aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/fs_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/fs_dev.c')
-rw-r--r--src/firejail/fs_dev.c181
1 files changed, 117 insertions, 64 deletions
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index 2fd450391..d710e98f2 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -30,17 +30,75 @@
30#endif 30#endif
31#include <sys/types.h> 31#include <sys/types.h>
32 32
33typedef struct {
34 const char *dev_fname;
35 const char *run_fname;
36 int sound;
37 int hw3d;
38} DevEntry;
39
40static DevEntry dev[] = {
41 {"/dev/snd", RUN_DEV_DIR "/snd", 1, 0}, // sound device
42 {"/dev/dri", RUN_DEV_DIR "/dri", 0, 1}, // 3d device
43 {"/dev/nvidia0", RUN_DEV_DIR "/nvidia0", 0, 1},
44 {"/dev/nvidia1", RUN_DEV_DIR "/nvidia1", 0, 1},
45 {"/dev/nvidia2", RUN_DEV_DIR "/nvidia2", 0, 1},
46 {"/dev/nvidia3", RUN_DEV_DIR "/nvidia3", 0, 1},
47 {"/dev/nvidia4", RUN_DEV_DIR "/nvidia4", 0, 1},
48 {"/dev/nvidia5", RUN_DEV_DIR "/nvidia5", 0, 1},
49 {"/dev/nvidia6", RUN_DEV_DIR "/nvidia6", 0, 1},
50 {"/dev/nvidia7", RUN_DEV_DIR "/nvidia7", 0, 1},
51 {"/dev/nvidia8", RUN_DEV_DIR "/nvidia8", 0, 1},
52 {"/dev/nvidia9", RUN_DEV_DIR "/nvidia9", 0, 1},
53 {"/dev/nvidiactl", RUN_DEV_DIR "/nvidiactl", 0, 1},
54 {"/dev/nvidia-modset", RUN_DEV_DIR "/nvidia-modset", 0, 1},
55 {"/dev/nvidia-uvm", RUN_DEV_DIR "/nvidia-uvm", 0, 1},
56 {NULL, NULL, 0, 0}
57};
58
59static void deventry_mount(void) {
60 int i = 0;
61 while (dev[i].dev_fname != NULL) {
62 struct stat s;
63 if (stat(dev[i].run_fname, &s) == 0) {
64 int dir = is_dir(dev[i].run_fname);
65 if (arg_debug)
66 printf("mounting %s %s\n", dev[i].run_fname, (dir)? "directory": "file");
67 if (dir) {
68 mkdir_attr(dev[i].dev_fname, 0755, 0, 0);
69 }
70 else {
71 struct stat s;
72 if (stat(dev[i].run_fname, &s) == -1) {
73 if (arg_debug)
74 printf("Warning: cannot stat %s file\n", dev[i].run_fname);
75 i++;
76 continue;
77 }
78 FILE *fp = fopen(dev[i].dev_fname, "w");
79 if (fp) {
80 fprintf(fp, "\n");
81 SET_PERMS_STREAM(fp, s.st_uid, s.st_gid, s.st_mode);
82 fclose(fp);
83 }
84 }
85
86 if (mount(dev[i].run_fname, dev[i].dev_fname, NULL, MS_BIND|MS_REC, NULL) < 0)
87 errExit("mounting dev file");
88 fs_logger2("whitelist", dev[i].dev_fname);
89 }
90
91 i++;
92 }
93}
94
33static void create_char_dev(const char *path, mode_t mode, int major, int minor) { 95static void create_char_dev(const char *path, mode_t mode, int major, int minor) {
34 dev_t dev = makedev(major, minor); 96 dev_t dev = makedev(major, minor);
35 int rv = mknod(path, S_IFCHR | mode, dev); 97 if (mknod(path, S_IFCHR | mode, dev) == -1)
36 if (rv == -1)
37 goto errexit; 98 goto errexit;
38
39
40 if (chmod(path, mode) < 0) 99 if (chmod(path, mode) < 0)
41 goto errexit; 100 goto errexit;
42 if (chown(path, 0, 0) < 0) 101 ASSERT_PERMS(path, 0, 0, mode);
43 goto errexit;
44 102
45 return; 103 return;
46 104
@@ -62,35 +120,19 @@ errexit:
62} 120}
63 121
64void fs_private_dev(void){ 122void fs_private_dev(void){
65 int rv;
66 // install a new /dev directory 123 // install a new /dev directory
67 if (arg_debug) 124 if (arg_debug)
68 printf("Mounting tmpfs on /dev\n"); 125 printf("Mounting tmpfs on /dev\n");
69 126
70 int have_dri = 0;
71 struct stat s;
72 if (stat("/dev/dri", &s) == 0)
73 have_dri = 1;
74
75 // create DRI_DIR 127 // create DRI_DIR
76 fs_build_mnt_dir(); 128 // keep a copy of dev directory
77 if (have_dri) { 129 mkdir_attr(RUN_DEV_DIR, 0755, 0, 0);
78 /* coverity[toctou] */ 130 if (mount("/dev", RUN_DEV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
79 rv = mkdir(RUN_DRI_DIR, 0755); 131 errExit("mounting /dev/dri");
80 if (rv == -1) 132
81 errExit("mkdir"); 133 // create DEVLOG_FILE
82 if (chown(RUN_DRI_DIR, 0, 0) < 0)
83 errExit("chown");
84 if (chmod(RUN_DRI_DIR, 0755) < 0)
85 errExit("chmod");
86
87 // keep a copy of /dev/dri under DRI_DIR
88 if (mount("/dev/dri", RUN_DRI_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
89 errExit("mounting /dev/dri");
90 }
91
92 // restore /dev/log
93 int have_devlog = 0; 134 int have_devlog = 0;
135 struct stat s;
94 if (stat("/dev/log", &s) == 0) { 136 if (stat("/dev/log", &s) == 0) {
95 have_devlog = 1; 137 have_devlog = 1;
96 FILE *fp = fopen(RUN_DEVLOG_FILE, "w"); 138 FILE *fp = fopen(RUN_DEVLOG_FILE, "w");
@@ -108,6 +150,8 @@ void fs_private_dev(void){
108 if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) 150 if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
109 errExit("mounting /dev"); 151 errExit("mounting /dev");
110 fs_logger("tmpfs /dev"); 152 fs_logger("tmpfs /dev");
153
154 deventry_mount();
111 155
112 // bring back /dev/log 156 // bring back /dev/log
113 if (have_devlog) { 157 if (have_devlog) {
@@ -120,32 +164,14 @@ void fs_private_dev(void){
120 fs_logger("clone /dev/log"); 164 fs_logger("clone /dev/log");
121 } 165 }
122 } 166 }
167 if (mount(RUN_RO_DIR, RUN_DEV_DIR, "none", MS_BIND, "mode=400,gid=0") < 0)
168 errExit("disable /dev/snd");
123 169
124 // bring back the /dev/dri directory
125 if (have_dri) {
126 /* coverity[toctou] */
127 rv = mkdir("/dev/dri", 0755);
128 if (rv == -1)
129 errExit("mkdir");
130 if (chown("/dev/dri", 0, 0) < 0)
131 errExit("chown");
132 if (chmod("/dev/dri",0755) < 0)
133 errExit("chmod");
134 if (mount(RUN_DRI_DIR, "/dev/dri", NULL, MS_BIND|MS_REC, NULL) < 0)
135 errExit("mounting /dev/dri");
136 fs_logger("whitelist /dev/dri");
137 }
138 170
139 // create /dev/shm 171 // create /dev/shm
140 if (arg_debug) 172 if (arg_debug)
141 printf("Create /dev/shm directory\n"); 173 printf("Create /dev/shm directory\n");
142 rv = mkdir("/dev/shm", 01777); 174 mkdir_attr("/dev/shm", 01777, 0, 0);
143 if (rv == -1)
144 errExit("mkdir");
145 if (chown("/dev/shm", 0, 0) < 0)
146 errExit("chown");
147 if (chmod("/dev/shm", 01777) < 0)
148 errExit("chmod");
149 fs_logger("mkdir /dev/shm"); 175 fs_logger("mkdir /dev/shm");
150 176
151 // create devices 177 // create devices
@@ -167,13 +193,7 @@ void fs_private_dev(void){
167#endif 193#endif
168 194
169 // pseudo-terminal 195 // pseudo-terminal
170 rv = mkdir("/dev/pts", 0755); 196 mkdir_attr("/dev/pts", 0755, 0, 0);
171 if (rv == -1)
172 errExit("mkdir");
173 if (chown("/dev/pts", 0, 0) < 0)
174 errExit("chown");
175 if (chmod("/dev/pts", 0755) < 0)
176 errExit("chmod");
177 fs_logger("mkdir /dev/pts"); 197 fs_logger("mkdir /dev/pts");
178 create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2"); 198 create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2");
179 fs_logger("mknod /dev/pts/ptmx"); 199 fs_logger("mknod /dev/pts/ptmx");
@@ -186,7 +206,7 @@ void fs_private_dev(void){
186 206
187 207
188 // mount /dev/pts 208 // mount /dev/pts
189 gid_t ttygid = get_tty_gid(); 209 gid_t ttygid = get_group_id("tty");
190 char *data; 210 char *data;
191 if (asprintf(&data, "newinstance,gid=%d,mode=620,ptmxmode=0666", (int) ttygid) == -1) 211 if (asprintf(&data, "newinstance,gid=%d,mode=620,ptmxmode=0666", (int) ttygid) == -1)
192 errExit("asprintf"); 212 errExit("asprintf");
@@ -205,6 +225,7 @@ void fs_private_dev(void){
205} 225}
206 226
207 227
228#if 0
208void fs_dev_shm(void) { 229void fs_dev_shm(void) {
209 uid_t uid = getuid(); // set a new shm only if we started as root 230 uid_t uid = getuid(); // set a new shm only if we started as root
210 if (uid) 231 if (uid)
@@ -222,12 +243,7 @@ void fs_dev_shm(void) {
222 if (lnk) { 243 if (lnk) {
223 if (!is_dir(lnk)) { 244 if (!is_dir(lnk)) {
224 // create directory 245 // create directory
225 if (mkdir(lnk, 01777)) 246 mkdir_attr(lnk, 01777, 0, 0);
226 errExit("mkdir");
227 if (chown(lnk, 0, 0))
228 errExit("chown");
229 if (chmod(lnk, 01777))
230 errExit("chmod");
231 } 247 }
232 if (arg_debug) 248 if (arg_debug)
233 printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk); 249 printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk);
@@ -243,3 +259,40 @@ void fs_dev_shm(void) {
243 259
244 } 260 }
245} 261}
262#endif
263
264static void disable_file_or_dir(const char *fname) {
265 if (arg_debug)
266 printf("disable %s\n", fname);
267 struct stat s;
268 if (stat(fname, &s) != -1) {
269 if (is_dir(fname)) {
270 if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0)
271 errExit("disable directory");
272 }
273 else {
274 if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0)
275 errExit("disable file");
276 }
277 }
278 fs_logger2("blacklist", fname);
279
280}
281
282void fs_dev_disable_sound(void) {
283 int i = 0;
284 while (dev[i].dev_fname != NULL) {
285 if (dev[i].sound)
286 disable_file_or_dir(dev[i].dev_fname);
287 i++;
288 }
289}
290
291void fs_dev_disable_3d(void) {
292 int i = 0;
293 while (dev[i].dev_fname != NULL) {
294 if (dev[i].hw3d)
295 disable_file_or_dir(dev[i].dev_fname);
296 i++;
297 }
298}