]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/import-common.c
process-util: add another fork_safe() flag for enabling LOG_ERR/LOG_WARN logging
[thirdparty/systemd.git] / src / import / import-common.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b6e676ce
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2015 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
618234a5 21#include <sched.h>
b6e676ce
LP
22#include <sys/prctl.h>
23#include <sys/stat.h>
24#include <unistd.h>
25
b6e676ce 26#include "btrfs-util.h"
430f0182 27#include "capability-util.h"
3ffd4af2
LP
28#include "fd-util.h"
29#include "import-common.h"
24882e06 30#include "signal-util.h"
618234a5 31#include "util.h"
b6e676ce
LP
32
33int import_make_read_only_fd(int fd) {
34 int r;
35
36 assert(fd >= 0);
37
38 /* First, let's make this a read-only subvolume if it refers
39 * to a subvolume */
40 r = btrfs_subvol_set_read_only_fd(fd, true);
4c701096 41 if (IN_SET(r, -ENOTTY, -ENOTDIR, -EINVAL)) {
b6e676ce
LP
42 struct stat st;
43
44 /* This doesn't refer to a subvolume, or the file
45 * system isn't even btrfs. In that, case fall back to
46 * chmod()ing */
47
48 r = fstat(fd, &st);
49 if (r < 0)
50 return log_error_errno(errno, "Failed to stat temporary image: %m");
51
52 /* Drop "w" flag */
53 if (fchmod(fd, st.st_mode & 07555) < 0)
54 return log_error_errno(errno, "Failed to chmod() final image: %m");
55
56 return 0;
57
58 } else if (r < 0)
59 return log_error_errno(r, "Failed to make subvolume read-only: %m");
60
61 return 0;
62}
63
64int import_make_read_only(const char *path) {
65 _cleanup_close_ int fd = 1;
66
67 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
68 if (fd < 0)
69 return log_error_errno(errno, "Failed to open %s: %m", path);
70
71 return import_make_read_only_fd(fd);
72}
73
587fec42 74int import_fork_tar_x(const char *path, pid_t *ret) {
b6e676ce
LP
75 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
76 pid_t pid;
77 int r;
78
79 assert(path);
80 assert(ret);
81
82 if (pipe2(pipefd, O_CLOEXEC) < 0)
83 return log_error_errno(errno, "Failed to create pipe for tar: %m");
84
b6e1fff1 85 r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
4c253ed1 86 if (r < 0)
b6e1fff1 87 return r;
4c253ed1 88 if (r == 0) {
b6e676ce
LP
89 int null_fd;
90 uint64_t retain =
91 (1ULL << CAP_CHOWN) |
92 (1ULL << CAP_FOWNER) |
93 (1ULL << CAP_FSETID) |
94 (1ULL << CAP_MKNOD) |
95 (1ULL << CAP_SETFCAP) |
96 (1ULL << CAP_DAC_OVERRIDE);
97
98 /* Child */
99
b6e676ce
LP
100 pipefd[1] = safe_close(pipefd[1]);
101
046a82c1
LP
102 r = move_fd(pipefd[0], STDIN_FILENO, false);
103 if (r < 0) {
104 log_error_errno(r, "Failed to move fd: %m");
b6e676ce
LP
105 _exit(EXIT_FAILURE);
106 }
107
b6e676ce
LP
108 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
109 if (null_fd < 0) {
110 log_error_errno(errno, "Failed to open /dev/null: %m");
111 _exit(EXIT_FAILURE);
112 }
113
046a82c1
LP
114 r = move_fd(null_fd, STDOUT_FILENO, false);
115 if (r < 0) {
116 log_error_errno(r, "Failed to move fd: %m");
b6e676ce
LP
117 _exit(EXIT_FAILURE);
118 }
119
913f38e4 120 stdio_unset_cloexec();
b6e676ce
LP
121
122 if (unshare(CLONE_NEWNET) < 0)
123 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
124
a103496c 125 r = capability_bounding_set_drop(retain, true);
b6e676ce
LP
126 if (r < 0)
127 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
128
2944758c 129 execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL);
b6e676ce
LP
130 log_error_errno(errno, "Failed to execute tar: %m");
131 _exit(EXIT_FAILURE);
132 }
133
134 pipefd[0] = safe_close(pipefd[0]);
135 r = pipefd[1];
136 pipefd[1] = -1;
137
138 *ret = pid;
139
140 return r;
141}
587fec42
LP
142
143int import_fork_tar_c(const char *path, pid_t *ret) {
144 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
145 pid_t pid;
146 int r;
147
148 assert(path);
149 assert(ret);
150
151 if (pipe2(pipefd, O_CLOEXEC) < 0)
152 return log_error_errno(errno, "Failed to create pipe for tar: %m");
153
b6e1fff1 154 r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
4c253ed1 155 if (r < 0)
b6e1fff1 156 return r;
4c253ed1 157 if (r == 0) {
587fec42
LP
158 int null_fd;
159 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
160
161 /* Child */
162
587fec42
LP
163 pipefd[0] = safe_close(pipefd[0]);
164
046a82c1
LP
165 r = move_fd(pipefd[1], STDOUT_FILENO, false);
166 if (r < 0) {
167 log_error_errno(r, "Failed to move fd: %m");
587fec42
LP
168 _exit(EXIT_FAILURE);
169 }
170
587fec42
LP
171 null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
172 if (null_fd < 0) {
173 log_error_errno(errno, "Failed to open /dev/null: %m");
174 _exit(EXIT_FAILURE);
175 }
176
046a82c1
LP
177 r = move_fd(null_fd, STDIN_FILENO, false);
178 if (r < 0) {
179 log_error_errno(errno, "Failed to move fd: %m");
587fec42
LP
180 _exit(EXIT_FAILURE);
181 }
182
913f38e4 183 stdio_unset_cloexec();
587fec42
LP
184
185 if (unshare(CLONE_NEWNET) < 0)
186 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
187
a103496c 188 r = capability_bounding_set_drop(retain, true);
587fec42
LP
189 if (r < 0)
190 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
191
2944758c 192 execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL);
587fec42
LP
193 log_error_errno(errno, "Failed to execute tar: %m");
194 _exit(EXIT_FAILURE);
195 }
196
197 pipefd[1] = safe_close(pipefd[1]);
198 r = pipefd[0];
199 pipefd[0] = -1;
200
201 *ret = pid;
202
203 return r;
204}