diff options
-rw-r--r-- | src/firejail/fs.c | 60 | ||||
-rw-r--r-- | src/firejail/main.c | 2 |
2 files changed, 43 insertions, 19 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 825f004cc..ed0131b1d 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -1160,7 +1160,8 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1160 | exit(1); | 1160 | exit(1); |
1161 | } | 1161 | } |
1162 | 1162 | ||
1163 | // rootdir has to be owned by root | 1163 | // rootdir has to be owned by root and is not allowed to be world-writable |
1164 | // we checked already if it is a directory | ||
1164 | if (stat(rootdir, &s) != 0) { | 1165 | if (stat(rootdir, &s) != 0) { |
1165 | fprintf(stderr, "Error: cannot find chroot directory\n"); | 1166 | fprintf(stderr, "Error: cannot find chroot directory\n"); |
1166 | exit(1); | 1167 | exit(1); |
@@ -1169,6 +1170,10 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1169 | fprintf(stderr, "Error: chroot directory should be owned by root\n"); | 1170 | fprintf(stderr, "Error: chroot directory should be owned by root\n"); |
1170 | exit(1); | 1171 | exit(1); |
1171 | } | 1172 | } |
1173 | if ((S_IWOTH & s.st_mode) != 0) { | ||
1174 | fprintf(stderr, "Error: chroot directory is not allowed to be world-writable\n"); | ||
1175 | exit(1); | ||
1176 | } | ||
1172 | 1177 | ||
1173 | // check /dev | 1178 | // check /dev |
1174 | if (asprintf(&name, "%s/dev", rootdir) == -1) | 1179 | if (asprintf(&name, "%s/dev", rootdir) == -1) |
@@ -1177,8 +1182,8 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1177 | fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); | 1182 | fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); |
1178 | exit(1); | 1183 | exit(1); |
1179 | } | 1184 | } |
1180 | if (s.st_uid != 0) { | 1185 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { |
1181 | fprintf(stderr, "Error: chroot /dev directory should be owned by root\n"); | 1186 | fprintf(stderr, "Error: chroot /dev should be a directory owned by root\n"); |
1182 | exit(1); | 1187 | exit(1); |
1183 | } | 1188 | } |
1184 | free(name); | 1189 | free(name); |
@@ -1190,8 +1195,8 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1190 | fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); | 1195 | fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); |
1191 | exit(1); | 1196 | exit(1); |
1192 | } | 1197 | } |
1193 | if (s.st_uid != 0) { | 1198 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { |
1194 | fprintf(stderr, "Error: chroot /var/tmp directory should be owned by root\n"); | 1199 | fprintf(stderr, "Error: chroot /var/tmp should be a directory owned by root\n"); |
1195 | exit(1); | 1200 | exit(1); |
1196 | } | 1201 | } |
1197 | free(name); | 1202 | free(name); |
@@ -1203,8 +1208,8 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1203 | fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); | 1208 | fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); |
1204 | exit(1); | 1209 | exit(1); |
1205 | } | 1210 | } |
1206 | if (s.st_uid != 0) { | 1211 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { |
1207 | fprintf(stderr, "Error: chroot /proc directory should be owned by root\n"); | 1212 | fprintf(stderr, "Error: chroot /proc should be a directory owned by root\n"); |
1208 | exit(1); | 1213 | exit(1); |
1209 | } | 1214 | } |
1210 | free(name); | 1215 | free(name); |
@@ -1216,8 +1221,8 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1216 | fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); | 1221 | fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); |
1217 | exit(1); | 1222 | exit(1); |
1218 | } | 1223 | } |
1219 | if (s.st_uid != 0) { | 1224 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { |
1220 | fprintf(stderr, "Error: chroot /tmp directory should be owned by root\n"); | 1225 | fprintf(stderr, "Error: chroot /tmp should be a directory owned by root\n"); |
1221 | exit(1); | 1226 | exit(1); |
1222 | } | 1227 | } |
1223 | free(name); | 1228 | free(name); |
@@ -1229,8 +1234,12 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1229 | fprintf(stderr, "Error: cannot find /etc in chroot directory\n"); | 1234 | fprintf(stderr, "Error: cannot find /etc in chroot directory\n"); |
1230 | exit(1); | 1235 | exit(1); |
1231 | } | 1236 | } |
1232 | if (s.st_uid != 0) { | 1237 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { |
1233 | fprintf(stderr, "Error: chroot /etc directory should be owned by root\n"); | 1238 | fprintf(stderr, "Error: chroot /etc should be a directory owned by root\n"); |
1239 | exit(1); | ||
1240 | } | ||
1241 | if ((S_IWOTH & s.st_mode) != 0) { | ||
1242 | fprintf(stderr, "Error: chroot /etc is not allowed to be world-writable\n"); | ||
1234 | exit(1); | 1243 | exit(1); |
1235 | } | 1244 | } |
1236 | free(name); | 1245 | free(name); |
@@ -1272,8 +1281,8 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1272 | fprintf(stderr, "Error: cannot find /tmp/.X11-unix in chroot directory\n"); | 1281 | fprintf(stderr, "Error: cannot find /tmp/.X11-unix in chroot directory\n"); |
1273 | exit(1); | 1282 | exit(1); |
1274 | } | 1283 | } |
1275 | if (s.st_uid != 0) { | 1284 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { |
1276 | fprintf(stderr, "Error: chroot /tmp/.X11-unix directory should be owned by root\n"); | 1285 | fprintf(stderr, "Error: chroot /tmp/.X11-unix should be a directory owned by root\n"); |
1277 | exit(1); | 1286 | exit(1); |
1278 | } | 1287 | } |
1279 | free(name); | 1288 | free(name); |
@@ -1308,16 +1317,29 @@ void fs_chroot(const char *rootdir) { | |||
1308 | 1317 | ||
1309 | // some older distros don't have a /run directory | 1318 | // some older distros don't have a /run directory |
1310 | // create one by default | 1319 | // create one by default |
1311 | // create /run/firejail directory in chroot | ||
1312 | char *rundir; | 1320 | char *rundir; |
1313 | if (asprintf(&rundir, "%s/run", rootdir) == -1) | 1321 | if (asprintf(&rundir, "%s/run", rootdir) == -1) |
1314 | errExit("asprintf"); | 1322 | errExit("asprintf"); |
1315 | if (is_link(rundir)) { | 1323 | struct stat s; |
1316 | fprintf(stderr, "Error: invalid run directory inside chroot\n"); | 1324 | if (lstat(rundir, &s) == 0) { |
1317 | exit(1); | 1325 | if (S_ISLNK(s.st_mode)) { |
1326 | fprintf(stderr, "Error: chroot /run is a symbolic link\n"); | ||
1327 | exit(1); | ||
1328 | } | ||
1329 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { | ||
1330 | fprintf(stderr, "Error: chroot /run should be a directory owned by root\n"); | ||
1331 | exit(1); | ||
1332 | } | ||
1333 | if ((S_IWOTH & s.st_mode) != 0) { | ||
1334 | fprintf(stderr, "Error: chroot /run is not allowed to be world-writable\n"); | ||
1335 | exit(1); | ||
1336 | } | ||
1318 | } | 1337 | } |
1319 | create_empty_dir_as_root(rundir, 0755); | 1338 | else |
1339 | create_empty_dir_as_root(rundir, 0755); | ||
1320 | free(rundir); | 1340 | free(rundir); |
1341 | |||
1342 | // create /run/firejail directory in chroot | ||
1321 | if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1) | 1343 | if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1) |
1322 | errExit("asprintf"); | 1344 | errExit("asprintf"); |
1323 | create_empty_dir_as_root(rundir, 0755); | 1345 | create_empty_dir_as_root(rundir, 0755); |
@@ -1329,6 +1351,7 @@ void fs_chroot(const char *rootdir) { | |||
1329 | create_empty_dir_as_root(rundir, 0755); | 1351 | create_empty_dir_as_root(rundir, 0755); |
1330 | if (mount(RUN_MNT_DIR, rundir, NULL, MS_BIND|MS_REC, NULL) < 0) | 1352 | if (mount(RUN_MNT_DIR, rundir, NULL, MS_BIND|MS_REC, NULL) < 0) |
1331 | errExit("mount bind"); | 1353 | errExit("mount bind"); |
1354 | free(rundir); | ||
1332 | 1355 | ||
1333 | // copy /etc/resolv.conf in chroot directory | 1356 | // copy /etc/resolv.conf in chroot directory |
1334 | char *fname; | 1357 | char *fname; |
@@ -1339,6 +1362,7 @@ void fs_chroot(const char *rootdir) { | |||
1339 | unlink(fname); | 1362 | unlink(fname); |
1340 | if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) // root needed | 1363 | if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) // root needed |
1341 | fwarning("/etc/resolv.conf not initialized\n"); | 1364 | fwarning("/etc/resolv.conf not initialized\n"); |
1365 | free(fname); | ||
1342 | 1366 | ||
1343 | // chroot into the new directory | 1367 | // chroot into the new directory |
1344 | #ifdef HAVE_GCOV | 1368 | #ifdef HAVE_GCOV |
diff --git a/src/firejail/main.c b/src/firejail/main.c index ba952b1cb..435c04d76 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -1502,7 +1502,7 @@ int main(int argc, char **argv) { | |||
1502 | 1502 | ||
1503 | // check chroot dirname exists | 1503 | // check chroot dirname exists |
1504 | if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) { | 1504 | if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) { |
1505 | fprintf(stderr, "Error: invalid directory %s\n", cfg.chrootdir); | 1505 | fprintf(stderr, "Error: invalid chroot directory %s\n", cfg.chrootdir); |
1506 | return 1; | 1506 | return 1; |
1507 | } | 1507 | } |
1508 | 1508 | ||