diff options
author | smitsohu <smitsohu@gmail.com> | 2020-08-27 22:47:24 +0200 |
---|---|---|
committer | smitsohu <smitsohu@gmail.com> | 2020-08-27 22:47:24 +0200 |
commit | ad61473afe2b9aee44330595e4874d24ff93836e (patch) | |
tree | a496268c803d1ccca51bc7d19b663a42ba8a16ac | |
parent | chroot: little tweaks (diff) | |
download | firejail-ad61473afe2b9aee44330595e4874d24ff93836e.tar.gz firejail-ad61473afe2b9aee44330595e4874d24ff93836e.tar.zst firejail-ad61473afe2b9aee44330595e4874d24ff93836e.zip |
expose pulseaudio in chroot if FIREJAIL_CHROOT_PULSE is set
issue #3568
-rw-r--r-- | src/firejail/chroot.c | 61 |
1 files changed, 50 insertions, 11 deletions
diff --git a/src/firejail/chroot.c b/src/firejail/chroot.c index 26a91faba..7411a2b48 100644 --- a/src/firejail/chroot.c +++ b/src/firejail/chroot.c | |||
@@ -60,27 +60,29 @@ errout: | |||
60 | exit(1); | 60 | exit(1); |
61 | } | 61 | } |
62 | 62 | ||
63 | // copy /etc/resolv.conf in chroot directory | 63 | // copy /etc/resolv.conf or /etc/machine-id in chroot directory |
64 | static void copy_resolvconf(int parentfd) { | 64 | static void update_file(int parentfd, const char *fname) { |
65 | int in = open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC); | 65 | assert(fname); |
66 | assert(fname[0] == '/'); | ||
67 | |||
68 | int in = open(fname, O_RDONLY|O_CLOEXEC); | ||
66 | if (in == -1) | 69 | if (in == -1) |
67 | goto errout; | 70 | goto errout; |
68 | struct stat src; | 71 | struct stat src; |
69 | if (fstat(in, &src) == -1) | 72 | if (fstat(in, &src) == -1) |
70 | errExit("fstat"); | 73 | errExit("fstat"); |
71 | // try to detect if resolv.conf has been bind mounted into the chroot | 74 | // try to detect if file has been bind mounted into the chroot |
72 | // do nothing in this case in order to not unlink the real file | ||
73 | struct stat dst; | 75 | struct stat dst; |
74 | if (fstatat(parentfd, "etc/resolv.conf", &dst, 0) == 0) { | 76 | if (fstatat(parentfd, fname+1, &dst, 0) == 0) { |
75 | if (src.st_dev == dst.st_dev && src.st_ino == dst.st_ino) { | 77 | if (src.st_dev == dst.st_dev && src.st_ino == dst.st_ino) { |
76 | close(in); | 78 | close(in); |
77 | return; | 79 | return; |
78 | } | 80 | } |
79 | } | 81 | } |
80 | if (arg_debug) | 82 | if (arg_debug) |
81 | printf("Updating /etc/resolv.conf in chroot\n"); | 83 | printf("Updating %s in chroot\n", fname); |
82 | unlinkat(parentfd, "etc/resolv.conf", 0); | 84 | unlinkat(parentfd, fname+1, 0); |
83 | int out = openat(parentfd, "etc/resolv.conf", O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 85 | int out = openat(parentfd, fname+1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); |
84 | if (out == -1) { | 86 | if (out == -1) { |
85 | close(in); | 87 | close(in); |
86 | goto errout; | 88 | goto errout; |
@@ -92,7 +94,7 @@ static void copy_resolvconf(int parentfd) { | |||
92 | return; | 94 | return; |
93 | 95 | ||
94 | errout: | 96 | errout: |
95 | fwarning("/etc/resolv.conf not initialized\n"); | 97 | fwarning("%s not initialized\n", fname); |
96 | } | 98 | } |
97 | 99 | ||
98 | // exit if error | 100 | // exit if error |
@@ -187,6 +189,43 @@ void fs_chroot(const char *rootdir) { | |||
187 | errExit("mkdir"); | 189 | errExit("mkdir"); |
188 | check_subdir(parentfd, "run", 1); | 190 | check_subdir(parentfd, "run", 1); |
189 | 191 | ||
192 | // pulseaudio; only support for default directory /run/user/$UID/pulse | ||
193 | if (getenv("FIREJAIL_CHROOT_PULSE")) { | ||
194 | char *pulse; | ||
195 | if (asprintf(&pulse, "%s/run/user/%d/pulse", cfg.chrootdir, getuid()) == -1) | ||
196 | errExit("asprintf"); | ||
197 | char *orig_pulse = pulse + strlen(cfg.chrootdir); | ||
198 | |||
199 | if (arg_debug) | ||
200 | printf("Mounting %s on chroot %s\n", orig_pulse, orig_pulse); | ||
201 | int src = safe_fd(orig_pulse, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
202 | if (src == -1) { | ||
203 | fprintf(stderr, "Error: cannot open %s\n", orig_pulse); | ||
204 | exit(1); | ||
205 | } | ||
206 | int dst = safe_fd(pulse, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
207 | if (dst == -1) { | ||
208 | fprintf(stderr, "Error: cannot open %s\n", pulse); | ||
209 | exit(1); | ||
210 | } | ||
211 | free(pulse); | ||
212 | |||
213 | char *proc_src, *proc_dst; | ||
214 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) | ||
215 | errExit("asprintf"); | ||
216 | if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1) | ||
217 | errExit("asprintf"); | ||
218 | if (mount(proc_src, proc_dst, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
219 | errExit("mount bind"); | ||
220 | free(proc_src); | ||
221 | free(proc_dst); | ||
222 | close(src); | ||
223 | close(dst); | ||
224 | |||
225 | // update /etc/machine-id in chroot | ||
226 | update_file(parentfd, "/etc/machine-id"); | ||
227 | } | ||
228 | |||
190 | // create /run/firejail directory in chroot | 229 | // create /run/firejail directory in chroot |
191 | if (mkdirat(parentfd, RUN_FIREJAIL_DIR+1, 0755) == -1 && errno != EEXIST) | 230 | if (mkdirat(parentfd, RUN_FIREJAIL_DIR+1, 0755) == -1 && errno != EEXIST) |
192 | errExit("mkdir"); | 231 | errExit("mkdir"); |
@@ -223,7 +262,7 @@ void fs_chroot(const char *rootdir) { | |||
223 | close(fd); | 262 | close(fd); |
224 | 263 | ||
225 | // update chroot resolv.conf | 264 | // update chroot resolv.conf |
226 | copy_resolvconf(parentfd); | 265 | update_file(parentfd, "/etc/resolv.conf"); |
227 | 266 | ||
228 | #ifdef HAVE_GCOV | 267 | #ifdef HAVE_GCOV |
229 | __gcov_flush(); | 268 | __gcov_flush(); |