diff options
-rw-r--r-- | src/firejail/pulseaudio.c | 126 | ||||
-rw-r--r-- | src/firejail/restrict_users.c | 23 |
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 | ||
75 | static 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) |
77 | void pulseaudio_init(void) { | 82 | void 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 | ||
172 | out: | ||
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 | ||
69 | static void sanitize_home(void) { | 69 | static 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 | ||