From 7a4f0318edea0540129a7ba10c2606aa1a23b6fa Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 26 Aug 2024 19:07:18 +0530 Subject: [PATCH] Remote control: When listening on a UNIX domain socket only allow connections from processes having the same user id Fixes #7777 --- docs/changelog.rst | 2 ++ kitty/boss.py | 2 +- kitty/child-monitor.c | 16 +++++++++++++++- kitty/fast_data_types.pyi | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index d7bb970e6..233eb97da 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -83,6 +83,8 @@ Detailed list of changes - Wayland: Fix for upcoming explicit sync changes in Wayland compositors breaking kitty (:iss:`7767`) +- Remote control: When listening on a UNIX domain socket only allow connections from processes having the same user id (:pull:`7777`) + 0.36.1 [2024-08-24] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/boss.py b/kitty/boss.py index 342d7ca0b..209f6ea37 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -362,7 +362,7 @@ def __init__( self.child_monitor: ChildMonitor = ChildMonitor( self.on_child_death, DumpCommands(args) if args.dump_commands or args.dump_bytes else None, - talk_fd, listen_fd, + talk_fd, listen_fd, self.listening_on.startswith('unix:') ) self.args: CLIOptions = args self.mouse_handler: Optional[Callable[[WindowSystemMouseEvent], None]] = None diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index dbfaed2c4..feee3a134 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -152,6 +152,8 @@ mask_kitty_signals_process_wide(PyObject *self UNUSED, PyObject *a UNUSED) { Py_RETURN_NONE; } +static int verify_peer_uid = false; + static PyObject * new_childmonitor_object(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { ChildMonitor *self; @@ -160,7 +162,7 @@ new_childmonitor_object(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwd int ret; if (the_monitor) { PyErr_SetString(PyExc_RuntimeError, "Can have only a single ChildMonitor instance"); return NULL; } - if (!PyArg_ParseTuple(args, "OO|ii", &death_notify, &dump_callback, &talk_fd, &listen_fd)) return NULL; + if (!PyArg_ParseTuple(args, "OO|iip", &death_notify, &dump_callback, &talk_fd, &listen_fd, &verify_peer_uid)) return NULL; if ((ret = pthread_mutex_init(&children_lock, NULL)) != 0) { PyErr_Format(PyExc_RuntimeError, "Failed to create children_lock mutex: %s", strerror(ret)); return NULL; @@ -1663,6 +1665,18 @@ accept_peer(int listen_fd, bool shutting_down, bool is_remote_control_peer) { if (!shutting_down) perror("accept() on talk socket failed!"); return false; } + if (verify_peer_uid) { + uid_t peer_uid; gid_t peer_gid; + if (!getpeerid(peer, &peer_uid, &peer_gid)) { + log_error("Denying access to peer because failed to get uid and gid for peer: %d with error: %s", peer, strerror(errno)); + safe_close(peer, __FILE__, __LINE__); + return true; + } + if (peer_uid != geteuid()) { + log_error("Denying access to peer because its uid (%d) does not match our uid (%d)", peer_uid, geteuid()); + return true; + } + } add_peer(peer, is_remote_control_peer); return true; } diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 861eb6454..dedbfc5dd 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1366,6 +1366,7 @@ class ChildMonitor: dump_callback: Optional[Callable[[int, str, Any], None]], talk_fd: int = -1, listen_fd: int = -1, + verify_peer_uid: bool = False, ): pass