Skip to content

Commit d5d7184

Browse files
committed
find_file(): Check for broken symlinks and I/O errors
Previously these were ignored. Treat them as errors instead and terminate the search. Fixes: QubesOS/qubes-issues#9089
1 parent f74981f commit d5d7184

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

libqrexec/exec.c

+23-5
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ static int execute_qrexec_service(
212212

213213
/*
214214
Find a file in the ':'-delimited list of paths given in path_list.
215-
Returns 0 on success, -1 on failure.
215+
Returns 0 on success, -1 if the file is definitely absent in all of the
216+
paths, and -2 on error (broken symlink, I/O error, path too long, out
217+
of memory, etc).
216218
On success, fills buffer and statbuf (unless statbuf is NULL).
217219
*/
218220
static int find_file(
@@ -225,6 +227,10 @@ static int find_file(
225227
struct stat dummy_buf;
226228
const char *path_start = path_list;
227229
size_t name_length = strlen(name);
230+
int res;
231+
232+
if (name_length > NAME_MAX)
233+
return -1; /* cannot possibly exist */
228234

229235
if (!statbuf)
230236
statbuf = &dummy_buf;
@@ -236,15 +242,27 @@ static int find_file(
236242

237243
if (path_length + name_length + 1 >= buffer_size) {
238244
LOG(ERROR, "find_qrexec_service_file: buffer too small for file path");
239-
return -1;
245+
return -2;
240246
}
241247

242248
memcpy(buffer, path_start, path_length);
243249
buffer[path_length] = '/';
244250
strcpy(buffer + path_length + 1, name);
245251
//LOG(INFO, "stat(%s)", buffer);
246-
if (stat(buffer, statbuf) == 0)
252+
res = lstat(buffer, statbuf);
253+
if (res == 0 && S_ISLNK(statbuf->st_mode)) {
254+
/* check if the symlink is valid */
255+
res = stat(buffer, statbuf);
256+
assert(res == -1 || !S_ISLNK(statbuf->st_mode));
257+
}
258+
if (res == 0) {
247259
return 0;
260+
} else {
261+
assert(res == -1);
262+
if (errno != ENOENT) {
263+
return -2;
264+
}
265+
}
248266

249267
path_start = path_end;
250268
while (*path_start == ':')
@@ -264,7 +282,7 @@ static int load_service_config_raw(struct qrexec_parsed_command *cmd,
264282

265283
int ret = find_file(config_path, cmd->service_descriptor,
266284
config_full_path, sizeof(config_full_path), NULL);
267-
if (ret < 0 && strcmp(cmd->service_descriptor, cmd->service_name) != 0)
285+
if (ret == -1 && strcmp(cmd->service_descriptor, cmd->service_name) != 0)
268286
ret = find_file(config_path, cmd->service_name,
269287
config_full_path, sizeof(config_full_path), NULL);
270288
if (ret < 0)
@@ -462,7 +480,7 @@ static int execute_qrexec_service(
462480
int ret = find_file(qrexec_service_path, cmd->service_descriptor,
463481
service_full_path, sizeof(service_full_path),
464482
&statbuf);
465-
if (ret < 0 && strcmp(cmd->service_descriptor, cmd->service_name) != 0)
483+
if (ret == -1 && strcmp(cmd->service_descriptor, cmd->service_name) != 0)
466484
ret = find_file(qrexec_service_path, cmd->service_name,
467485
service_full_path, sizeof(service_full_path),
468486
&statbuf);

qrexec/tests/socket/agent.py

-1
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,6 @@ def test_exec_service_with_arg(self):
525525
)
526526
self.check_dom0(dom0)
527527

528-
@unittest.expectedFailure
529528
def test_exec_broken_specific_service(self):
530529
os.symlink("/dev/null/invalid",
531530
os.path.join(self.tempdir, "rpc", "qubes.Service+arg"))

0 commit comments

Comments
 (0)