aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-12-11 20:49:54 +0100
committerLibravatar smitsohu <smitsohu@gmail.com>2018-12-11 20:49:54 +0100
commit93779cb9cd0d098cd3587e2f795200d98e3af1ee (patch)
tree1ede125095137385b0da7f20e3a6f7da96d3105a
parentadd create_empty_dir_as_user function, refactor (diff)
downloadfirejail-93779cb9cd0d098cd3587e2f795200d98e3af1ee.tar.gz
firejail-93779cb9cd0d098cd3587e2f795200d98e3af1ee.tar.zst
firejail-93779cb9cd0d098cd3587e2f795200d98e3af1ee.zip
pulseaudio: use env variable fallback in more cases
setting the PULSE_CLIENTCONFIG environment variable to the unmounted file is a safe fallback, use it in more cases when mounting is considered not an option
-rw-r--r--src/firejail/pulseaudio.c170
1 files changed, 60 insertions, 110 deletions
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index 4ddaba7ed..ce1692ba2 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -102,124 +102,74 @@ void pulseaudio_init(void) {
102 if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700)) 102 if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700))
103 errExit("set_perms"); 103 errExit("set_perms");
104 104
105 // create ~/.config/pulse directory if not present 105 // create ~/.config directory if necessary
106 char *dir1; 106 char *homeusercfg;
107 if (asprintf(&dir1, "%s/.config", cfg.homedir) == -1) 107 if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1)
108 errExit("asprintf");
109 if (lstat(dir1, &s) == -1) {
110 pid_t child = fork();
111 if (child < 0)
112 errExit("fork");
113 if (child == 0) {
114 // drop privileges
115 drop_privs(0);
116
117 int rv = mkdir(dir1, 0755);
118 if (rv == 0) {
119 if (chmod(dir1, 0755))
120 {;} // do nothing
121 }
122#ifdef HAVE_GCOV
123 __gcov_flush();
124#endif
125 _exit(0);
126 }
127 // wait for the child to finish
128 waitpid(child, NULL, 0);
129 fs_logger2("create", dir1);
130 }
131 else {
132 // we expect a user owned directory
133 if (!S_ISDIR(s.st_mode) || s.st_uid != getuid()) {
134 if (S_ISLNK(s.st_mode))
135 fprintf(stderr, "Error: user .config is a symbolic link\n");
136 else
137 fprintf(stderr, "Error: user .config is not a directory owned by the current user\n");
138 exit(1);
139 }
140 }
141 free(dir1);
142
143 if (asprintf(&dir1, "%s/.config/pulse", cfg.homedir) == -1)
144 errExit("asprintf"); 108 errExit("asprintf");
145 if (lstat(dir1, &s) == -1) { 109 create_empty_dir_as_user(homeusercfg, 0700);
146 pid_t child = fork(); 110 // set environment variable if creating ~/.config wasn't successful or if it is not a directory owned by the user
147 if (child < 0) 111 if (lstat(homeusercfg, &s) != 0 || !S_ISDIR(s.st_mode) || s.st_uid != getuid()) {
148 errExit("fork"); 112 if (arg_debug)
149 if (child == 0) { 113 printf("Setting PULSE_CLIENTCONFIG environment variable\n");
150 // drop privileges 114 if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0)
151 drop_privs(0); 115 errExit("setenv");
152 116 free(homeusercfg);
153 int rv = mkdir(dir1, 0700); 117 free(pulsecfg);
154 if (rv == 0) { 118 return;
155 if (chmod(dir1, 0700))
156 {;} // do nothing
157 }
158#ifdef HAVE_GCOV
159 __gcov_flush();
160#endif
161 _exit(0);
162 }
163 // wait for the child to finish
164 waitpid(child, NULL, 0);
165 fs_logger2("create", dir1);
166 }
167 else {
168 // we expect a user owned directory
169 if (!S_ISDIR(s.st_mode) || s.st_uid != getuid()) {
170 if (S_ISLNK(s.st_mode))
171 fprintf(stderr, "Error: user .config/pulse is a symbolic link\n");
172 else
173 fprintf(stderr, "Error: user .config/pulse is not a directory owned by the current user\n");
174 exit(1);
175 }
176 } 119 }
177 free(dir1); 120 free(homeusercfg);
178 121
179 // if we have ~/.config/pulse mount the new directory, else set environment variable. 122 // create ~/.config/pulse directory if necessary
180 char *homeusercfg;
181 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1) 123 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
182 errExit("asprintf"); 124 errExit("asprintf");
183 if (stat(homeusercfg, &s) == 0) { 125 create_empty_dir_as_user(homeusercfg, 0700);
184 // get a file descriptor for ~/.config/pulse, fails if there is any symlink 126 // set environment variable if creating ~/.config/pulse wasn't successful or if it is not a directory owned by the user
185 int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 127 if (lstat(homeusercfg, &s) != 0 || !S_ISDIR(s.st_mode) || s.st_uid != getuid()) {
186 if (fd == -1) 128 if (arg_debug)
187 errExit("safe_fd"); 129 printf("Setting PULSE_CLIENTCONFIG environment variable\n");
188 // confirm the actual mount destination is owned by the user
189 if (fstat(fd, &s) == -1 || s.st_uid != getuid())
190 errExit("fstat");
191 // preserve a read-only mount
192 struct statvfs vfs;
193 if (fstatvfs(fd, &vfs) == -1)
194 errExit("fstatvfs");
195 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY)
196 fs_rdonly(RUN_PULSE_DIR);
197 // mount via the link in /proc/self/fd
198 char *proc;
199 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
200 errExit("asprintf");
201 if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0)
202 errExit("mount pulseaudio");
203 fs_logger2("tmpfs", homeusercfg);
204 free(proc);
205 close(fd);
206 // check /proc/self/mountinfo to confirm the mount is ok
207 MountData *mptr = get_last_mount();
208 if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
209 errLogExit("invalid pulseaudio mount");
210
211 char *p;
212 if (asprintf(&p, "%s/client.conf", homeusercfg) == -1)
213 errExit("asprintf");
214 fs_logger2("create", p);
215 free(p);
216 }
217
218 else {
219 // set environment
220 if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0) 130 if (setenv("PULSE_CLIENTCONFIG", pulsecfg, 1) < 0)
221 errExit("setenv"); 131 errExit("setenv");
132 free(homeusercfg);
133 free(pulsecfg);
134 return;
135 }
136
137 // get a file descriptor for ~/.config/pulse, fails if there is any symlink
138 int fd = safe_fd(homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
139 if (fd == -1)
140 errExit("safe_fd");
141 // confirm again the actual mount destination is owned by the user
142 if (fstat(fd, &s) == -1)
143 errExit("fstat");
144 if (s.st_uid != getuid()) {
145 fprintf(stderr, "Error: %s is not owned by the current user\n", homeusercfg);
146 exit(1);
222 } 147 }
148 // preserve a read-only mount
149 struct statvfs vfs;
150 if (fstatvfs(fd, &vfs) == -1)
151 errExit("fstatvfs");
152 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY)
153 fs_rdonly(RUN_PULSE_DIR);
154 // mount via the link in /proc/self/fd
155 char *proc;
156 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
157 errExit("asprintf");
158 if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0)
159 errExit("mount pulseaudio");
160 free(proc);
161 close(fd);
162 // check /proc/self/mountinfo to confirm the mount is ok
163 MountData *mptr = get_last_mount();
164 if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
165 errLogExit("invalid pulseaudio mount");
166 fs_logger2("tmpfs", homeusercfg);
167
168 char *p;
169 if (asprintf(&p, "%s/client.conf", homeusercfg) == -1)
170 errExit("asprintf");
171 fs_logger2("create", p);
172 free(p);
223 173
224 free(pulsecfg); 174 free(pulsecfg);
225 free(homeusercfg); 175 free(homeusercfg);