aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/mountinfo.c
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-10-25 22:07:19 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2018-10-25 22:07:19 +0200
commita7164cb38171c0291fac7f3a0767fe8f1c69b02d (patch)
tree88335663b94f807ebe7efcdb70eaeae80701601e /src/firejail/mountinfo.c
parentmerges (diff)
downloadfirejail-a7164cb38171c0291fac7f3a0767fe8f1c69b02d.tar.gz
firejail-a7164cb38171c0291fac7f3a0767fe8f1c69b02d.tar.zst
firejail-a7164cb38171c0291fac7f3a0767fe8f1c69b02d.zip
experimental: remounts child mount points as well (read-only, read-write, noexec)
Diffstat (limited to 'src/firejail/mountinfo.c')
-rw-r--r--src/firejail/mountinfo.c205
1 files changed, 169 insertions, 36 deletions
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c
index 4a7816901..b7760ba67 100644
--- a/src/firejail/mountinfo.c
+++ b/src/firejail/mountinfo.c
@@ -19,16 +19,19 @@
19*/ 19*/
20 20
21#include "firejail.h" 21#include "firejail.h"
22#include <fcntl.h>
22 23
23#define MAX_BUF 4096 24#define MAX_BUF 4096
25
24static char mbuf[MAX_BUF]; 26static char mbuf[MAX_BUF];
25static MountData mdata; 27static MountData mdata;
26 28
29
27// Convert octal escape sequence to decimal value 30// Convert octal escape sequence to decimal value
28static int read_oct(const char *path) { 31static int read_oct(const char *path) {
29 int decimal = 0; 32 int decimal = 0;
30 int digit, i; 33 int digit, i;
31 // there are always three octal digits 34 // there are always exactly three octal digits
32 for (i = 1; i < 4; i++) { 35 for (i = 1; i < 4; i++) {
33 digit = *(path + i); 36 digit = *(path + i);
34 if (digit < '0' || digit > '7') { 37 if (digit < '0' || digit > '7') {
@@ -61,43 +64,38 @@ static void unmangle_path(char *path) {
61 } 64 }
62} 65}
63 66
64// Get info regarding the last kernel mount operation. 67// Parse a line from /proc/self/mountinfo,
65// The return value points to a static area, and will be overwritten by subsequent calls. 68// the function does an exit(1) if anything goes wrong.
66// The function does an exit(1) if anything goes wrong. 69static void parse_line(char *line, MountData *output) {
67MountData *get_last_mount(void) { 70 assert(line && *line);
68 // open /proc/self/mountinfo 71 memset(output, 0, sizeof(*output));
69 FILE *fp = fopen("/proc/self/mountinfo", "r"); 72 // extract filesystem name, directory and filesystem types
70 if (!fp)
71 goto errexit;
72
73 mbuf[0] = '\0';
74 while (fgets(mbuf, MAX_BUF, fp));
75 fclose(fp);
76 if (arg_debug)
77 printf("%s", mbuf);
78
79 // extract filesystem name, directory and filesystem type
80 // examples: 73 // examples:
81 // 587 543 8:1 /tmp /etc rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=ordered 74 // 587 543 8:1 /tmp /etc rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=ordered
82 // mdata.fsname: /tmp 75 // output.mountid: 587
83 // mdata.dir: /etc 76 // output.fsname: /tmp
84 // mdata.fstype: ext4 77 // output.dir: /etc
78 // output.fstype: ext4
85 // 585 564 0:76 / /home/netblue/.cache rw,nosuid,nodev - tmpfs tmpfs rw 79 // 585 564 0:76 / /home/netblue/.cache rw,nosuid,nodev - tmpfs tmpfs rw
86 // mdata.fsname: / 80 // output.mountid: 585
87 // mdata.dir: /home/netblue/.cache 81 // output.fsname: /
88 // mdata.fstype: tmpfs 82 // output.dir: /home/netblue/.cache
89 memset(&mdata, 0, sizeof(mdata)); 83 // output.fstype: tmpfs
90 char *ptr = strtok(mbuf, " "); 84
85 char *ptr = strtok(line, " ");
91 if (!ptr) 86 if (!ptr)
92 goto errexit; 87 goto errexit;
93 88 if (ptr != line)
89 goto errexit;
90 output->mountid = atoi(ptr);
94 int cnt = 1; 91 int cnt = 1;
92
95 while ((ptr = strtok(NULL, " ")) != NULL) { 93 while ((ptr = strtok(NULL, " ")) != NULL) {
96 cnt++; 94 cnt++;
97 if (cnt == 4) 95 if (cnt == 4)
98 mdata.fsname = ptr; 96 output->fsname = ptr;
99 else if (cnt == 5) { 97 else if (cnt == 5) {
100 mdata.dir = ptr; 98 output->dir = ptr;
101 break; 99 break;
102 } 100 }
103 } 101 }
@@ -109,21 +107,156 @@ MountData *get_last_mount(void) {
109 ptr = strtok(NULL, " "); 107 ptr = strtok(NULL, " ");
110 if (!ptr) 108 if (!ptr)
111 goto errexit; 109 goto errexit;
112 mdata.fstype = ptr++; 110 output->fstype = ptr++;
113 111
114 if (mdata.fsname == NULL || 112
115 mdata.dir == NULL || 113 if (output->mountid == 0 ||
116 mdata.fstype == NULL) 114 output->fsname == NULL ||
115 output->dir == NULL ||
116 output->fstype == NULL)
117 goto errexit; 117 goto errexit;
118 118
119 unmangle_path(mdata.fsname); 119 // restore empty spaces
120 unmangle_path(mdata.dir); 120 unmangle_path(output->fsname);
121 unmangle_path(output->dir);
122
123 return;
124
125errexit:
126 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n");
127 exit(1);
128}
129
130// The return value points to a static area, and will be overwritten by subsequent calls.
131MountData *get_last_mount(void) {
132 // open /proc/self/mountinfo
133 FILE *fp = fopen("/proc/self/mountinfo", "re");
134 if (!fp) {
135 perror("fopen");
136 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n");
137 exit(1);
138 }
139
140 mbuf[0] = '\0';
141 // go to the last line
142 while (fgets(mbuf, MAX_BUF, fp));
143 fclose(fp);
144 if (arg_debug)
145 printf("%s", mbuf);
146
147 parse_line(mbuf, &mdata);
121 148
122 if (arg_debug) 149 if (arg_debug)
123 printf("fsname=%s dir=%s fstype=%s\n", mdata.fsname, mdata.dir, mdata.fstype); 150 printf("mountid=%d fsname=%s dir=%s fstype=%s\n", mdata.mountid, mdata.fsname, mdata.dir, mdata.fstype);
124 return &mdata; 151 return &mdata;
152}
153
154// Extract the mount id from /proc/self/fdinfo and return it.
155int get_mount_id(const char *path) {
156 EUID_ASSERT();
157 int fd = open(path, O_PATH|O_CLOEXEC);
158 if (fd == -1)
159 return 0;
160
161 char *fdinfo;
162 if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1)
163 errExit("asprintf");
164 EUID_ROOT();
165 FILE *fp = fopen(fdinfo, "re");
166 EUID_USER();
167 if (!fp)
168 goto errexit;
169 // go to the last line
170 char buf[MAX_BUF];
171 while (fgets(buf, MAX_BUF, fp));
172 fclose(fp);
173 close(fd);
174 // go to the mount id
175 if (strncmp(buf, "mnt_id:", 7) != 0)
176 goto errexit;
177 char *ptr = buf + 7;
178 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
179 ptr++;
180 }
181 if (*ptr == '\0')
182 goto errexit;
183 free(fdinfo);
184
185 return atoi(ptr);
125 186
126errexit: 187errexit:
127 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); 188 fprintf(stderr, "Error: cannot read file in /proc/self/fdinfo\n");
128 exit(1); 189 exit(1);
129} 190}
191
192// Return array with all paths that might need a remount.
193char **get_all_mounts(const int mountid, const char *path) {
194 // open /proc/self/mountinfo
195 FILE *fp = fopen("/proc/self/mountinfo", "re");
196 if (!fp) {
197 perror("fopen");
198 fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n");
199 exit(1);
200 }
201
202 size_t size = 32;
203 size_t cnt = 0;
204 char **rv = malloc(size * sizeof(*rv));
205 if (!rv)
206 errExit("malloc");
207
208 // read /proc/self/mountinfo
209 size_t pathlen = strlen(path);
210 int found = 0;
211 while (fgets(mbuf, MAX_BUF, fp)) {
212 // find mount point with mount id
213 if (!found) {
214 parse_line(mbuf, &mdata);
215 if (mdata.mountid == mountid) {
216 // don't remount blacklisted paths,
217 // give up if mount id has been reassigned
218 if (strstr(mdata.fsname, "firejail.ro.dir") ||
219 strstr(mdata.fsname, "firejail.ro.file") ||
220 strncmp(mdata.dir, path, strlen(mdata.dir)))
221 break;
222
223 *rv = strdup(path);
224 if (*rv == NULL)
225 errExit("strdup");
226 cnt++;
227 found = 1;
228 continue;
229 }
230 else
231 continue;
232 }
233 // from here on add all mount points below path
234 parse_line(mbuf, &mdata);
235 if (strncmp(mdata.dir, path, pathlen) == 0 &&
236 mdata.dir[pathlen] == '/' &&
237 strstr(mdata.fsname, "firejail.ro.dir") == NULL &&
238 strstr(mdata.fsname, "firejail.ro.file") == NULL) {
239
240 if (cnt >= size) {
241 size *= 2;
242 rv = realloc(rv, size * sizeof(*rv));
243 if (!rv)
244 errExit("realloc");
245 }
246 rv[cnt] = strdup(mdata.dir);
247 if (!rv[cnt])
248 errExit("strdup");
249 cnt++;
250 }
251 }
252 if (cnt == size) {
253 size++;
254 rv = realloc(rv, size * sizeof(*rv));
255 if (!rv)
256 errExit("realloc");
257 }
258 rv[cnt] = NULL; // end of the array
259
260 fclose(fp);
261 return rv;
262}