Skip to content

Commit 58c85ee

Browse files
committed
Harden fm-shim-backend D-Bus name acquisition, error replies, fd hygiene, systemd sandboxing, and cleanup
- Add DBUS_NAME_FLAG_DO_NOT_QUEUE and terminate on IN_QUEUE to prevent silent name takeover after another owner exits - Send proper D-Bus error replies for unrecognized methods, wrong object paths, and wrong interfaces instead of leaving callers hanging - Close inherited file descriptors in child process before execve to avoid leaking the D-Bus socket to the frontend - Add systemd sandboxing directives (NoNewPrivileges, ProtectSystem, ProtectHome, PrivateTmp, etc.) to the user service - Add explicit dbus_connection_unref/dbus_error_free on main loop exit https://claude.ai/code/session_01CgrrFhhVWtqtfhvJdEcBWm
1 parent 3949bf3 commit 58c85ee

2 files changed

Lines changed: 55 additions & 9 deletions

File tree

usr/lib/systemd/user/fm-shim.service#security-misc-shared

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ StartLimitBurst=3
1010
Type=notify
1111
ExecStart=/usr/bin/fm-shim-backend
1212
Restart=always
13+
NoNewPrivileges=yes
14+
ProtectSystem=strict
15+
ProtectHome=read-only
16+
PrivateTmp=yes
17+
RestrictNamespaces=yes
18+
RestrictRealtime=yes
19+
MemoryDenyWriteExecute=yes
20+
LockPersonality=yes
1321

1422
[Install]
1523
WantedBy=default.target

usr/src/security-misc/fm-shim-backend.c#security-misc-shared

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <unistd.h>
3333
#include <assert.h>
3434
#include <sys/wait.h>
35+
#include <dirent.h>
3536
#include <signal.h>
3637
#include <dbus/dbus.h>
3738
#include <systemd/sd-daemon.h>
@@ -192,7 +193,23 @@ void launch_frontend_process(const char *mode_opt, char **uri_list,
192193
if (fork_pid == -1) {
193194
err(1, "launch_frontend_process: fork failed");
194195
} else if (fork_pid == 0) {
195-
/* child */
196+
/* child - close inherited fds (except stdin/stdout/stderr) */
197+
DIR *fd_dir = opendir("/proc/self/fd");
198+
if (fd_dir != NULL) {
199+
int dir_fd = dirfd(fd_dir);
200+
struct dirent *fd_entry;
201+
while ((fd_entry = readdir(fd_dir)) != NULL) {
202+
char *endptr = NULL;
203+
long fd_num = strtol(fd_entry->d_name, &endptr, 10);
204+
if (endptr == fd_entry->d_name || *endptr != '\0') {
205+
continue;
206+
}
207+
if (fd_num >= 3 && fd_num != (long)dir_fd) {
208+
close((int)fd_num);
209+
}
210+
}
211+
closedir(fd_dir);
212+
}
196213
#pragma GCC diagnostic push
197214
#pragma GCC diagnostic ignored "-Wcast-qual"
198215
if (execve(arg_arr[0], (char **)arg_arr, (char **)env_arr) == -1) {
@@ -332,7 +349,7 @@ int main(void) {
332349

333350
dbus_name_request_rslt = dbus_bus_request_name(dbus_conn,
334351
"org.freedesktop.FileManager1",
335-
DBUS_NAME_FLAG_REPLACE_EXISTING,
352+
DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE,
336353
&error_data);
337354
if (dbus_name_request_rslt == -1) {
338355
errx(1, "Failed to request 'org.freedesktop.FileManager1' name from D-Bus. Error name: '%s'. Error contents: '%s'.",
@@ -346,13 +363,7 @@ int main(void) {
346363
sd_notify(0, "STATUS=Running");
347364
break;
348365
case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
349-
warnx("Requested 'org.freedesktop.FileManager1' name from D-Bus, but was placed in queue.");
350-
warnx("This may be a security risk! Please report this bug!");
351-
/*
352-
* sd_notify(0, "READY=1") is intentionally omitted here, so that
353-
* systemcheck will show a warning about the system not being ready
354-
*/
355-
sd_notify(0, "STATUS=Running, security issue detected");
366+
errx(1, "Requested 'org.freedesktop.FileManager1' name from D-Bus, but was placed in queue. This is a security risk! Please report this bug!");
356367
break;
357368
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
358369
warnx("Possible bug, we already own 'org.freedesktop.FileManager1' name?");
@@ -393,6 +404,14 @@ int main(void) {
393404
if (strcmp(dbus_msg_obj_path, "/org/freedesktop/FileManager1") != 0) {
394405
warnx("Received a D-Bus method call for object path '%s', rather than '/org/freedesktop/FileManager1'!",
395406
dbus_msg_obj_path);
407+
if (dbus_message_get_no_reply(dbus_msg) == FALSE) {
408+
DBusMessage *err_reply = dbus_message_new_error(dbus_msg,
409+
DBUS_ERROR_UNKNOWN_OBJECT, "Unknown object path");
410+
if (err_reply != NULL) {
411+
dbus_connection_send(dbus_conn, err_reply, NULL);
412+
dbus_message_unref(err_reply);
413+
}
414+
}
396415
goto cleanup;
397416
}
398417

@@ -404,6 +423,14 @@ int main(void) {
404423
if (strcmp(dbus_msg_iface, "org.freedesktop.FileManager1") != 0) {
405424
warnx("Received a D-Bus method call for interface '%s', rather than 'org.freedesktop.FileManager1'!",
406425
dbus_msg_iface);
426+
if (dbus_message_get_no_reply(dbus_msg) == FALSE) {
427+
DBusMessage *err_reply = dbus_message_new_error(dbus_msg,
428+
DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
429+
if (err_reply != NULL) {
430+
dbus_connection_send(dbus_conn, err_reply, NULL);
431+
dbus_message_unref(err_reply);
432+
}
433+
}
407434
goto cleanup;
408435
}
409436

@@ -422,6 +449,14 @@ int main(void) {
422449
} else {
423450
warnx("Received a D-Bus method call for unrecognized method '%s'!",
424451
dbus_msg_method);
452+
if (dbus_message_get_no_reply(dbus_msg) == FALSE) {
453+
DBusMessage *err_reply = dbus_message_new_error(dbus_msg,
454+
DBUS_ERROR_UNKNOWN_METHOD, "Unknown method");
455+
if (err_reply != NULL) {
456+
dbus_connection_send(dbus_conn, err_reply, NULL);
457+
dbus_message_unref(err_reply);
458+
}
459+
}
425460
}
426461

427462
cleanup:
@@ -433,4 +468,7 @@ cleanup:
433468
dbus_msg_iface = NULL;
434469
dbus_msg_method = NULL;
435470
}
471+
472+
dbus_connection_unref(dbus_conn);
473+
dbus_error_free(&error_data);
436474
}

0 commit comments

Comments
 (0)