diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/x11.c | 89 |
1 files changed, 89 insertions, 0 deletions
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. | ||
120 | static 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 | ||
115 | static int random_display_number(void) { | 203 | static 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 | ||