]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/import/import-common.c
81209cdaf6502d69a6f38276f18508b0055431fd
[thirdparty/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 stdio_unset_cloexec();
129
130 if (unshare(CLONE_NEWNET) < 0)
131 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
132
133 r = capability_bounding_set_drop(retain, true);
134 if (r < 0)
135 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
136
137 execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL);
138 log_error_errno(errno, "Failed to execute tar: %m");
139 _exit(EXIT_FAILURE);
140 }
141
142 pipefd[0] = safe_close(pipefd[0]);
143 r = pipefd[1];
144 pipefd[1] = -1;
145
146 *ret = pid;
147
148 return r;
149 }
150
151 int import_fork_tar_c(const char *path, pid_t *ret) {
152 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
153 pid_t pid;
154 int r;
155
156 assert(path);
157 assert(ret);
158
159 if (pipe2(pipefd, O_CLOEXEC) < 0)
160 return log_error_errno(errno, "Failed to create pipe for tar: %m");
161
162 pid = fork();
163 if (pid < 0)
164 return log_error_errno(errno, "Failed to fork off tar: %m");
165
166 if (pid == 0) {
167 int null_fd;
168 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
169
170 /* Child */
171
172 (void) reset_all_signal_handlers();
173 (void) reset_signal_mask();
174 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
175
176 pipefd[0] = safe_close(pipefd[0]);
177
178 if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
179 log_error_errno(errno, "Failed to dup2() fd: %m");
180 _exit(EXIT_FAILURE);
181 }
182
183 if (pipefd[1] != STDOUT_FILENO)
184 pipefd[1] = safe_close(pipefd[1]);
185
186 null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
187 if (null_fd < 0) {
188 log_error_errno(errno, "Failed to open /dev/null: %m");
189 _exit(EXIT_FAILURE);
190 }
191
192 if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
193 log_error_errno(errno, "Failed to dup2() fd: %m");
194 _exit(EXIT_FAILURE);
195 }
196
197 if (null_fd != STDIN_FILENO)
198 null_fd = safe_close(null_fd);
199
200 stdio_unset_cloexec();
201
202 if (unshare(CLONE_NEWNET) < 0)
203 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
204
205 r = capability_bounding_set_drop(retain, true);
206 if (r < 0)
207 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
208
209 execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL);
210 log_error_errno(errno, "Failed to execute tar: %m");
211 _exit(EXIT_FAILURE);
212 }
213
214 pipefd[1] = safe_close(pipefd[1]);
215 r = pipefd[0];
216 pipefd[0] = -1;
217
218 *ret = pid;
219
220 return r;
221 }