aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/pulseaudio.c
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-06-12 01:57:01 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2018-06-12 01:57:01 +0200
commit8db696600f6fd0f425e19f0f154ad6639e2f0a92 (patch)
treed5fefe65cd12d42928f0d5eb5c46049f75cf866d /src/firejail/pulseaudio.c
parentremoved CFG_CHROOT_DESKTOP config option (diff)
downloadfirejail-8db696600f6fd0f425e19f0f154ad6639e2f0a92.tar.gz
firejail-8db696600f6fd0f425e19f0f154ad6639e2f0a92.tar.zst
firejail-8db696600f6fd0f425e19f0f154ad6639e2f0a92.zip
additional mount hardening (pulseaudio, Xauthority)
Diffstat (limited to 'src/firejail/pulseaudio.c')
-rw-r--r--src/firejail/pulseaudio.c77
1 files changed, 52 insertions, 25 deletions
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index 15d44e4cc..e43307d70 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -24,6 +24,13 @@
24#include <dirent.h> 24#include <dirent.h>
25#include <sys/wait.h> 25#include <sys/wait.h>
26 26
27// on Debian 7 we are missing O_PATH definition
28#include <fcntl.h>
29#ifndef O_PATH
30#define O_PATH 010000000
31#endif
32
33
27// disable pulseaudio socket 34// disable pulseaudio socket
28void pulseaudio_disable(void) { 35void pulseaudio_disable(void) {
29 if (arg_debug) 36 if (arg_debug)
@@ -72,14 +79,19 @@ void pulseaudio_init(void) {
72 struct stat s; 79 struct stat s;
73 80
74 // do we have pulseaudio in the system? 81 // do we have pulseaudio in the system?
75 if (stat("/etc/pulse/client.conf", &s) == -1) 82 if (stat("/etc/pulse/client.conf", &s) == -1) {
83 if (arg_debug)
84 printf("/etc/pulse/client.conf not found\n");
76 return; 85 return;
86 }
77 87
78 // create the new user pulseaudio directory 88 // create the new user pulseaudio directory
79 int rv = mkdir(RUN_PULSE_DIR, 0700); 89 if (mkdir(RUN_PULSE_DIR, 0700) == -1)
80 (void) rv; // in --chroot mode the directory can already be there 90 errExit("mkdir");
81 if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700)) 91 // make it a mount point and add mount flags
82 errExit("set_perms"); 92 if (mount(RUN_PULSE_DIR, RUN_PULSE_DIR, NULL, MS_BIND, NULL) < 0 ||
93 mount(NULL, RUN_PULSE_DIR, NULL, MS_NOEXEC|MS_NODEV|MS_NOSUID|MS_BIND|MS_REMOUNT, NULL) < 0)
94 errExit("mount RUN_PULSE_DIR");
83 95
84 // create the new client.conf file 96 // create the new client.conf file
85 char *pulsecfg = NULL; 97 char *pulsecfg = NULL;
@@ -93,12 +105,15 @@ void pulseaudio_init(void) {
93 fprintf(fp, "%s", "\nenable-shm = no\n"); 105 fprintf(fp, "%s", "\nenable-shm = no\n");
94 SET_PERMS_STREAM(fp, getuid(), getgid(), 0644); 106 SET_PERMS_STREAM(fp, getuid(), getgid(), 0644);
95 fclose(fp); 107 fclose(fp);
108 // hand over the directory to the user
109 if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700))
110 errExit("set_perms");
96 111
97 // create ~/.config/pulse directory if not present 112 // create ~/.config/pulse directory if not present
98 char *dir1; 113 char *dir1;
99 if (asprintf(&dir1, "%s/.config", cfg.homedir) == -1) 114 if (asprintf(&dir1, "%s/.config", cfg.homedir) == -1)
100 errExit("asprintf"); 115 errExit("asprintf");
101 if (stat(dir1, &s) == -1) { 116 if (lstat(dir1, &s) == -1) {
102 pid_t child = fork(); 117 pid_t child = fork();
103 if (child < 0) 118 if (child < 0)
104 errExit("fork"); 119 errExit("fork");
@@ -121,9 +136,12 @@ void pulseaudio_init(void) {
121 fs_logger2("create", dir1); 136 fs_logger2("create", dir1);
122 } 137 }
123 else { 138 else {
124 // make sure the directory is owned by the user 139 // we expect a user owned directory
125 if (s.st_uid != getuid()) { 140 if (!S_ISDIR(s.st_mode) || s.st_uid != getuid()) {
126 fprintf(stderr, "Error: user .config directory is not owned by the current user\n"); 141 if (S_ISLNK(s.st_mode))
142 fprintf(stderr, "Error: user .config is a symbolic link\n");
143 else
144 fprintf(stderr, "Error: user .config is not a directory owned by the current user\n");
127 exit(1); 145 exit(1);
128 } 146 }
129 } 147 }
@@ -131,7 +149,7 @@ void pulseaudio_init(void) {
131 149
132 if (asprintf(&dir1, "%s/.config/pulse", cfg.homedir) == -1) 150 if (asprintf(&dir1, "%s/.config/pulse", cfg.homedir) == -1)
133 errExit("asprintf"); 151 errExit("asprintf");
134 if (stat(dir1, &s) == -1) { 152 if (lstat(dir1, &s) == -1) {
135 pid_t child = fork(); 153 pid_t child = fork();
136 if (child < 0) 154 if (child < 0)
137 errExit("fork"); 155 errExit("fork");
@@ -154,33 +172,42 @@ void pulseaudio_init(void) {
154 fs_logger2("create", dir1); 172 fs_logger2("create", dir1);
155 } 173 }
156 else { 174 else {
157 // make sure the directory is owned by the user 175 // we expect a user owned directory
158 if (s.st_uid != getuid()) { 176 if (!S_ISDIR(s.st_mode) || s.st_uid != getuid()) {
159 fprintf(stderr, "Error: user .config/pulse directory is not owned by the current user\n"); 177 if (S_ISLNK(s.st_mode))
178 fprintf(stderr, "Error: user .config/pulse is a symbolic link\n");
179 else
180 fprintf(stderr, "Error: user .config/pulse is not a directory owned by the current user\n");
160 exit(1); 181 exit(1);
161 } 182 }
162 } 183 }
163 free(dir1); 184 free(dir1);
164 185
165 // if we have ~/.config/pulse mount the new directory, else set environment variable 186 // if we have ~/.config/pulse mount the new directory, else set environment variable.
166 char *homeusercfg; 187 char *homeusercfg;
167 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1) 188 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
168 errExit("asprintf"); 189 errExit("asprintf");
169 if (stat(homeusercfg, &s) == 0) { 190 if (stat(homeusercfg, &s) == 0) {
170 if (is_link(homeusercfg)) { 191 // get a file descriptor for ~/.config/pulse, fails if there is any symlink
171 fprintf(stderr, "Error: user .config/pulse is a symbolic link\n"); 192 int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
172 exit(1); 193 if (fd == -1)
173 } 194 errExit("safe_fd");
174 if (mount(RUN_PULSE_DIR, homeusercfg, "none", MS_BIND, NULL) < 0 || 195 // confirm the actual mount destination is owned by the user
175 mount(NULL, homeusercfg, NULL, MS_NOEXEC|MS_NODEV|MS_NOSUID|MS_BIND|MS_REMOUNT, NULL) < 0) 196 if (fstat(fd, &s) == -1 || s.st_uid != getuid())
197 errExit("fstat");
198
199 // mount via the link in /proc/self/fd
200 char *proc;
201 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
202 errExit("asprintf");
203 if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0)
176 errExit("mount pulseaudio"); 204 errExit("mount pulseaudio");
177 fs_logger2("tmpfs", homeusercfg); 205 fs_logger2("tmpfs", homeusercfg);
178 206 free(proc);
207 close(fd);
179 // check /proc/self/mountinfo to confirm the mount is ok 208 // check /proc/self/mountinfo to confirm the mount is ok
180 MountData *mptr = get_last_mount(); 209 MountData *mptr = get_last_mount();
181 if (strcmp(mptr->dir, homeusercfg) != 0) 210 if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
182 errLogExit("invalid pulseaudio mount");
183 if (strcmp(mptr->fstype, "tmpfs") != 0)
184 errLogExit("invalid pulseaudio mount"); 211 errLogExit("invalid pulseaudio mount");
185 212
186 char *p; 213 char *p;