]> git.proxmox.com Git - systemd.git/blob - src/import/import-common.c
Imported Upstream version 227
[systemd.git] / src / import / import-common.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sched.h>
23 #include <sys/prctl.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26
27 #include "btrfs-util.h"
28 #include "capability.h"
29 #include "signal-util.h"
30 #include "util.h"
31 #include "import-common.h"
32
33 int 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);
41 if (r == -ENOTTY || r == -ENOTDIR || r == -EINVAL) {
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
64 int 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
74 int import_fork_tar_x(const char *path, pid_t *ret) {
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
85 pid = fork();
86 if (pid < 0)
87 return log_error_errno(errno, "Failed to fork off tar: %m");
88
89 if (pid == 0) {
90 int null_fd;
91 uint64_t retain =
92 (1ULL << CAP_CHOWN) |
93 (1ULL << CAP_FOWNER) |
94 (1ULL << CAP_FSETID) |
95 (1ULL << CAP_MKNOD) |
96 (1ULL << CAP_SETFCAP) |
97 (1ULL << CAP_DAC_OVERRIDE);
98
99 /* Child */
100
101 (void) reset_all_signal_handlers();
102 (void) reset_signal_mask();
103 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
104
105 pipefd[1] = safe_close(pipefd[1]);
106
107 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
108 log_error_errno(errno, "Failed to dup2() fd: %m");
109 _exit(EXIT_FAILURE);
110 }
111
112 if (pipefd[0] != STDIN_FILENO)
113 pipefd[0] = safe_close(pipefd[0]);
114
115 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
116 if (null_fd < 0) {
117 log_error_errno(errno, "Failed to open /dev/null: %m");
118 _exit(EXIT_FAILURE);
119 }
120
121 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
122 log_error_errno(errno, "Failed to dup2() fd: %m");
123 _exit(EXIT_FAILURE);
124 }
125
126 if (null_fd != STDOUT_FILENO)
127 null_fd = safe_close(null_fd);
128
129 fd_cloexec(STDIN_FILENO, false);
130 fd_cloexec(STDOUT_FILENO, false);
131 fd_cloexec(STDERR_FILENO, false);
132
133 if (unshare(CLONE_NEWNET) < 0)
134 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
135
136 r = capability_bounding_set_drop(~retain, true);
137 if (r < 0)
138 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
139
140 execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
141 log_error_errno(errno, "Failed to execute tar: %m");
142 _exit(EXIT_FAILURE);
143 }
144
145 pipefd[0] = safe_close(pipefd[0]);
146 r = pipefd[1];
147 pipefd[1] = -1;
148
149 *ret = pid;
150
151 return r;
152 }
153
154 int import_fork_tar_c(const char *path, pid_t *ret) {
155 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
156 pid_t pid;
157 int r;
158
159 assert(path);
160 assert(ret);
161
162 if (pipe2(pipefd, O_CLOEXEC) < 0)
163 return log_error_errno(errno, "Failed to create pipe for tar: %m");
164
165 pid = fork();
166 if (pid < 0)
167 return log_error_errno(errno, "Failed to fork off tar: %m");
168
169 if (pid == 0) {
170 int null_fd;
171 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
172
173 /* Child */
174
175 (void) reset_all_signal_handlers();
176 (void) reset_signal_mask();
177 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
178
179 pipefd[0] = safe_close(pipefd[0]);
180
181 if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
182 log_error_errno(errno, "Failed to dup2() fd: %m");
183 _exit(EXIT_FAILURE);
184 }
185
186 if (pipefd[1] != STDOUT_FILENO)
187 pipefd[1] = safe_close(pipefd[1]);
188
189 null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
190 if (null_fd < 0) {
191 log_error_errno(errno, "Failed to open /dev/null: %m");
192 _exit(EXIT_FAILURE);
193 }
194
195 if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
196 log_error_errno(errno, "Failed to dup2() fd: %m");
197 _exit(EXIT_FAILURE);
198 }
199
200 if (null_fd != STDIN_FILENO)
201 null_fd = safe_close(null_fd);
202
203 fd_cloexec(STDIN_FILENO, false);
204 fd_cloexec(STDOUT_FILENO, false);
205 fd_cloexec(STDERR_FILENO, false);
206
207 if (unshare(CLONE_NEWNET) < 0)
208 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
209
210 r = capability_bounding_set_drop(~retain, true);
211 if (r < 0)
212 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
213
214 execlp("tar", "tar", "-C", path, "-c", ".", NULL);
215 log_error_errno(errno, "Failed to execute tar: %m");
216 _exit(EXIT_FAILURE);
217 }
218
219 pipefd[1] = safe_close(pipefd[1]);
220 r = pipefd[0];
221 pipefd[0] = -1;
222
223 *ret = pid;
224
225 return r;
226 }