diff options
author | netblue30 <netblue30@protonmail.com> | 2021-02-24 10:45:29 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-24 10:45:29 -0500 |
commit | 9a47e2de8e7aa050b0579424c693b38fc812b036 (patch) | |
tree | c30e68b2ce7273dce6f1cbaaa29e1d3e90a89140 /src | |
parent | Merge pull request #4001 from kmk3/fix-signal-xdg-ignore (diff) | |
parent | Add checks to fs_private_dir_mount (diff) | |
download | firejail-9a47e2de8e7aa050b0579424c693b38fc812b036.tar.gz firejail-9a47e2de8e7aa050b0579424c693b38fc812b036.tar.zst firejail-9a47e2de8e7aa050b0579424c693b38fc812b036.zip |
Merge pull request #3998 from Tomin1/first_fixes
Upstreaming a set of fixes from Sailfish's packaging
Diffstat (limited to 'src')
-rw-r--r-- | src/fcopy/main.c | 56 | ||||
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/fs_etc.c | 20 | ||||
-rw-r--r-- | src/firejail/fs_mkdir.c | 4 | ||||
-rw-r--r-- | src/firejail/main.c | 2 | ||||
-rw-r--r-- | src/firejail/network_main.c | 2 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 25 |
7 files changed, 96 insertions, 15 deletions
diff --git a/src/fcopy/main.c b/src/fcopy/main.c index 01633be59..d863b537b 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c | |||
@@ -172,6 +172,47 @@ static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) { | |||
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | static char *proc_pid_to_self(const char *target) | ||
176 | { | ||
177 | char *use_target = 0; | ||
178 | char *proc_pid = 0; | ||
179 | |||
180 | if (!(use_target = canonicalize_file_name(target))) | ||
181 | goto done; | ||
182 | |||
183 | // target is under /proc/<PID>? | ||
184 | static const char proc[] = "/proc/"; | ||
185 | if (strncmp(use_target, proc, sizeof proc - 1)) | ||
186 | goto done; | ||
187 | |||
188 | int digit = use_target[sizeof proc - 1]; | ||
189 | if (digit < '1' || digit > '9') | ||
190 | goto done; | ||
191 | |||
192 | // check where /proc/self points to | ||
193 | static const char proc_self[] = "/proc/self"; | ||
194 | if (!(proc_pid = canonicalize_file_name(proc_self))) | ||
195 | goto done; | ||
196 | |||
197 | // redirect /proc/PID/xxx -> /proc/self/XXX | ||
198 | size_t pfix = strlen(proc_pid); | ||
199 | if (strncmp(use_target, proc_pid, pfix)) | ||
200 | goto done; | ||
201 | |||
202 | if (use_target[pfix] != 0 && use_target[pfix] != '/') | ||
203 | goto done; | ||
204 | |||
205 | char *tmp; | ||
206 | if (asprintf(&tmp, "%s%s", proc_self, use_target + pfix) != -1) { | ||
207 | if (arg_debug) | ||
208 | fprintf(stderr, "SYMLINK %s\n --> %s\n", use_target, tmp); | ||
209 | free(use_target), use_target = tmp; | ||
210 | } | ||
211 | |||
212 | done: | ||
213 | free(proc_pid); | ||
214 | return use_target; | ||
215 | } | ||
175 | 216 | ||
176 | void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { | 217 | void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { |
177 | (void) mode; | 218 | (void) mode; |
@@ -183,7 +224,7 @@ void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, | |||
183 | if (lstat(linkpath, &s) == 0) | 224 | if (lstat(linkpath, &s) == 0) |
184 | return; | 225 | return; |
185 | 226 | ||
186 | char *rp = realpath(target, NULL); | 227 | char *rp = proc_pid_to_self(target); |
187 | if (rp) { | 228 | if (rp) { |
188 | if (symlink(rp, linkpath) == -1) { | 229 | if (symlink(rp, linkpath) == -1) { |
189 | free(rp); | 230 | free(rp); |
@@ -227,16 +268,14 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
227 | first = 0; | 268 | first = 0; |
228 | else if (!arg_quiet) | 269 | else if (!arg_quiet) |
229 | fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); | 270 | fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname); |
230 | free(outfname); | 271 | goto out; |
231 | return 0; | ||
232 | } | 272 | } |
233 | 273 | ||
234 | // extract mode and ownership | 274 | // extract mode and ownership |
235 | if (stat(infname, &s) != 0) { | 275 | if (stat(infname, &s) != 0) { |
236 | if (!arg_quiet) | 276 | if (!arg_quiet) |
237 | fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); | 277 | fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname); |
238 | free(outfname); | 278 | goto out; |
239 | return 0; | ||
240 | } | 279 | } |
241 | uid_t uid = s.st_uid; | 280 | uid_t uid = s.st_uid; |
242 | gid_t gid = s.st_gid; | 281 | gid_t gid = s.st_gid; |
@@ -246,8 +285,7 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
246 | if ((s.st_size + size_cnt) > copy_limit) { | 285 | if ((s.st_size + size_cnt) > copy_limit) { |
247 | fprintf(stderr, "Error fcopy: size limit of %lu MB reached\n", (copy_limit / 1024) / 1024); | 286 | fprintf(stderr, "Error fcopy: size limit of %lu MB reached\n", (copy_limit / 1024) / 1024); |
248 | size_limit_reached = 1; | 287 | size_limit_reached = 1; |
249 | free(outfname); | 288 | goto out; |
250 | return 0; | ||
251 | } | 289 | } |
252 | 290 | ||
253 | file_cnt++; | 291 | file_cnt++; |
@@ -262,7 +300,8 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str | |||
262 | else if (ftype == FTW_SL) { | 300 | else if (ftype == FTW_SL) { |
263 | copy_link(infname, outfname, mode, uid, gid); | 301 | copy_link(infname, outfname, mode, uid, gid); |
264 | } | 302 | } |
265 | 303 | out: | |
304 | free(outfname); | ||
266 | return(0); | 305 | return(0); |
267 | } | 306 | } |
268 | 307 | ||
@@ -295,6 +334,7 @@ static char *check(const char *src) { | |||
295 | return rsrc; // normal exit from the function | 334 | return rsrc; // normal exit from the function |
296 | 335 | ||
297 | errexit: | 336 | errexit: |
337 | free(rsrc); | ||
298 | fprintf(stderr, "Error fcopy: invalid file %s\n", src); | 338 | fprintf(stderr, "Error fcopy: invalid file %s\n", src); |
299 | exit(1); | 339 | exit(1); |
300 | } | 340 | } |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 719cd74ae..36340ff2c 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -649,6 +649,8 @@ void network_set_run_file(pid_t pid); | |||
649 | 649 | ||
650 | // fs_etc.c | 650 | // fs_etc.c |
651 | void fs_machineid(void); | 651 | void fs_machineid(void); |
652 | void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list); | ||
653 | void fs_private_dir_mount(const char *private_dir, const char *private_run_dir); | ||
652 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list); | 654 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list); |
653 | 655 | ||
654 | // no_sandbox.c | 656 | // no_sandbox.c |
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c index d152ed2f6..b9ed81db3 100644 --- a/src/firejail/fs_etc.c +++ b/src/firejail/fs_etc.c | |||
@@ -138,7 +138,7 @@ static void duplicate(const char *fname, const char *private_dir, const char *pr | |||
138 | } | 138 | } |
139 | 139 | ||
140 | 140 | ||
141 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list) { | 141 | void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list) { |
142 | assert(private_dir); | 142 | assert(private_dir); |
143 | assert(private_run_dir); | 143 | assert(private_run_dir); |
144 | assert(private_list); | 144 | assert(private_list); |
@@ -185,6 +185,19 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c | |||
185 | free(dlist); | 185 | free(dlist); |
186 | fs_logger_print(); | 186 | fs_logger_print(); |
187 | } | 187 | } |
188 | } | ||
189 | |||
190 | void fs_private_dir_mount(const char *private_dir, const char *private_run_dir) { | ||
191 | assert(private_dir); | ||
192 | assert(private_run_dir); | ||
193 | |||
194 | // nothing to do if directory does not exist | ||
195 | struct stat s; | ||
196 | if (stat(private_dir, &s) == -1) { | ||
197 | if (arg_debug) | ||
198 | printf("Cannot find %s\n", private_dir); | ||
199 | return; | ||
200 | } | ||
188 | 201 | ||
189 | if (arg_debug) | 202 | if (arg_debug) |
190 | printf("Mount-bind %s on top of %s\n", private_run_dir, private_dir); | 203 | printf("Mount-bind %s on top of %s\n", private_run_dir, private_dir); |
@@ -199,3 +212,8 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c | |||
199 | 212 | ||
200 | fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end()); | 213 | fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end()); |
201 | } | 214 | } |
215 | |||
216 | void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list) { | ||
217 | fs_private_dir_copy(private_dir, private_run_dir, private_list); | ||
218 | fs_private_dir_mount(private_dir, private_run_dir); | ||
219 | } | ||
diff --git a/src/firejail/fs_mkdir.c b/src/firejail/fs_mkdir.c index d1b3b5629..8cfeea582 100644 --- a/src/firejail/fs_mkdir.c +++ b/src/firejail/fs_mkdir.c | |||
@@ -46,7 +46,7 @@ static void mkdir_recursive(char *path) { | |||
46 | struct stat s; | 46 | struct stat s; |
47 | 47 | ||
48 | if (chdir("/")) { | 48 | if (chdir("/")) { |
49 | fprintf(stderr, "Error: can't chdir to /"); | 49 | fprintf(stderr, "Error: can't chdir to /\n"); |
50 | return; | 50 | return; |
51 | } | 51 | } |
52 | 52 | ||
@@ -63,7 +63,7 @@ static void mkdir_recursive(char *path) { | |||
63 | return; | 63 | return; |
64 | } | 64 | } |
65 | if (chdir(subdir)) { | 65 | if (chdir(subdir)) { |
66 | fprintf(stderr, "Error: can't chdir to %s", subdir); | 66 | fprintf(stderr, "Error: can't chdir to %s\n", subdir); |
67 | return; | 67 | return; |
68 | } | 68 | } |
69 | 69 | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index 61533fcd9..ef8166204 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -297,7 +297,7 @@ static void check_network(Bridge *br) { | |||
297 | else if (br->ipsandbox) { // for macvlan check network range | 297 | else if (br->ipsandbox) { // for macvlan check network range |
298 | char *rv = in_netrange(br->ipsandbox, br->ip, br->mask); | 298 | char *rv = in_netrange(br->ipsandbox, br->ip, br->mask); |
299 | if (rv) { | 299 | if (rv) { |
300 | fprintf(stderr, "%s", rv); | 300 | fprintf(stderr, "%s\n", rv); |
301 | exit(1); | 301 | exit(1); |
302 | } | 302 | } |
303 | } | 303 | } |
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c index f1ad6430a..ee3c00872 100644 --- a/src/firejail/network_main.c +++ b/src/firejail/network_main.c | |||
@@ -120,7 +120,7 @@ void net_configure_sandbox_ip(Bridge *br) { | |||
120 | // check network range | 120 | // check network range |
121 | char *rv = in_netrange(br->ipsandbox, br->ip, br->mask); | 121 | char *rv = in_netrange(br->ipsandbox, br->ip, br->mask); |
122 | if (rv) { | 122 | if (rv) { |
123 | fprintf(stderr, "%s", rv); | 123 | fprintf(stderr, "%s\n", rv); |
124 | exit(1); | 124 | exit(1); |
125 | } | 125 | } |
126 | // send an ARP request and check if there is anybody on this IP address | 126 | // send an ARP request and check if there is anybody on this IP address |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 9a4be5cc0..ff5f4cb1e 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -969,8 +969,29 @@ int sandbox(void* sandbox_arg) { | |||
969 | else if (arg_overlay) | 969 | else if (arg_overlay) |
970 | fwarning("private-etc feature is disabled in overlay\n"); | 970 | fwarning("private-etc feature is disabled in overlay\n"); |
971 | else { | 971 | else { |
972 | fs_private_dir_list("/etc", RUN_ETC_DIR, cfg.etc_private_keep); | 972 | /* Current /etc/passwd and /etc/group files are bind |
973 | fs_private_dir_list("/usr/etc", RUN_USR_ETC_DIR, cfg.etc_private_keep); // openSUSE | 973 | * mounted filtered versions of originals. Leaving |
974 | * them underneath private-etc mount causes problems | ||
975 | * in devices with older kernels, e.g. attempts to | ||
976 | * update the real /etc/passwd file yield EBUSY. | ||
977 | * | ||
978 | * As we do want to retain filtered /etc content: | ||
979 | * 1. duplicate /etc content to RUN_ETC_DIR | ||
980 | * 2. unmount bind mounts from /etc | ||
981 | * 3. mount RUN_ETC_DIR at /etc | ||
982 | */ | ||
983 | fs_private_dir_copy("/etc", RUN_ETC_DIR, cfg.etc_private_keep); | ||
984 | fs_private_dir_copy("/usr/etc", RUN_USR_ETC_DIR, cfg.etc_private_keep); // openSUSE | ||
985 | |||
986 | if (umount2("/etc/group", MNT_DETACH) == -1) | ||
987 | fprintf(stderr, "/etc/group: unmount: %m\n"); | ||
988 | |||
989 | if (umount2("/etc/passwd", MNT_DETACH) == -1) | ||
990 | fprintf(stderr, "/etc/passwd: unmount: %m\n"); | ||
991 | |||
992 | fs_private_dir_mount("/etc", RUN_ETC_DIR); | ||
993 | fs_private_dir_mount("/usr/etc", RUN_USR_ETC_DIR); | ||
994 | |||
974 | // create /etc/ld.so.preload file again | 995 | // create /etc/ld.so.preload file again |
975 | if (need_preload) | 996 | if (need_preload) |
976 | fs_trace_preload(); | 997 | fs_trace_preload(); |