aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2017-02-15 09:10:07 -0500
committerLibravatar netblue30 <netblue30@yahoo.com>2017-02-15 09:10:07 -0500
commitbe71ace09007086b0444cf00e51458df4faf2e6f (patch)
tree8e3e2c23c4fe4e029c2e41adc21d2a4c5a24ab64
parentmerge #1100 from zackw: rework abstract X11 socket detection (diff)
downloadfirejail-be71ace09007086b0444cf00e51458df4faf2e6f.tar.gz
firejail-be71ace09007086b0444cf00e51458df4faf2e6f.tar.zst
firejail-be71ace09007086b0444cf00e51458df4faf2e6f.zip
merge #1100 from zackw: rework X11 display number assignment
-rw-r--r--README1
-rw-r--r--src/firejail/x11.c89
2 files changed, 90 insertions, 0 deletions
diff --git a/README b/README
index e729b4580..08617425f 100644
--- a/README
+++ b/README
@@ -108,6 +108,7 @@ Zack Weinberg (https://github.com/zackw)
108 - rework masking X11 sockets in /tmp/.X11-unix directory 108 - rework masking X11 sockets in /tmp/.X11-unix directory
109 - rework xpra and xephyr detection 109 - rework xpra and xephyr detection
110 - rework abstract X11 socket detection 110 - rework abstract X11 socket detection
111 - rework X11 display number assignment
111Igor Bukanov (https://github.com/ibukanov) 112Igor Bukanov (https://github.com/ibukanov)
112 - found/fiixed privilege escalation in --hosts-file option 113 - found/fiixed privilege escalation in --hosts-file option
113Cat (https://github.com/ecat3) 114Cat (https://github.com/ecat3)
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 328ecce18..a415929b1 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -20,6 +20,8 @@
20#include "firejail.h" 20#include "firejail.h"
21#include <sys/types.h> 21#include <sys/types.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <sys/socket.h>
24#include <sys/un.h>
23#include <fcntl.h> 25#include <fcntl.h>
24#include <unistd.h> 26#include <unistd.h>
25#include <signal.h> 27#include <signal.h>
@@ -112,6 +114,92 @@ static int x11_abstract_sockets_present(void) {
112 return found; 114 return found;
113} 115}
114 116
117// Choose a random, unallocated display number. This has an inherent
118// and unavoidable TOCTOU race, since we cannot create either the
119// socket or a lockfile ourselves.
120static int random_display_number(void) {
121 int display;
122 int found = 0;
123 int i;
124
125 struct sockaddr_un sa;
126 // The -1 here is because we need space to inject a
127 // leading nul byte.
128 int sun_pathmax = (int)(sizeof sa.sun_path - 1);
129 assert((size_t)sun_pathmax == sizeof sa.sun_path - 1);
130 int sun_pathlen;
131
132 int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
133 if (sockfd == -1)
134 errExit("socket");
135
136 for (i = 0; i < 100; i++) {
137 // We try display numbers in the range 21 through 1000.
138 // Normal X servers typically use displays in the 0-10 range;
139 // ssh's X11 forwarding uses 10-20, and login screens
140 // (e.g. gdm3) may use displays above 1000.
141 display = rand() % 979 + 21;
142
143 // The display number might be claimed by a server listening
144 // in _either_ the normal or the abstract namespace; they
145 // don't necessarily do both. The easiest way to check is
146 // to try to connect, both ways.
147 memset(&sa, 0, sizeof sa);
148 sa.sun_family = AF_UNIX;
149 sun_pathlen = snprintf(sa.sun_path, sun_pathmax,
150 "/tmp/.X11-unix/X%d", display);
151 if (sun_pathlen >= sun_pathmax) {
152 fprintf(stderr, "sun_path too small for display :%d"
153 " (only %d bytes usable)\n", display, sun_pathmax);
154 exit(1);
155 }
156
157 if (connect(sockfd, (struct sockaddr *)&sa,
158 offsetof(struct sockaddr_un, sun_path) + sun_pathlen + 1) == 0) {
159 close(sockfd);
160 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
161 if (sockfd == -1)
162 errExit("socket");
163 continue;
164 }
165 if (errno != ECONNREFUSED && errno != ENOENT)
166 errExit("connect");
167
168 // Name not claimed in the normal namespace; now try it
169 // in the abstract namespace. Note that abstract-namespace
170 // names are NOT nul-terminated; they extend to the length
171 // specified as the third argument to 'connect'.
172 memmove(sa.sun_path + 1, sa.sun_path, sun_pathlen + 1);
173 sa.sun_path[0] = '\0';
174 if (connect(sockfd, (struct sockaddr *)&sa,
175 offsetof(struct sockaddr_un, sun_path) + 1 + sun_pathlen) == 0) {
176 close(sockfd);
177 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
178 if (sockfd == -1)
179 errExit("socket");
180 continue;
181 }
182 if (errno != ECONNREFUSED && errno != ENOENT)
183 errExit("connect");
184
185 // This display number is unclaimed. Of course, it could
186 // be claimed before we get around to doing it...
187 found = 1;
188 break;
189 }
190 close(sockfd);
191
192 if (!found) {
193 fputs("Error: cannot find an unallocated X11 display number, "
194 "exiting...\n", stderr);
195 exit(1);
196 }
197 return display;
198}
199
200
201
202#if 0
115static int random_display_number(void) { 203static int random_display_number(void) {
116 int i; 204 int i;
117 int found = 1; 205 int found = 1;
@@ -137,6 +225,7 @@ static int random_display_number(void) {
137 return display; 225 return display;
138} 226}
139#endif 227#endif
228#endif
140 229
141 230
142 231