aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/firejail/pulseaudio.c126
-rw-r--r--src/firejail/restrict_users.c23
2 files changed, 67 insertions, 82 deletions
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index a8fb838ab..b4df78dda 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -27,7 +27,7 @@
27 27
28#include <fcntl.h> 28#include <fcntl.h>
29#ifndef O_PATH 29#ifndef O_PATH
30# define O_PATH 010000000 30#define O_PATH 010000000
31#endif 31#endif
32 32
33// disable pulseaudio socket 33// disable pulseaudio socket
@@ -72,8 +72,13 @@ void pulseaudio_disable(void) {
72 closedir(dir); 72 closedir(dir);
73} 73}
74 74
75static void pulseaudio_set_environment(const char *path) {
76 assert(path);
77 if (setenv("PULSE_CLIENTCONFIG", path, 1) < 0)
78 errExit("setenv");
79}
75 80
76// disable shm in pulseaudio 81// disable shm in pulseaudio (issue #69)
77void pulseaudio_init(void) { 82void pulseaudio_init(void) {
78 struct stat s; 83 struct stat s;
79 84
@@ -108,84 +113,63 @@ void pulseaudio_init(void) {
108 errExit("set_perms"); 113 errExit("set_perms");
109 114
110 // create ~/.config/pulse directory if not present 115 // create ~/.config/pulse directory if not present
111 char *homeusercfg; 116 char *homeusercfg = NULL;
112 if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1) 117 if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1)
113 errExit("asprintf"); 118 errExit("asprintf");
114 if (lstat(homeusercfg, &s) == -1) { 119 if (create_empty_dir_as_user(homeusercfg, 0700))
115 if (create_empty_dir_as_user(homeusercfg, 0700)) 120 fs_logger2("create", homeusercfg);
116 fs_logger2("create", homeusercfg);
117 }
118 else if (!S_ISDIR(s.st_mode)) {
119 if (S_ISLNK(s.st_mode))
120 fprintf(stderr, "Error: %s is a symbolic link\n", homeusercfg);
121 else
122 fprintf(stderr, "Error: %s is not a directory\n", homeusercfg);
123 exit(1);
124 }
125 free(homeusercfg);
126 121
122 free(homeusercfg);
127 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1) 123 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
128 errExit("asprintf"); 124 errExit("asprintf");
129 if (lstat(homeusercfg, &s) == -1) { 125 if (create_empty_dir_as_user(homeusercfg, 0700))
130 if (create_empty_dir_as_user(homeusercfg, 0700)) 126 fs_logger2("create", homeusercfg);
131 fs_logger2("create", homeusercfg); 127
132 } 128 // if ~/.config/pulse now exists and there are no symbolic links, mount the new directory
133 else if (!S_ISDIR(s.st_mode)) { 129 // else set environment variable
134 if (S_ISLNK(s.st_mode)) 130 int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
135 fprintf(stderr, "Error: %s is a symbolic link\n", homeusercfg); 131 if (fd == -1) {
136 else 132 pulseaudio_set_environment(pulsecfg);
137 fprintf(stderr, "Error: %s is not a directory\n", homeusercfg); 133 goto out;
138 exit(1);
139 } 134 }
140 135 // confirm the actual mount destination is owned by the user
141 // if we have ~/.config/pulse mount the new directory, else set environment variable. 136 if (fstat(fd, &s) == -1)
142 if (stat(homeusercfg, &s) == 0) { 137 errExit("fstat");
143 // get a file descriptor for ~/.config/pulse, fails if there is any symlink 138 if (s.st_uid != getuid()) {
144 int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
145 if (fd == -1)
146 errExit("safe_fd");
147 // confirm the actual mount destination is owned by the user
148 if (fstat(fd, &s) == -1)
149 errExit("fstat");
150 if (s.st_uid != getuid()) {
151 fprintf(stderr, "Error: %s is not owned by the current user\n", homeusercfg);
152 exit(1);
153 }
154 // preserve a read-only mount
155 struct statvfs vfs;
156 if (fstatvfs(fd, &vfs) == -1)
157 errExit("fstatvfs");
158 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY)
159 fs_remount(RUN_PULSE_DIR, MOUNT_READONLY, 0);
160 // mount via the link in /proc/self/fd
161 if (arg_debug)
162 printf("Mounting %s on %s\n", RUN_PULSE_DIR, homeusercfg);
163 char *proc;
164 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
165 errExit("asprintf");
166 if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0)
167 errExit("mount pulseaudio");
168 fs_logger2("tmpfs", homeusercfg);
169 free(proc);
170 close(fd); 139 close(fd);
171 // check /proc/self/mountinfo to confirm the mount is ok 140 pulseaudio_set_environment(pulsecfg);
172 MountData *mptr = get_last_mount(); 141 goto out;
173 if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
174 errLogExit("invalid pulseaudio mount");
175
176 char *p;
177 if (asprintf(&p, "%s/client.conf", homeusercfg) == -1)
178 errExit("asprintf");
179 fs_logger2("create", p);
180 free(p);
181 }
182
183 else {
184 // set environment
185 if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0)
186 errExit("setenv");
187 } 142 }
143 // preserve a read-only mount
144 struct statvfs vfs;
145 if (fstatvfs(fd, &vfs) == -1)
146 errExit("fstatvfs");
147 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY)
148 fs_remount(RUN_PULSE_DIR, MOUNT_READONLY, 0);
149 // mount via the link in /proc/self/fd
150 if (arg_debug)
151 printf("Mounting %s on %s\n", RUN_PULSE_DIR, homeusercfg);
152 char *proc;
153 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
154 errExit("asprintf");
155 if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0)
156 errExit("mount pulseaudio");
157 // check /proc/self/mountinfo to confirm the mount is ok
158 MountData *mptr = get_last_mount();
159 if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
160 errLogExit("invalid pulseaudio mount");
161 fs_logger2("tmpfs", homeusercfg);
162 free(proc);
163 close(fd);
164
165 char *p;
166 if (asprintf(&p, "%s/client.conf", homeusercfg) == -1)
167 errExit("asprintf");
168 fs_logger2("create", p);
169 pulseaudio_set_environment(p);
170 free(p);
188 171
172out:
189 free(pulsecfg); 173 free(pulsecfg);
190 free(homeusercfg); 174 free(homeusercfg);
191} 175}
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c
index 5ebb0e9ec..804b45339 100644
--- a/src/firejail/restrict_users.c
+++ b/src/firejail/restrict_users.c
@@ -29,7 +29,7 @@
29 29
30#include <fcntl.h> 30#include <fcntl.h>
31#ifndef O_PATH 31#ifndef O_PATH
32# define O_PATH 010000000 32#define O_PATH 010000000
33#endif 33#endif
34 34
35#define MAXBUF 1024 35#define MAXBUF 1024
@@ -68,24 +68,25 @@ static USER_LIST *ulist_find(const char *user) {
68 68
69static void sanitize_home(void) { 69static void sanitize_home(void) {
70 assert(getuid() != 0); // this code works only for regular users 70 assert(getuid() != 0); // this code works only for regular users
71 struct stat s;
71 72
72 if (arg_debug) 73 if (arg_debug)
73 printf("Cleaning /home directory\n"); 74 printf("Cleaning /home directory\n");
74 75
75 struct stat s;
76 if (stat(cfg.homedir, &s) == -1) {
77 // cannot find home directory, just return
78 fwarning("cannot find home directory\n");
79 return;
80 }
81
82 if (mkdir(RUN_WHITELIST_HOME_DIR, 0755) == -1) 76 if (mkdir(RUN_WHITELIST_HOME_DIR, 0755) == -1)
83 errExit("mkdir"); 77 errExit("mkdir");
84 78
85 // keep a copy of the user home directory 79 // keep a copy of the user home directory
86 int fd = safe_fd(cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 80 int fd = safe_fd(cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
87 if (fd == -1) 81 if (fd == -1) {
88 errExit("safe_fd"); 82 if (errno == ENOENT)
83 fwarning("cannot find user home directory\n");
84 else
85 fwarning("cannot clean /home directory\n");
86 return;
87 }
88 if (fstat(fd, &s) == -1)
89 errExit("fstat");
89 char *proc; 90 char *proc;
90 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 91 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
91 errExit("asprintf"); 92 errExit("asprintf");
@@ -167,7 +168,7 @@ static void sanitize_run(void) {
167 if (set_perms(runuser, getuid(), getgid(), 0700)) 168 if (set_perms(runuser, getuid(), getgid(), 0700))
168 errExit("set_perms"); 169 errExit("set_perms");
169 170
170 // mount user home directory 171 // mount /run/user/$UID directory
171 if (mount(RUN_WHITELIST_RUN_DIR, runuser, NULL, MS_BIND|MS_REC, NULL) < 0) 172 if (mount(RUN_WHITELIST_RUN_DIR, runuser, NULL, MS_BIND|MS_REC, NULL) < 0)
172 errExit("mount bind"); 173 errExit("mount bind");
173 174