aboutsummaryrefslogtreecommitdiffstats
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, 146 insertions, 0 deletions
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
new file mode 100644
index 000000000..57b0b4f3e
--- /dev/null
+++ b/src/firejail/fs_etc.c
@@ -0,0 +1,146 @@
1/*
2 * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com)
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "firejail.h"
21#include <sys/mount.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <unistd.h>
26
27static void check_dir_or_file(const char *name) {
28 assert(name);
29 struct stat s;
30 char *fname;
31 if (asprintf(&fname, "/etc/%s", name) == -1)
32 errExit("asprintf");
33 if (arg_debug)
34 printf("Checking %s\n", fname);
35 if (stat(fname, &s) == -1) {
36 fprintf(stderr, "Error: file %s not found.\n", fname);
37 exit(1);
38 }
39
40 // dir or regular file
41 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) {
42 free(fname);
43 return;
44 }
45
46 if (!is_link(fname)) {
47 free(fname);
48 return;
49 }
50
51 fprintf(stderr, "Error: invalid file type, %s.\n", fname);
52 exit(1);
53}
54
55void fs_check_etc_list(void) {
56 if (strstr(cfg.etc_private_keep, "..")) {
57 fprintf(stderr, "Error: invalid private etc list\n");
58 exit(1);
59 }
60
61 char *dlist = strdup(cfg.etc_private_keep);
62 if (!dlist)
63 errExit("strdup");
64
65 char *ptr = strtok(dlist, ",");
66 check_dir_or_file(ptr);
67 while ((ptr = strtok(NULL, ",")) != NULL)
68 check_dir_or_file(ptr);
69
70 free(dlist);
71}
72
73static void duplicate(char *fname) {
74 char *cmd;
75
76 // copy the file
77 if (asprintf(&cmd, "cp -a --parents /etc/%s %s", fname, MNT_DIR) == -1)
78 errExit("asprintf");
79 if (arg_debug)
80 printf("%s\n", cmd);
81 if (system(cmd))
82 errExit("system cp -a --parents");
83 free(cmd);
84}
85
86
87void fs_private_etc_list(void) {
88 char *private_list = cfg.etc_private_keep;
89 assert(private_list);
90
91 uid_t u = getuid();
92 gid_t g = getgid();
93 struct stat s;
94 if (stat("/etc", &s) == -1) {
95 fprintf(stderr, "Error: cannot find user /etc directory\n");
96 exit(1);
97 }
98
99 // create /tmp/firejail/mnt/etc directory
100 fs_build_mnt_dir();
101 int rv = mkdir(ETC_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
102 if (rv == -1)
103 errExit("mkdir");
104 if (chown(ETC_DIR, 0, 0) < 0)
105 errExit("chown");
106 if (chmod(ETC_DIR, 0755) < 0)
107 errExit("chmod");
108
109 // copy the list of files in the new etc directory
110 // using a new child process without root privileges
111 pid_t child = fork();
112 if (child < 0)
113 errExit("fork");
114 if (child == 0) {
115 if (arg_debug)
116 printf("Copying files in the new home:\n");
117
118 // elevate privileges - files in the new /etc directory belong to root
119 if (setreuid(0, 0) < 0)
120 errExit("setreuid");
121 if (setregid(0, 0) < 0)
122 errExit("setregid");
123
124 // copy the list of files in the new home directory
125 char *dlist = strdup(private_list);
126 if (!dlist)
127 errExit("strdup");
128
129 char *ptr = strtok(dlist, ",");
130 duplicate(ptr);
131
132 while ((ptr = strtok(NULL, ",")) != NULL)
133 duplicate(ptr);
134 free(dlist);
135 exit(0);
136 }
137 // wait for the child to finish
138 waitpid(child, NULL, 0);
139
140 if (arg_debug)
141 printf("Mount-bind %s on top of /etc\n", ETC_DIR);
142 if (mount(ETC_DIR, "/etc", NULL, MS_BIND|MS_REC, NULL) < 0)
143 errExit("mount bind");
144
145}
146