]>
Commit | Line | Data |
---|---|---|
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 | |
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); | |
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 | ||
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 | ||
587fec42 | 74 | int 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 | |
143 | int 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 | } |