aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/util.c')
-rw-r--r--src/firejail/util.c138
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
1112void disable_file_or_dir(const char *fname) { 1114void 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
1129void disable_file_path(const char *path, const char *file) { 1143void 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
1227int 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
1240int 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
1255int 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
1268int 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
1213int has_handler(pid_t pid, int signal) { 1281int 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;