Skip to content

Commit 695c3f3

Browse files
committed
find_file(): Check for symlinks to /dev/tcp/
This path should not exist, so subsequent accesses will fail. However, later changes will interpret these paths specially.
1 parent 4342589 commit 695c3f3

File tree

1 file changed

+51
-6
lines changed

1 file changed

+51
-6
lines changed

libqrexec/exec.c

+51-6
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,13 @@ static int qubes_connect(int s, const char *connect_path, const size_t total_pat
208208
Returns 0 on success, -1 if the file is definitely absent in all of the
209209
paths, and -2 on error (broken symlink, I/O error, path too long, out
210210
of memory, etc).
211-
On success, fills buffer and statbuf (unless statbuf is NULL).
211+
On success, fills buffer and statbuf (unless statbuf is NULL). buffer
212+
will contain the path to the file, while statbuf will contain metadata
213+
about the file as reported by stat(2).
214+
If statbuf is not NULL, buffer may be filled with string starting
215+
with "/dev/tcp/", which corresponds to the target of the symbolic link.
216+
In this case, statbuf will contain the metadata for the symlink itself,
217+
not its (hopefully nonexistent) target.
212218
*/
213219
static int find_file(
214220
const char *path_list,
@@ -220,13 +226,22 @@ static int find_file(
220226
struct stat dummy_buf;
221227
const char *path_start = path_list;
222228
size_t name_length = strlen(name);
229+
char *buf = NULL;
223230
int res;
231+
int rc;
224232

225233
if (name_length > NAME_MAX)
226234
return -1; /* cannot possibly exist */
227235

228-
if (!statbuf)
236+
if (!statbuf) {
229237
statbuf = &dummy_buf;
238+
} else {
239+
buf = malloc(buffer_size);
240+
if (buf == NULL) {
241+
LOG(ERROR, "Cannot allocate %zu bytes", buffer_size);
242+
return -2;
243+
}
244+
}
230245

231246
while (*path_start) {
232247
/* Find next path (up to ':') */
@@ -235,7 +250,8 @@ static int find_file(
235250

236251
if (path_length + name_length + 1 >= buffer_size) {
237252
LOG(ERROR, "find_qrexec_service_file: buffer too small for file path");
238-
return -2;
253+
rc = -2;
254+
goto done;
239255
}
240256

241257
memcpy(buffer, path_start, path_length);
@@ -244,24 +260,53 @@ static int find_file(
244260
//LOG(INFO, "stat(%s)", buffer);
245261
res = lstat(buffer, statbuf);
246262
if (res == 0 && S_ISLNK(statbuf->st_mode)) {
263+
if (buf != NULL) {
264+
ssize_t res = readlink(buffer, buf, buffer_size);
265+
if (res < 0) {
266+
/* readlink(2) failed */
267+
LOG(ERROR, "readlink(2) failed: %m");
268+
rc = -2;
269+
goto done;
270+
}
271+
size_t target_len = (size_t)res;
272+
if ((target_len >= sizeof("/dev/tcp") && memcmp(buf, "/dev/tcp/", sizeof("/dev/tcp")) == 0) ||
273+
(target_len == sizeof("/dev/tcp") - 1 && memcmp(buf, "/dev/tcp/", sizeof("/dev/tcp") - 1) == 0))
274+
{
275+
if (target_len >= buffer_size) {
276+
/* buffer too small */
277+
rc = -2;
278+
} else {
279+
memcpy(buffer, buf, target_len);
280+
buffer[target_len] = '\0';
281+
rc = 0;
282+
}
283+
goto done;
284+
}
285+
}
247286
/* check if the symlink is valid */
248287
res = stat(buffer, statbuf);
249288
assert(res == -1 || !S_ISLNK(statbuf->st_mode));
250289
}
251290
if (res == 0) {
252-
return 0;
291+
rc = 0;
292+
goto done;
253293
} else {
254294
assert(res == -1);
255295
if (errno != ENOENT) {
256-
return -2;
296+
LOG(ERROR, "stat/lstat(%s): %m", buffer);
297+
rc = -2;
298+
goto done;
257299
}
258300
}
259301

260302
path_start = path_end;
261303
while (*path_start == ':')
262304
path_start++;
263305
}
264-
return -1;
306+
rc = -1;
307+
done:
308+
free(buf);
309+
return rc;
265310
}
266311

267312
static int load_service_config_raw(struct qrexec_parsed_command *cmd,

0 commit comments

Comments
 (0)