aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2019-07-08 11:24:00 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2019-07-08 11:24:00 +0200
commitf4d60fa954cc89222c321dd7ad1329baa1d8b26a (patch)
treef8c95fe3b0a78ed852fb3bfeb084b1dd3184d716 /src
parentmisc cleanup (safe_fd function) (diff)
downloadfirejail-f4d60fa954cc89222c321dd7ad1329baa1d8b26a.tar.gz
firejail-f4d60fa954cc89222c321dd7ad1329baa1d8b26a.tar.zst
firejail-f4d60fa954cc89222c321dd7ad1329baa1d8b26a.zip
reduce redundancy in fs_check_chroot_dir
Diffstat (limited to 'src')
-rw-r--r--src/firejail/fs.c130
1 files changed, 47 insertions, 83 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 9a15d825e..13f01a51b 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -1127,11 +1127,36 @@ void fs_overlayfs(void) {
1127 1127
1128#ifdef HAVE_CHROOT 1128#ifdef HAVE_CHROOT
1129// exit if error 1129// exit if error
1130static void fs_check_chroot_subdir(const char *subdir, int parentfd, int check_writable) {
1131 assert(subdir);
1132 int fd = openat(parentfd, subdir, O_PATH|O_CLOEXEC);
1133 if (fd == -1) {
1134 if (errno == ENOENT)
1135 fprintf(stderr, "Error: cannot find /%s in chroot directory\n", subdir);
1136 else {
1137 perror("open");
1138 fprintf(stderr, "Error: cannot open /%s in chroot directory\n", subdir);
1139 }
1140 exit(1);
1141 }
1142 struct stat s;
1143 if (fstat(fd, &s) == -1)
1144 errExit("fstat");
1145 close(fd);
1146 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1147 fprintf(stderr, "Error: chroot /%s should be a directory owned by root\n", subdir);
1148 exit(1);
1149 }
1150 if (check_writable && ((S_IWGRP|S_IWOTH) & s.st_mode) != 0) {
1151 fprintf(stderr, "Error: only root user should be given write permission on chroot /%s\n", subdir);
1152 exit(1);
1153 }
1154}
1155
1156// exit if error
1130void fs_check_chroot_dir(const char *rootdir) { 1157void fs_check_chroot_dir(const char *rootdir) {
1131 EUID_ASSERT(); 1158 EUID_ASSERT();
1132 assert(rootdir); 1159 assert(rootdir);
1133 char *dir = EMPTY_STRING;
1134 struct stat s;
1135 1160
1136 char *overlay; 1161 char *overlay;
1137 if (asprintf(&overlay, "%s/.firejail", cfg.homedir) == -1) 1162 if (asprintf(&overlay, "%s/.firejail", cfg.homedir) == -1)
@@ -1150,6 +1175,7 @@ void fs_check_chroot_dir(const char *rootdir) {
1150 } 1175 }
1151 // rootdir has to be owned by root and is not allowed to be generally writable, 1176 // rootdir has to be owned by root and is not allowed to be generally writable,
1152 // this also excludes /tmp, /var/tmp and such 1177 // this also excludes /tmp, /var/tmp and such
1178 struct stat s;
1153 if (fstat(parentfd, &s) == -1) 1179 if (fstat(parentfd, &s) == -1)
1154 errExit("fstat"); 1180 errExit("fstat");
1155 if (s.st_uid != 0) { 1181 if (s.st_uid != 0) {
@@ -1161,64 +1187,24 @@ void fs_check_chroot_dir(const char *rootdir) {
1161 exit(1); 1187 exit(1);
1162 } 1188 }
1163 1189
1164 // check /dev 1190 // check subdirectories in rootdir
1165 dir = "dev"; 1191 typedef struct {
1166 int fd = openat(parentfd, dir, O_PATH|O_CLOEXEC); 1192 char *dname;
1167 if (fd == -1) 1193 int check_writable;
1168 goto error1; 1194 } chrootsubdir;
1169 if (fstat(fd, &s) == -1) 1195 chrootsubdir dirs[] = {
1170 errExit("fstat"); 1196 {"dev", 0},
1171 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) 1197 {"etc", 1},
1172 goto error2; 1198 {"proc", 0},
1173 close(fd); 1199 {"tmp", 0},
1174 1200 {"var/tmp", 0},
1175 // check /var/tmp 1201 {NULL, 0}
1176 dir = "var/tmp"; 1202 };
1177 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC); 1203 chrootsubdir *tmp = dirs;
1178 if (fd == -1) 1204 while (tmp->dname) {
1179 goto error1; 1205 fs_check_chroot_subdir(tmp->dname, parentfd, tmp->check_writable);
1180 if (fstat(fd, &s) == -1) 1206 tmp++;
1181 errExit("fstat");
1182 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1183 goto error2;
1184 close(fd);
1185
1186 // check /proc
1187 dir = "proc";
1188 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1189 if (fd == -1)
1190 goto error1;
1191 if (fstat(fd, &s) == -1)
1192 errExit("fstat");
1193 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1194 goto error2;
1195 close(fd);
1196
1197 // check /tmp
1198 dir = "tmp";
1199 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1200 if (fd == -1)
1201 goto error1;
1202 if (fstat(fd, &s) == -1)
1203 errExit("fstat");
1204 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1205 goto error2;
1206 close(fd);
1207
1208 // check /etc
1209 dir = "etc";
1210 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1211 if (fd == -1)
1212 goto error1;
1213 if (fstat(fd, &s) == -1)
1214 errExit("fstat");
1215 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1216 goto error2;
1217 if (((S_IWGRP|S_IWOTH) & s.st_mode) != 0) {
1218 fprintf(stderr, "Error: only root user should be given write permission on chroot /etc\n");
1219 exit(1);
1220 } 1207 }
1221 close(fd);
1222 1208
1223 // there should be no checking on <chrootdir>/etc/resolv.conf 1209 // there should be no checking on <chrootdir>/etc/resolv.conf
1224 // the file is replaced with the real /etc/resolv.conf anyway 1210 // the file is replaced with the real /etc/resolv.conf anyway
@@ -1249,32 +1235,10 @@ void fs_check_chroot_dir(const char *rootdir) {
1249#endif 1235#endif
1250 1236
1251 // check x11 socket directory 1237 // check x11 socket directory
1252 if (getenv("FIREJAIL_X11")) { 1238 if (getenv("FIREJAIL_X11"))
1253 dir = "tmp/.X11-unix"; 1239 fs_check_chroot_subdir("tmp/.X11-unix", parentfd, 0);
1254 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1255 if (fd == -1)
1256 goto error1;
1257 if (fstat(fd, &s) == -1)
1258 errExit("fstat");
1259 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1260 goto error2;
1261 close(fd);
1262 }
1263 1240
1264 close(parentfd); 1241 close(parentfd);
1265 return;
1266
1267error1:
1268 if (errno == ENOENT)
1269 fprintf(stderr, "Error: cannot find /%s in chroot directory\n", dir);
1270 else {
1271 perror("open");
1272 fprintf(stderr, "Error: cannot open /%s in chroot directory\n", dir);
1273 }
1274 exit(1);
1275error2:
1276 fprintf(stderr, "Error: chroot /%s should be a directory owned by root\n", dir);
1277 exit(1);
1278} 1242}
1279 1243
1280// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf 1244// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf