From 0d8655e4da43ce0ed1ed6cc4925c1f994f65215c Mon Sep 17 00:00:00 2001 From: smitsohu Date: Thu, 13 Dec 2018 03:12:34 +0100 Subject: Revert "pulseaudio: use env variable fallback in more cases" This reverts commit 93779cb9cd0d098cd3587e2f795200d98e3af1ee. That commit removed restrictions, but also added new inconsistencies. Starting again from the previous state is easier than evolving the current state, hence reverting the commit. --- src/firejail/pulseaudio.c | 170 ++++++++++++++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 60 deletions(-) diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c index ce1692ba2..4ddaba7ed 100644 --- a/src/firejail/pulseaudio.c +++ b/src/firejail/pulseaudio.c @@ -102,74 +102,124 @@ void pulseaudio_init(void) { if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700)) errExit("set_perms"); - // create ~/.config directory if necessary - char *homeusercfg; - if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1) + // create ~/.config/pulse directory if not present + char *dir1; + if (asprintf(&dir1, "%s/.config", cfg.homedir) == -1) errExit("asprintf"); - create_empty_dir_as_user(homeusercfg, 0700); - // set environment variable if creating ~/.config wasn't successful or if it is not a directory owned by the user - if (lstat(homeusercfg, &s) != 0 || !S_ISDIR(s.st_mode) || s.st_uid != getuid()) { - if (arg_debug) - printf("Setting PULSE_CLIENTCONFIG environment variable\n"); - if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0) - errExit("setenv"); - free(homeusercfg); - free(pulsecfg); - return; + if (lstat(dir1, &s) == -1) { + pid_t child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + // drop privileges + drop_privs(0); + + int rv = mkdir(dir1, 0755); + if (rv == 0) { + if (chmod(dir1, 0755)) + {;} // do nothing + } +#ifdef HAVE_GCOV + __gcov_flush(); +#endif + _exit(0); + } + // wait for the child to finish + waitpid(child, NULL, 0); + fs_logger2("create", dir1); } - free(homeusercfg); + else { + // we expect a user owned directory + if (!S_ISDIR(s.st_mode) || s.st_uid != getuid()) { + if (S_ISLNK(s.st_mode)) + fprintf(stderr, "Error: user .config is a symbolic link\n"); + else + fprintf(stderr, "Error: user .config is not a directory owned by the current user\n"); + exit(1); + } + } + free(dir1); + + if (asprintf(&dir1, "%s/.config/pulse", cfg.homedir) == -1) + errExit("asprintf"); + if (lstat(dir1, &s) == -1) { + pid_t child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + // drop privileges + drop_privs(0); + + int rv = mkdir(dir1, 0700); + if (rv == 0) { + if (chmod(dir1, 0700)) + {;} // do nothing + } +#ifdef HAVE_GCOV + __gcov_flush(); +#endif + _exit(0); + } + // wait for the child to finish + waitpid(child, NULL, 0); + fs_logger2("create", dir1); + } + else { + // we expect a user owned directory + if (!S_ISDIR(s.st_mode) || s.st_uid != getuid()) { + if (S_ISLNK(s.st_mode)) + fprintf(stderr, "Error: user .config/pulse is a symbolic link\n"); + else + fprintf(stderr, "Error: user .config/pulse is not a directory owned by the current user\n"); + exit(1); + } + } + free(dir1); - // create ~/.config/pulse directory if necessary + // if we have ~/.config/pulse mount the new directory, else set environment variable. + char *homeusercfg; if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1) errExit("asprintf"); - create_empty_dir_as_user(homeusercfg, 0700); - // set environment variable if creating ~/.config/pulse wasn't successful or if it is not a directory owned by the user - if (lstat(homeusercfg, &s) != 0 || !S_ISDIR(s.st_mode) || s.st_uid != getuid()) { - if (arg_debug) - printf("Setting PULSE_CLIENTCONFIG environment variable\n"); - if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0) - errExit("setenv"); - free(homeusercfg); - free(pulsecfg); - return; + if (stat(homeusercfg, &s) == 0) { + // get a file descriptor for ~/.config/pulse, fails if there is any symlink + int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); + if (fd == -1) + errExit("safe_fd"); + // confirm the actual mount destination is owned by the user + if (fstat(fd, &s) == -1 || s.st_uid != getuid()) + errExit("fstat"); + // preserve a read-only mount + struct statvfs vfs; + if (fstatvfs(fd, &vfs) == -1) + errExit("fstatvfs"); + if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY) + fs_rdonly(RUN_PULSE_DIR); + // mount via the link in /proc/self/fd + char *proc; + if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) + errExit("asprintf"); + if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0) + errExit("mount pulseaudio"); + fs_logger2("tmpfs", homeusercfg); + free(proc); + close(fd); + // check /proc/self/mountinfo to confirm the mount is ok + MountData *mptr = get_last_mount(); + if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) + errLogExit("invalid pulseaudio mount"); + + char *p; + if (asprintf(&p, "%s/client.conf", homeusercfg) == -1) + errExit("asprintf"); + fs_logger2("create", p); + free(p); } - // get a file descriptor for ~/.config/pulse, fails if there is any symlink - int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); - if (fd == -1) - errExit("safe_fd"); - // confirm again the actual mount destination is owned by the user - if (fstat(fd, &s) == -1) - errExit("fstat"); - if (s.st_uid != getuid()) { - fprintf(stderr, "Error: %s is not owned by the current user\n", homeusercfg); - exit(1); + else { + // set environment + if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0) + errExit("setenv"); } - // preserve a read-only mount - struct statvfs vfs; - if (fstatvfs(fd, &vfs) == -1) - errExit("fstatvfs"); - if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY) - fs_rdonly(RUN_PULSE_DIR); - // mount via the link in /proc/self/fd - char *proc; - if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) - errExit("asprintf"); - if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0) - errExit("mount pulseaudio"); - free(proc); - close(fd); - // check /proc/self/mountinfo to confirm the mount is ok - MountData *mptr = get_last_mount(); - if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) - errLogExit("invalid pulseaudio mount"); - fs_logger2("tmpfs", homeusercfg); - - char *p; - if (asprintf(&p, "%s/client.conf", homeusercfg) == -1) - errExit("asprintf"); - fs_logger2("create", p); - free(p); free(pulsecfg); free(homeusercfg); -- cgit v1.2.3-54-g00ecf