diff options
author | smitsohu <smitsohu@gmail.com> | 2018-11-04 19:03:49 +0100 |
---|---|---|
committer | smitsohu <smitsohu@gmail.com> | 2018-11-04 19:03:49 +0100 |
commit | 35d2aec567c0e9c9b5c79678b1dc762916d5492c (patch) | |
tree | 40335d4a7320d830cc5f1717fb8afd6e95532330 /src/firejail/mountinfo.c | |
parent | mount appimages nodev,nosuid (diff) | |
download | firejail-35d2aec567c0e9c9b5c79678b1dc762916d5492c.tar.gz firejail-35d2aec567c0e9c9b5c79678b1dc762916d5492c.tar.zst firejail-35d2aec567c0e9c9b5c79678b1dc762916d5492c.zip |
recursive remounts: add fallback for old kernels, some improvements
* vanilla kernels before 3.15 don't expose a mount id in /proc/pid/fdinfo files.
This is still relevant on Ubuntu 14.04 with 3.13 kernel, CentOS 7 doesn't
have this problem. In this case fall back to simple a remount and print
a warning.
* drop euid switching as it doesn't really serve a purpose here (paths are not opened
in reading or writing mode, and we are not doing anything with it) and potentially
causes problems when suid programs are sandboxed
* more rigorous error handling
Diffstat (limited to 'src/firejail/mountinfo.c')
-rw-r--r-- | src/firejail/mountinfo.c | 44 |
1 files changed, 29 insertions, 15 deletions
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c index b7e6c6fdd..ab1e501a7 100644 --- a/src/firejail/mountinfo.c +++ b/src/firejail/mountinfo.c | |||
@@ -153,7 +153,6 @@ MountData *get_last_mount(void) { | |||
153 | 153 | ||
154 | // Extract the mount id from /proc/self/fdinfo and return it. | 154 | // Extract the mount id from /proc/self/fdinfo and return it. |
155 | int get_mount_id(const char *path) { | 155 | int get_mount_id(const char *path) { |
156 | EUID_ASSERT(); | ||
157 | int fd = open(path, O_PATH|O_CLOEXEC); | 156 | int fd = open(path, O_PATH|O_CLOEXEC); |
158 | if (fd == -1) | 157 | if (fd == -1) |
159 | return -1; | 158 | return -1; |
@@ -161,32 +160,41 @@ int get_mount_id(const char *path) { | |||
161 | char *fdinfo; | 160 | char *fdinfo; |
162 | if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) | 161 | if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) |
163 | errExit("asprintf"); | 162 | errExit("asprintf"); |
164 | EUID_ROOT(); | ||
165 | FILE *fp = fopen(fdinfo, "re"); | 163 | FILE *fp = fopen(fdinfo, "re"); |
166 | EUID_USER(); | 164 | if (!fp) { |
167 | if (!fp) | 165 | perror("fopen"); |
168 | goto errexit; | 166 | fprintf(stderr, "Error: cannot open %s\n", fdinfo); |
167 | exit(1); | ||
168 | } | ||
169 | 169 | ||
170 | // read the file | 170 | // read the file |
171 | char buf[MAX_BUF]; | 171 | char buf[MAX_BUF]; |
172 | while (fgets(buf, MAX_BUF, fp)) { | 172 | if (fgets(buf, MAX_BUF, fp) == NULL) { |
173 | fprintf(stderr, "Error: cannot read %s\n", fdinfo); | ||
174 | exit(1); | ||
175 | } | ||
176 | do { | ||
173 | if (strncmp(buf, "mnt_id:", 7) == 0) { | 177 | if (strncmp(buf, "mnt_id:", 7) == 0) { |
174 | char *ptr = buf + 7; | 178 | char *ptr = buf + 7; |
175 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { | 179 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { |
176 | ptr++; | 180 | ptr++; |
177 | } | 181 | } |
178 | if (*ptr == '\0') | 182 | if (*ptr == '\0') { |
179 | goto errexit; | 183 | fprintf(stderr, "Error: cannot read %s\n", fdinfo); |
184 | exit(1); | ||
185 | } | ||
180 | fclose(fp); | 186 | fclose(fp); |
181 | close(fd); | 187 | close(fd); |
182 | free(fdinfo); | 188 | free(fdinfo); |
183 | return atoi(ptr); | 189 | return atoi(ptr); |
184 | } | 190 | } |
185 | } | 191 | } while (fgets(buf, MAX_BUF, fp)); |
186 | 192 | ||
187 | errexit: | 193 | // fallback, kernels older than 3.15 don't expose the mount id in this place |
188 | fprintf(stderr, "Error: cannot read %s\n", fdinfo); | 194 | fclose(fp); |
189 | exit(1); | 195 | close(fd); |
196 | free(fdinfo); | ||
197 | return -2; | ||
190 | } | 198 | } |
191 | 199 | ||
192 | // Return array with all paths that might need a remount. | 200 | // Return array with all paths that might need a remount. |
@@ -208,7 +216,11 @@ char **build_mount_array(const int mountid, const char *path) { | |||
208 | // read /proc/self/mountinfo | 216 | // read /proc/self/mountinfo |
209 | size_t pathlen = strlen(path); | 217 | size_t pathlen = strlen(path); |
210 | int found = 0; | 218 | int found = 0; |
211 | while (fgets(mbuf, MAX_BUF, fp)) { | 219 | if (fgets(mbuf, MAX_BUF, fp) == NULL) { |
220 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | ||
221 | exit(1); | ||
222 | } | ||
223 | do { | ||
212 | // find mount point with mount id | 224 | // find mount point with mount id |
213 | if (!found) { | 225 | if (!found) { |
214 | parse_line(mbuf, &mdata); | 226 | parse_line(mbuf, &mdata); |
@@ -230,7 +242,8 @@ char **build_mount_array(const int mountid, const char *path) { | |||
230 | else | 242 | else |
231 | continue; | 243 | continue; |
232 | } | 244 | } |
233 | // from here on add all mount points below path | 245 | // from here on add all mount points below path, |
246 | // don't remount blacklisted paths | ||
234 | parse_line(mbuf, &mdata); | 247 | parse_line(mbuf, &mdata); |
235 | if (strncmp(mdata.dir, path, pathlen) == 0 && | 248 | if (strncmp(mdata.dir, path, pathlen) == 0 && |
236 | mdata.dir[pathlen] == '/' && | 249 | mdata.dir[pathlen] == '/' && |
@@ -248,7 +261,8 @@ char **build_mount_array(const int mountid, const char *path) { | |||
248 | errExit("strdup"); | 261 | errExit("strdup"); |
249 | cnt++; | 262 | cnt++; |
250 | } | 263 | } |
251 | } | 264 | } while (fgets(mbuf, MAX_BUF, fp)); |
265 | |||
252 | if (cnt == size) { | 266 | if (cnt == size) { |
253 | size++; | 267 | size++; |
254 | rv = realloc(rv, size * sizeof(*rv)); | 268 | rv = realloc(rv, size * sizeof(*rv)); |