]> git.proxmox.com Git - systemd.git/blob - src/import/import-common.c
Merge tag 'upstream/229'
[systemd.git] / src / import / import-common.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2015 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <sched.h>
21 #include <sys/prctl.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "btrfs-util.h"
26 #include "capability-util.h"
27 #include "fd-util.h"
28 #include "import-common.h"
29 #include "signal-util.h"
30 #include "util.h"
31
32 int import_make_read_only_fd(int fd) {
33 int r;
34
35 assert(fd >= 0);
36
37 /* First, let's make this a read-only subvolume if it refers
38 * to a subvolume */
39 r = btrfs_subvol_set_read_only_fd(fd, true);
40 if (r == -ENOTTY || r == -ENOTDIR || r == -EINVAL) {
41 struct stat st;
42
43 /* This doesn't refer to a subvolume, or the file
44 * system isn't even btrfs. In that, case fall back to
45 * chmod()ing */
46
47 r = fstat(fd, &st);
48 if (r < 0)
49 return log_error_errno(errno, "Failed to stat temporary image: %m");
50
51 /* Drop "w" flag */
52 if (fchmod(fd, st.st_mode & 07555) < 0)
53 return log_error_errno(errno, "Failed to chmod() final image: %m");
54
55 return 0;
56
57 } else if (r < 0)
58 return log_error_errno(r, "Failed to make subvolume read-only: %m");
59
60 return 0;
61 }
62
63 int import_make_read_only(const char *path) {
64 _cleanup_close_ int fd = 1;
65
66 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
67 if (fd < 0)
68 return log_error_errno(errno, "Failed to open %s: %m", path);
69
70 return import_make_read_only_fd(fd);
71 }
72
73 int import_fork_tar_x(const char *path, pid_t *ret) {
74 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
75 pid_t pid;
76 int r;
77
78 assert(path);
79 assert(ret);
80
81 if (pipe2(pipefd, O_CLOEXEC) < 0)
82 return log_error_errno(errno, "Failed to create pipe for tar: %m");
83
84 pid = fork();
85 if (pid < 0)
86 return log_error_errno(errno, "Failed to fork off tar: %m");
87
88 if (pid == 0) {
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
100 (void) reset_all_signal_handlers();
101 (void) reset_signal_mask();
102 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
103
104 pipefd[1] = safe_close(pipefd[1]);
105
106 if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
107 log_error_errno(errno, "Failed to dup2() fd: %m");
108 _exit(EXIT_FAILURE);
109 }
110
111 if (pipefd[0] != STDIN_FILENO)
112 pipefd[0] = safe_close(pipefd[0]);
113
114 null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
115 if (null_fd < 0) {
116 log_error_errno(errno, "Failed to open /dev/null: %m");
117 _exit(EXIT_FAILURE);
118 }
119
120 if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
121 log_error_errno(errno, "Failed to dup2() fd: %m");
122 _exit(EXIT_FAILURE);
123 }
124
125 if (null_fd != STDOUT_FILENO)
126 null_fd = safe_close(null_fd);
127
128 fd_cloexec(STDIN_FILENO, false);
129 fd_cloexec(STDOUT_FILENO, false);
130 fd_cloexec(STDERR_FILENO, false);
131
132 if (unshare(CLONE_NEWNET) < 0)
133 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
134
135 r = capability_bounding_set_drop(retain, true);
136 if (r < 0)
137 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
138
139 execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
140 log_error_errno(errno, "Failed to execute tar: %m");
141 _exit(EXIT_FAILURE);
142 }
143
144 pipefd[0] = safe_close(pipefd[0]);
145 r = pipefd[1];
146 pipefd[1] = -1;
147
148 *ret = pid;
149
150 return r;
151 }
152
153 int import_fork_tar_c(const char *path, pid_t *ret) {
154 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
155 pid_t pid;
156 int r;
157
158 assert(path);
159 assert(ret);
160
161 if (pipe2(pipefd, O_CLOEXEC) < 0)
162 return log_error_errno(errno, "Failed to create pipe for tar: %m");
163
164 pid = fork();
165 if (pid < 0)
166 return log_error_errno(errno, "Failed to fork off tar: %m");
167
168 if (pid == 0) {
169 int null_fd;
170 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
171
172 /* Child */
173
174 (void) reset_all_signal_handlers();
175 (void) reset_signal_mask();
176 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
177
178 pipefd[0] = safe_close(pipefd[0]);
179
180 if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
181 log_error_errno(errno, "Failed to dup2() fd: %m");
182 _exit(EXIT_FAILURE);
183 }
184
185 if (pipefd[1] != STDOUT_FILENO)
186 pipefd[1] = safe_close(pipefd[1]);
187
188 null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
189 if (null_fd < 0) {
190 log_error_errno(errno, "Failed to open /dev/null: %m");
191 _exit(EXIT_FAILURE);
192 }
193
194 if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
195 log_error_errno(errno, "Failed to dup2() fd: %m");
196 _exit(EXIT_FAILURE);
197 }
198
199 if (null_fd != STDIN_FILENO)
200 null_fd = safe_close(null_fd);
201
202 fd_cloexec(STDIN_FILENO, false);
203 fd_cloexec(STDOUT_FILENO, false);
204 fd_cloexec(STDERR_FILENO, false);
205
206 if (unshare(CLONE_NEWNET) < 0)
207 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
208
209 r = capability_bounding_set_drop(retain, true);
210 if (r < 0)
211 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
212
213 execlp("tar", "tar", "-C", path, "-c", ".", NULL);
214 log_error_errno(errno, "Failed to execute tar: %m");
215 _exit(EXIT_FAILURE);
216 }
217
218 pipefd[1] = safe_close(pipefd[1]);
219 r = pipefd[0];
220 pipefd[0] = -1;
221
222 *ret = pid;
223
224 return r;
225 }