summaryrefslogtreecommitdiffstats
path: root/src/firejail/fs_etc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/fs_etc.c')
-rw-r--r--src/firejail/fs_etc.c146
1 files changed, 42 insertions, 104 deletions
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index 7e18840fd..80329d5ba 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -21,20 +21,13 @@
21#include <sys/mount.h> 21#include <sys/mount.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <sys/types.h> 23#include <sys/types.h>
24#include <sys/wait.h>
25#include <unistd.h> 24#include <unistd.h>
26 25
27// return 0 if file not found, 1 if found 26// return 0 if file not found, 1 if found
28static int check_dir_or_file(const char *name) { 27static int check_dir_or_file(const char *fname) {
29 assert(name); 28 assert(fname);
30 invalid_filename(name);
31 29
32 struct stat s; 30 struct stat s;
33 char *fname;
34 if (asprintf(&fname, "/etc/%s", name) == -1)
35 errExit("asprintf");
36 if (arg_debug)
37 printf("Checking %s\n", fname);
38 if (stat(fname, &s) == -1) { 31 if (stat(fname, &s) == -1) {
39 if (arg_debug) 32 if (arg_debug)
40 printf("Warning: file %s not found.\n", fname); 33 printf("Warning: file %s not found.\n", fname);
@@ -46,78 +39,46 @@ static int check_dir_or_file(const char *name) {
46 goto errexit; 39 goto errexit;
47 40
48 // dir or regular file 41 // dir or regular file
49 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) { 42 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || !is_link(fname))
50 free(fname); 43 return 1; // normal exit
51 return 1;
52 }
53
54 if (!is_link(fname)) {
55 free(fname);
56 return 1;
57 }
58
59 44
60errexit: 45errexit:
61 fprintf(stderr, "Error: invalid file type, %s.\n", fname); 46 fprintf(stderr, "Error: invalid file type, %s.\n", fname);
62 exit(1); 47 exit(1);
63} 48}
64 49
65void fs_check_etc_list(void) { 50static void duplicate(char *fname) {
66 EUID_ASSERT(); 51 if (*fname == '~' || *fname == '/' || strstr(fname, "..")) {
67 if (strstr(cfg.etc_private_keep, "..")) { 52 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname);
68 fprintf(stderr, "Error: invalid private etc list\n");
69 exit(1); 53 exit(1);
70 } 54 }
71 55 invalid_filename(fname);
72 char *dlist = strdup(cfg.etc_private_keep); 56
73 if (!dlist) 57 char *src;
74 errExit("strdup"); 58 if (asprintf(&src, "/etc/%s", fname) == -1)
75 59 errExit("asprintf");
76 // build a new list only with the files found 60 if (check_dir_or_file(src) == 0) {
77 char *newlist = malloc(strlen(cfg.etc_private_keep) + 1); 61 if (!arg_quiet)
78 if (!newlist) 62 fprintf(stderr, "Warning: skipping %s for private bin\n", fname);
79 errExit("malloc"); 63 free(src);
80 *newlist = '\0'; 64 return;
81
82 char *ptr = strtok(dlist, ",");
83 if (check_dir_or_file(ptr))
84 strcat(newlist, ptr);
85 while ((ptr = strtok(NULL, ",")) != NULL) {
86 if (check_dir_or_file(ptr)) {
87 strcat(newlist, ",");
88 strcat(newlist, ptr);
89 }
90 } 65 }
91 cfg.etc_private_keep = newlist;
92
93 free(dlist);
94}
95 66
96static void duplicate(char *fname) { 67 struct stat s;
97 // copy the file 68 if (stat(src, &s) == 0 && S_ISDIR(s.st_mode)) {
98 if (arg_debug) 69 // create the directory in RUN_ETC_DIR
99 printf("running: %s -a --parents /etc/%s %s\n", RUN_CP_COMMAND, fname, RUN_MNT_DIR); 70 char *dirname;
100 71 if (asprintf(&dirname, "%s/%s", RUN_ETC_DIR, fname) == -1)
101 pid_t child = fork();
102 if (child < 0)
103 errExit("fork");
104 if (child == 0) {
105 char *f;
106 if (asprintf(&f, "/etc/%s", fname) == -1)
107 errExit("asprintf"); 72 errExit("asprintf");
108 clearenv(); 73 create_empty_dir_as_root(dirname, s.st_mode);
109 execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", "--parents", f, RUN_MNT_DIR, NULL); 74 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, dirname);
110 perror("execlp"); 75 free(dirname);
111 _exit(1);
112 } 76 }
113 // wait for the child to finish 77 else
114 waitpid(child, NULL, 0); 78 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, RUN_ETC_DIR);
115 79
116 char *name; 80 fs_logger2("clone", src);
117 if (asprintf(&name, "/etc/%s", fname) == -1) 81 free(src);
118 errExit("asprintf");
119 fs_logger2("clone", name);
120 free(name);
121} 82}
122 83
123 84
@@ -125,12 +86,6 @@ void fs_private_etc_list(void) {
125 char *private_list = cfg.etc_private_keep; 86 char *private_list = cfg.etc_private_keep;
126 assert(private_list); 87 assert(private_list);
127 88
128 struct stat s;
129 if (stat("/etc", &s) == -1) {
130 fprintf(stderr, "Error: cannot find user /etc directory\n");
131 exit(1);
132 }
133
134 // create /run/firejail/mnt/etc directory 89 // create /run/firejail/mnt/etc directory
135 mkdir_attr(RUN_ETC_DIR, 0755, 0, 0); 90 mkdir_attr(RUN_ETC_DIR, 0755, 0, 0);
136 fs_logger("tmpfs /etc"); 91 fs_logger("tmpfs /etc");
@@ -141,39 +96,22 @@ void fs_private_etc_list(void) {
141 // copy the list of files in the new etc directory 96 // copy the list of files in the new etc directory
142 // using a new child process with root privileges 97 // using a new child process with root privileges
143 if (*private_list != '\0') { 98 if (*private_list != '\0') {
144 pid_t child = fork(); 99 if (arg_debug)
145 if (child < 0) 100 printf("Copying files in the new etc directory:\n");
146 errExit("fork"); 101
147 if (child == 0) { 102 // copy the list of files in the new home directory
148 if (arg_debug) 103 char *dlist = strdup(private_list);
149 printf("Copying files in the new etc directory:\n"); 104 if (!dlist)
105 errExit("strdup");
150 106
151 // elevate privileges - files in the new /etc directory belong to root 107
152 if (setreuid(0, 0) < 0) 108 char *ptr = strtok(dlist, ",");
153 errExit("setreuid"); 109 duplicate(ptr);
154 if (setregid(0, 0) < 0)
155 errExit("setregid");
156
157 // copy the list of files in the new home directory
158 char *dlist = strdup(private_list);
159 if (!dlist)
160 errExit("strdup");
161
162 110
163 char *ptr = strtok(dlist, ","); 111 while ((ptr = strtok(NULL, ",")) != NULL)
164 duplicate(ptr); 112 duplicate(ptr);
165 113 free(dlist);
166 while ((ptr = strtok(NULL, ",")) != NULL) 114 fs_logger_print();
167 duplicate(ptr);
168 free(dlist);
169 fs_logger_print();
170#ifdef HAVE_GCOV
171 __gcov_flush();
172#endif
173 _exit(0);
174 }
175 // wait for the child to finish
176 waitpid(child, NULL, 0);
177 } 115 }
178 116
179 if (arg_debug) 117 if (arg_debug)