diff options
author | 2019-10-13 03:21:27 +0200 | |
---|---|---|
committer | 2019-10-13 03:21:27 +0200 | |
commit | 6cec1f7e1bed4c39a26d45e73f0bba6a13980997 (patch) | |
tree | 9b99d80cd3a05f83f685fd248839505b2c6b5fc7 | |
parent | shorten fedora firefox private-bin (diff) | |
download | firejail-6cec1f7e1bed4c39a26d45e73f0bba6a13980997.tar.gz firejail-6cec1f7e1bed4c39a26d45e73f0bba6a13980997.tar.zst firejail-6cec1f7e1bed4c39a26d45e73f0bba6a13980997.zip |
x11 hardening
-rw-r--r-- | src/firejail/fs.c | 2 | ||||
-rw-r--r-- | src/firejail/x11.c | 44 |
2 files changed, 35 insertions, 11 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index f2639f318..003b15605 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -1134,6 +1134,7 @@ void fs_private_tmp(void) { | |||
1134 | char *cmd; | 1134 | char *cmd; |
1135 | if (asprintf(&cmd, "whitelist %s", rp) == -1) | 1135 | if (asprintf(&cmd, "whitelist %s", rp) == -1) |
1136 | errExit("asprintf"); | 1136 | errExit("asprintf"); |
1137 | profile_check_line(cmd, 0, NULL); | ||
1137 | profile_add(cmd); // profile_add does not duplicate the string | 1138 | profile_add(cmd); // profile_add does not duplicate the string |
1138 | } | 1139 | } |
1139 | if (rp) | 1140 | if (rp) |
@@ -1162,6 +1163,7 @@ void fs_private_tmp(void) { | |||
1162 | char *cmd; | 1163 | char *cmd; |
1163 | if (asprintf(&cmd, "whitelist /tmp/%s", entry->d_name) == -1) | 1164 | if (asprintf(&cmd, "whitelist /tmp/%s", entry->d_name) == -1) |
1164 | errExit("asprintf"); | 1165 | errExit("asprintf"); |
1166 | profile_check_line(cmd, 0, NULL); | ||
1165 | profile_add(cmd); // profile_add does not duplicate the string | 1167 | profile_add(cmd); // profile_add does not duplicate the string |
1166 | } | 1168 | } |
1167 | } | 1169 | } |
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index e707ab8bd..944c24bc7 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -1263,11 +1263,22 @@ void fs_x11(void) { | |||
1263 | if (display <= 0) | 1263 | if (display <= 0) |
1264 | return; | 1264 | return; |
1265 | 1265 | ||
1266 | struct stat s1, s2; | ||
1267 | if (stat("/tmp", &s1) != 0 || lstat("/tmp/.X11-unix", &s2) != 0) | ||
1268 | return; | ||
1269 | if ((s1.st_mode & S_ISVTX) == 0) { | ||
1270 | fwarning("cannot mask X11 sockets: sticky bit not set on /tmp directory\n"); | ||
1271 | return; | ||
1272 | } | ||
1273 | if (s2.st_uid != 0) { | ||
1274 | fwarning("cannot mask X11 sockets: /tmp/.X11-unix not owned by root user\n"); | ||
1275 | return; | ||
1276 | } | ||
1266 | char *x11file; | 1277 | char *x11file; |
1267 | if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1) | 1278 | if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1) |
1268 | errExit("asprintf"); | 1279 | errExit("asprintf"); |
1269 | struct stat x11stat; | 1280 | struct stat x11stat; |
1270 | if (stat(x11file, &x11stat) == -1 || !S_ISSOCK(x11stat.st_mode)) { | 1281 | if (lstat(x11file, &x11stat) != 0 || !S_ISSOCK(x11stat.st_mode)) { |
1271 | free(x11file); | 1282 | free(x11file); |
1272 | return; | 1283 | return; |
1273 | } | 1284 | } |
@@ -1278,12 +1289,8 @@ void fs_x11(void) { | |||
1278 | // Move the real /tmp/.X11-unix to a scratch location | 1289 | // Move the real /tmp/.X11-unix to a scratch location |
1279 | // so we can still access x11file after we mount a | 1290 | // so we can still access x11file after we mount a |
1280 | // tmpfs over /tmp/.X11-unix. | 1291 | // tmpfs over /tmp/.X11-unix. |
1281 | int rv = mkdir(RUN_WHITELIST_X11_DIR, 0700); | 1292 | if (mkdir(RUN_WHITELIST_X11_DIR, 0700) == -1) |
1282 | if (rv == -1) | ||
1283 | errExit("mkdir"); | 1293 | errExit("mkdir"); |
1284 | if (set_perms(RUN_WHITELIST_X11_DIR, 0, 0, 0700)) | ||
1285 | errExit("set_perms"); | ||
1286 | |||
1287 | if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0) | 1294 | if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0) |
1288 | errExit("mount bind"); | 1295 | errExit("mount bind"); |
1289 | 1296 | ||
@@ -1302,21 +1309,36 @@ void fs_x11(void) { | |||
1302 | errExit("fchown"); | 1309 | errExit("fchown"); |
1303 | close(fd); | 1310 | close(fd); |
1304 | 1311 | ||
1305 | // do the mount | 1312 | // the mount source is under control of the user, so be careful and |
1313 | // mount without following symbolic links, using a file descriptor | ||
1306 | char *wx11file; | 1314 | char *wx11file; |
1307 | if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1) | 1315 | if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1) |
1308 | errExit("asprintf"); | 1316 | errExit("asprintf"); |
1309 | if (mount(wx11file, x11file, NULL, MS_BIND|MS_REC, NULL) < 0) | 1317 | fd = safe_fd(wx11file, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
1318 | if (fd == -1) | ||
1319 | errExit("opening X11 socket"); | ||
1320 | // confirm once more we are mounting a socket | ||
1321 | if (fstat(fd, &x11stat) == -1) | ||
1322 | errExit("fstat"); | ||
1323 | if (!S_ISSOCK(x11stat.st_mode)) { | ||
1324 | errno = ENOTSOCK; | ||
1325 | errExit("mounting X11 socket"); | ||
1326 | } | ||
1327 | char *proc; | ||
1328 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | ||
1329 | errExit("asprintf"); | ||
1330 | if (mount(proc, x11file, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1310 | errExit("mount bind"); | 1331 | errExit("mount bind"); |
1311 | fs_logger2("whitelist", x11file); | 1332 | fs_logger2("whitelist", x11file); |
1312 | 1333 | close(fd); | |
1313 | free(x11file); | 1334 | free(proc); |
1314 | free(wx11file); | ||
1315 | 1335 | ||
1316 | // block access to RUN_WHITELIST_X11_DIR | 1336 | // block access to RUN_WHITELIST_X11_DIR |
1317 | if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, 0, MS_BIND, 0) < 0) | 1337 | if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, 0, MS_BIND, 0) < 0) |
1318 | errExit("mount"); | 1338 | errExit("mount"); |
1319 | fs_logger2("blacklist", RUN_WHITELIST_X11_DIR); | 1339 | fs_logger2("blacklist", RUN_WHITELIST_X11_DIR); |
1340 | free(wx11file); | ||
1341 | free(x11file); | ||
1320 | #endif | 1342 | #endif |
1321 | } | 1343 | } |
1322 | 1344 | ||