]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/import/import-common.c
grypt-util: drop two emacs modelines
[thirdparty/systemd.git] / src / import / import-common.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright 2015 Lennart Poettering
4 ***/
5
6 #include <sched.h>
7 #include <sys/prctl.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10
11 #include "btrfs-util.h"
12 #include "capability-util.h"
13 #include "fd-util.h"
14 #include "import-common.h"
15 #include "process-util.h"
16 #include "signal-util.h"
17 #include "util.h"
18
19 int import_make_read_only_fd(int fd) {
20 int r;
21
22 assert(fd >= 0);
23
24 /* First, let's make this a read-only subvolume if it refers
25 * to a subvolume */
26 r = btrfs_subvol_set_read_only_fd(fd, true);
27 if (IN_SET(r, -ENOTTY, -ENOTDIR, -EINVAL)) {
28 struct stat st;
29
30 /* This doesn't refer to a subvolume, or the file
31 * system isn't even btrfs. In that, case fall back to
32 * chmod()ing */
33
34 r = fstat(fd, &st);
35 if (r < 0)
36 return log_error_errno(errno, "Failed to stat temporary image: %m");
37
38 /* Drop "w" flag */
39 if (fchmod(fd, st.st_mode & 07555) < 0)
40 return log_error_errno(errno, "Failed to chmod() final image: %m");
41
42 return 0;
43
44 } else if (r < 0)
45 return log_error_errno(r, "Failed to make subvolume read-only: %m");
46
47 return 0;
48 }
49
50 int import_make_read_only(const char *path) {
51 _cleanup_close_ int fd = 1;
52
53 fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
54 if (fd < 0)
55 return log_error_errno(errno, "Failed to open %s: %m", path);
56
57 return import_make_read_only_fd(fd);
58 }
59
60 int import_fork_tar_x(const char *path, pid_t *ret) {
61 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
62 pid_t pid;
63 int r;
64
65 assert(path);
66 assert(ret);
67
68 if (pipe2(pipefd, O_CLOEXEC) < 0)
69 return log_error_errno(errno, "Failed to create pipe for tar: %m");
70
71 r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
72 if (r < 0)
73 return r;
74 if (r == 0) {
75 uint64_t retain =
76 (1ULL << CAP_CHOWN) |
77 (1ULL << CAP_FOWNER) |
78 (1ULL << CAP_FSETID) |
79 (1ULL << CAP_MKNOD) |
80 (1ULL << CAP_SETFCAP) |
81 (1ULL << CAP_DAC_OVERRIDE);
82
83 /* Child */
84
85 pipefd[1] = safe_close(pipefd[1]);
86
87 r = rearrange_stdio(pipefd[0], -1, STDERR_FILENO);
88 if (r < 0) {
89 log_error_errno(r, "Failed to rearrange stdin/stdout: %m");
90 _exit(EXIT_FAILURE);
91 }
92
93 if (unshare(CLONE_NEWNET) < 0)
94 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
95
96 r = capability_bounding_set_drop(retain, true);
97 if (r < 0)
98 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
99
100 execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL);
101 log_error_errno(errno, "Failed to execute tar: %m");
102 _exit(EXIT_FAILURE);
103 }
104
105 *ret = pid;
106
107 return TAKE_FD(pipefd[1]);
108 }
109
110 int import_fork_tar_c(const char *path, pid_t *ret) {
111 _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
112 pid_t pid;
113 int r;
114
115 assert(path);
116 assert(ret);
117
118 if (pipe2(pipefd, O_CLOEXEC) < 0)
119 return log_error_errno(errno, "Failed to create pipe for tar: %m");
120
121 r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
122 if (r < 0)
123 return r;
124 if (r == 0) {
125 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
126
127 /* Child */
128
129 pipefd[0] = safe_close(pipefd[0]);
130
131 r = rearrange_stdio(-1, pipefd[1], STDERR_FILENO);
132 if (r < 0) {
133 log_error_errno(r, "Failed to rearrange stdin/stdout: %m");
134 _exit(EXIT_FAILURE);
135 }
136
137 if (unshare(CLONE_NEWNET) < 0)
138 log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
139
140 r = capability_bounding_set_drop(retain, true);
141 if (r < 0)
142 log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
143
144 execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL);
145 log_error_errno(errno, "Failed to execute tar: %m");
146 _exit(EXIT_FAILURE);
147 }
148
149 *ret = pid;
150
151 return TAKE_FD(pipefd[0]);
152 }