diff options
Diffstat (limited to 'src/firejail/util.c')
-rw-r--r-- | src/firejail/util.c | 138 |
1 files changed, 103 insertions, 35 deletions
diff --git a/src/firejail/util.c b/src/firejail/util.c index dc9fe2449..44f1cbd02 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -394,11 +394,11 @@ void touch_file_as_user(const char *fname, mode_t mode) { | |||
394 | // drop privileges | 394 | // drop privileges |
395 | drop_privs(0); | 395 | drop_privs(0); |
396 | 396 | ||
397 | FILE *fp = fopen(fname, "wx"); | 397 | int fd = open(fname, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR); |
398 | if (fp) { | 398 | if (fd > -1) { |
399 | fprintf(fp, "\n"); | 399 | int err = fchmod(fd, mode); |
400 | SET_PERMS_STREAM(fp, -1, -1, mode); | 400 | (void) err; |
401 | fclose(fp); | 401 | close(fd); |
402 | } | 402 | } |
403 | else | 403 | else |
404 | fwarning("cannot create %s\n", fname); | 404 | fwarning("cannot create %s\n", fname); |
@@ -899,27 +899,29 @@ int remove_overlay_directory(void) { | |||
899 | errExit("asprintf"); | 899 | errExit("asprintf"); |
900 | 900 | ||
901 | if (lstat(path, &s) == 0) { | 901 | if (lstat(path, &s) == 0) { |
902 | // deal with obvious problems such as symlinks and root ownership | ||
903 | if (!S_ISDIR(s.st_mode)) { | ||
904 | if (S_ISLNK(s.st_mode)) | ||
905 | fprintf(stderr, "Error: %s is a symbolic link\n", path); | ||
906 | else | ||
907 | fprintf(stderr, "Error: %s is not a directory\n", path); | ||
908 | exit(1); | ||
909 | } | ||
910 | if (s.st_uid != getuid()) { | ||
911 | fprintf(stderr, "Error: %s is not owned by the current user\n", path); | ||
912 | exit(1); | ||
913 | } | ||
914 | |||
915 | pid_t child = fork(); | 902 | pid_t child = fork(); |
916 | if (child < 0) | 903 | if (child < 0) |
917 | errExit("fork"); | 904 | errExit("fork"); |
918 | if (child == 0) { | 905 | if (child == 0) { |
919 | // open ~/.firejail, fails if there is any symlink | 906 | // open ~/.firejail |
920 | int fd = safer_openat(-1, path, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 907 | int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); |
921 | if (fd == -1) | 908 | if (fd == -1) { |
922 | errExit("safer_openat"); | 909 | fprintf(stderr, "Error: cannot open %s\n", path); |
910 | _exit(1); | ||
911 | } | ||
912 | if (fstat(fd, &s) == -1) | ||
913 | errExit("fstat"); | ||
914 | if (!S_ISDIR(s.st_mode)) { | ||
915 | if (S_ISLNK(s.st_mode)) | ||
916 | fprintf(stderr, "Error: %s is a symbolic link\n", path); | ||
917 | else | ||
918 | fprintf(stderr, "Error: %s is not a directory\n", path); | ||
919 | _exit(1); | ||
920 | } | ||
921 | if (s.st_uid != getuid()) { | ||
922 | fprintf(stderr, "Error: %s is not owned by the current user\n", path); | ||
923 | _exit(1); | ||
924 | } | ||
923 | // chdir to ~/.firejail | 925 | // chdir to ~/.firejail |
924 | if (fchdir(fd) == -1) | 926 | if (fchdir(fd) == -1) |
925 | errExit("fchdir"); | 927 | errExit("fchdir"); |
@@ -988,8 +990,8 @@ int create_empty_dir_as_user(const char *dir, mode_t mode) { | |||
988 | drop_privs(0); | 990 | drop_privs(0); |
989 | 991 | ||
990 | if (mkdir(dir, mode) == 0) { | 992 | if (mkdir(dir, mode) == 0) { |
991 | if (chmod(dir, mode) == -1) | 993 | int err = chmod(dir, mode); |
992 | {;} // do nothing | 994 | (void) err; |
993 | } | 995 | } |
994 | else if (arg_debug) | 996 | else if (arg_debug) |
995 | printf("Directory %s not created: %s\n", dir, strerror(errno)); | 997 | printf("Directory %s not created: %s\n", dir, strerror(errno)); |
@@ -1110,20 +1112,32 @@ unsigned extract_timeout(const char *str) { | |||
1110 | } | 1112 | } |
1111 | 1113 | ||
1112 | void disable_file_or_dir(const char *fname) { | 1114 | void disable_file_or_dir(const char *fname) { |
1115 | assert(fname); | ||
1116 | |||
1117 | int fd = open(fname, O_PATH|O_CLOEXEC); | ||
1118 | if (fd < 0) | ||
1119 | return; | ||
1120 | |||
1113 | struct stat s; | 1121 | struct stat s; |
1114 | if (stat(fname, &s) != -1) { | 1122 | if (fstat(fd, &s) < 0) { // FUSE |
1115 | if (arg_debug) | 1123 | if (errno != EACCES) |
1116 | printf("blacklist %s\n", fname); | 1124 | errExit("fstat"); |
1117 | if (is_dir(fname)) { | 1125 | close(fd); |
1118 | if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | 1126 | return; |
1127 | } | ||
1128 | |||
1129 | if (arg_debug) | ||
1130 | printf("blacklist %s\n", fname); | ||
1131 | if (S_ISDIR(s.st_mode)) { | ||
1132 | if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0) | ||
1119 | errExit("disable directory"); | 1133 | errExit("disable directory"); |
1120 | } | ||
1121 | else { | ||
1122 | if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | ||
1123 | errExit("disable file"); | ||
1124 | } | ||
1125 | fs_logger2("blacklist", fname); | ||
1126 | } | 1134 | } |
1135 | else { | ||
1136 | if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0) | ||
1137 | errExit("disable file"); | ||
1138 | } | ||
1139 | close(fd); | ||
1140 | fs_logger2("blacklist", fname); | ||
1127 | } | 1141 | } |
1128 | 1142 | ||
1129 | void disable_file_path(const char *path, const char *file) { | 1143 | void disable_file_path(const char *path, const char *file) { |
@@ -1210,6 +1224,60 @@ int safer_openat(int dirfd, const char *path, int flags) { | |||
1210 | return fd; | 1224 | return fd; |
1211 | } | 1225 | } |
1212 | 1226 | ||
1227 | int remount_by_fd(int dst, unsigned long mountflags) { | ||
1228 | char *proc; | ||
1229 | if (asprintf(&proc, "/proc/self/fd/%d", dst) < 0) | ||
1230 | errExit("asprintf"); | ||
1231 | |||
1232 | int rv = mount(NULL, proc, NULL, mountflags|MS_BIND|MS_REMOUNT, NULL); | ||
1233 | if (rv < 0 && arg_debug) | ||
1234 | printf("Failed mount: %s\n", strerror(errno)); | ||
1235 | |||
1236 | free(proc); | ||
1237 | return rv; | ||
1238 | } | ||
1239 | |||
1240 | int bind_mount_by_fd(int src, int dst) { | ||
1241 | char *proc_src, *proc_dst; | ||
1242 | if (asprintf(&proc_src, "/proc/self/fd/%d", src) < 0 || | ||
1243 | asprintf(&proc_dst, "/proc/self/fd/%d", dst) < 0) | ||
1244 | errExit("asprintf"); | ||
1245 | |||
1246 | int rv = mount(proc_src, proc_dst, NULL, MS_BIND|MS_REC, NULL); | ||
1247 | if (rv < 0 && arg_debug) | ||
1248 | printf("Failed mount: %s\n", strerror(errno)); | ||
1249 | |||
1250 | free(proc_src); | ||
1251 | free(proc_dst); | ||
1252 | return rv; | ||
1253 | } | ||
1254 | |||
1255 | int bind_mount_fd_to_path(int src, const char *destname) { | ||
1256 | char *proc; | ||
1257 | if (asprintf(&proc, "/proc/self/fd/%d", src) < 0) | ||
1258 | errExit("asprintf"); | ||
1259 | |||
1260 | int rv = mount(proc, destname, NULL, MS_BIND|MS_REC, NULL); | ||
1261 | if (rv < 0 && arg_debug) | ||
1262 | printf("Failed mount: %s\n", strerror(errno)); | ||
1263 | |||
1264 | free(proc); | ||
1265 | return rv; | ||
1266 | } | ||
1267 | |||
1268 | int bind_mount_path_to_fd(const char *srcname, int dst) { | ||
1269 | char *proc; | ||
1270 | if (asprintf(&proc, "/proc/self/fd/%d", dst) < 0) | ||
1271 | errExit("asprintf"); | ||
1272 | |||
1273 | int rv = mount(srcname, proc, NULL, MS_BIND|MS_REC, NULL); | ||
1274 | if (rv < 0 && arg_debug) | ||
1275 | printf("Failed mount: %s\n", strerror(errno)); | ||
1276 | |||
1277 | free(proc); | ||
1278 | return rv; | ||
1279 | } | ||
1280 | |||
1213 | int has_handler(pid_t pid, int signal) { | 1281 | int has_handler(pid_t pid, int signal) { |
1214 | if (signal > 0 && signal <= SIGRTMAX) { | 1282 | if (signal > 0 && signal <= SIGRTMAX) { |
1215 | char *fname; | 1283 | char *fname; |