diff options
author | 2017-02-14 18:42:34 -0500 | |
---|---|---|
committer | 2017-02-14 18:42:34 -0500 | |
commit | 75a10497476ea1feb6275951e33eedcbe0110b8b (patch) | |
tree | 332f69c1646b06799d3a3069bf8ba7b69708730e /src | |
parent | compile cleanup (diff) | |
download | firejail-75a10497476ea1feb6275951e33eedcbe0110b8b.tar.gz firejail-75a10497476ea1feb6275951e33eedcbe0110b8b.tar.zst firejail-75a10497476ea1feb6275951e33eedcbe0110b8b.zip |
merge #1100 from zackw: rework DISPLAY environment parsing, rework masking X11 sockets in /tmp/.X11-unix directory
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/x11.c | 109 |
1 files changed, 93 insertions, 16 deletions
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index 2fedcc355..b551a2d2a 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <dirent.h> | 27 | #include <dirent.h> |
28 | #include <sys/mount.h> | 28 | #include <sys/mount.h> |
29 | #include <sys/wait.h> | 29 | #include <sys/wait.h> |
30 | #include <errno.h> | ||
31 | #include <limits.h> | ||
30 | int mask_x11_abstract_socket = 0; | 32 | int mask_x11_abstract_socket = 0; |
31 | 33 | ||
32 | #ifdef HAVE_X11 | 34 | #ifdef HAVE_X11 |
@@ -103,21 +105,44 @@ static int random_display_number(void) { | |||
103 | } | 105 | } |
104 | #endif | 106 | #endif |
105 | 107 | ||
106 | // return display number, -1 if not configured | 108 | |
109 | // Parse the DISPLAY environment variable and return a display number. | ||
110 | // Returns -1 if DISPLAY is not set, or is set to anything other than :ddd. | ||
107 | int x11_display(void) { | 111 | int x11_display(void) { |
108 | // extract display | 112 | const char *display_str = getenv("DISPLAY"); |
109 | char *d = getenv("DISPLAY"); | 113 | char *endp; |
110 | if (!d) | 114 | unsigned long display; |
111 | return - 1; | 115 | |
112 | 116 | if (!display_str) { | |
113 | int display; | 117 | if (arg_debug) |
114 | int rv = sscanf(d, ":%d", &display); | 118 | fputs("DISPLAY is not set\n", stderr); |
115 | if (rv != 1) | 119 | return -1; |
116 | return -1; | 120 | } |
117 | if (arg_debug) | 121 | |
118 | printf("DISPLAY %s, %d\n", d, display); | 122 | if (display_str[0] != ':' || display_str[1] < '0' || display_str[1] > '9') { |
119 | 123 | if (arg_debug) | |
120 | return display; | 124 | fprintf(stderr, "unsupported DISPLAY form '%s'\n", display_str); |
125 | return -1; | ||
126 | } | ||
127 | |||
128 | errno = 0; | ||
129 | display = strtoul(display_str+1, &endp, 10); | ||
130 | if (endp == display_str+1 || (*endp != '\0' && *endp != '.')) { // handling DISPLAY=:0 and also :0.0 | ||
131 | if (arg_debug) | ||
132 | fprintf(stderr, "unsupported DISPLAY form '%s'\n", display_str); | ||
133 | return -1; | ||
134 | } | ||
135 | if (errno || display > (unsigned long)INT_MAX) { | ||
136 | if (arg_debug) | ||
137 | fprintf(stderr, "display number %s is outside the valid range\n", | ||
138 | display_str+1); | ||
139 | return -1; | ||
140 | } | ||
141 | |||
142 | if (arg_debug) | ||
143 | fprintf(stderr, "DISPLAY=%s parsed as %lu\n", display_str, display); | ||
144 | |||
145 | return (int)display; | ||
121 | } | 146 | } |
122 | 147 | ||
123 | void fs_x11(void) { | 148 | void fs_x11(void) { |
@@ -129,10 +154,60 @@ void fs_x11(void) { | |||
129 | char *x11file; | 154 | char *x11file; |
130 | if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1) | 155 | if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1) |
131 | errExit("asprintf"); | 156 | errExit("asprintf"); |
132 | struct stat s; | 157 | struct stat x11stat; |
133 | if (stat(x11file, &s) == -1) | 158 | if (stat(x11file, &x11stat) == -1 || !S_ISSOCK(x11stat.st_mode)) { |
159 | free(x11file); | ||
134 | return; | 160 | return; |
161 | } | ||
135 | 162 | ||
163 | if (arg_debug || arg_debug_whitelists) | ||
164 | fprintf(stderr, "Masking all X11 sockets except %s\n", x11file); | ||
165 | |||
166 | // Move the real /tmp/.X11-unix to a scratch location | ||
167 | // so we can still access x11file after we mount a | ||
168 | // tmpfs over /tmp/.X11-unix. | ||
169 | int rv = mkdir(RUN_WHITELIST_X11_DIR, 0700); | ||
170 | if (rv == -1) | ||
171 | errExit("mkdir"); | ||
172 | if (set_perms(RUN_WHITELIST_X11_DIR, 0, 0, 0700)) | ||
173 | errExit("set_perms"); | ||
174 | |||
175 | if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0) | ||
176 | errExit("mount bind"); | ||
177 | |||
178 | // This directory must be mode 1777, or Xlib will barf. | ||
179 | if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", | ||
180 | MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME | MS_REC, | ||
181 | "mode=1777,uid=0,gid=0") < 0) | ||
182 | errExit("mounting tmpfs on /tmp/.X11-unix"); | ||
183 | fs_logger("tmpfs /tmp/.X11-unix"); | ||
184 | |||
185 | // create an empty file which will have the desired socket bind-mounted over it | ||
186 | int fd = open(x11file, O_RDWR|O_CREAT|O_EXCL, x11stat.st_mode & ~S_IFMT); | ||
187 | if (fd < 0) | ||
188 | errExit(x11file); | ||
189 | if (fchown(fd, x11stat.st_uid, x11stat.st_gid)) | ||
190 | errExit("fchown"); | ||
191 | close(fd); | ||
192 | |||
193 | // do the mount | ||
194 | char *wx11file; | ||
195 | if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1) | ||
196 | errExit("asprintf"); | ||
197 | if (mount(wx11file, x11file, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
198 | errExit("mount bind"); | ||
199 | fs_logger2("whitelist", x11file); | ||
200 | |||
201 | free(x11file); | ||
202 | free(wx11file); | ||
203 | |||
204 | // block access to RUN_WHITELIST_X11_DIR | ||
205 | if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, 0, MS_BIND, 0) < 0) | ||
206 | errExit("mount"); | ||
207 | fs_logger2("blacklist", RUN_WHITELIST_X11_DIR); | ||
208 | |||
209 | |||
210 | #if 0 | ||
136 | // keep a copy of real /tmp/.X11-unix directory in WHITELIST_TMP_DIR | 211 | // keep a copy of real /tmp/.X11-unix directory in WHITELIST_TMP_DIR |
137 | int rv = mkdir(RUN_WHITELIST_X11_DIR, 1777); | 212 | int rv = mkdir(RUN_WHITELIST_X11_DIR, 1777); |
138 | if (rv == -1) | 213 | if (rv == -1) |
@@ -177,6 +252,8 @@ void fs_x11(void) { | |||
177 | errExit("mount"); | 252 | errExit("mount"); |
178 | fs_logger2("blacklist", RUN_WHITELIST_X11_DIR); | 253 | fs_logger2("blacklist", RUN_WHITELIST_X11_DIR); |
179 | #endif | 254 | #endif |
255 | |||
256 | #endif | ||
180 | } | 257 | } |
181 | 258 | ||
182 | 259 | ||