diff --git a/conf/mctpd-dbus.conf b/conf/mctpd-dbus.conf
index e97bfe00..4ee74497 100644
--- a/conf/mctpd-dbus.conf
+++ b/conf/mctpd-dbus.conf
@@ -2,9 +2,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/conf/mctpd.service b/conf/mctpd.service
index 62410c15..7f96c25e 100644
--- a/conf/mctpd.service
+++ b/conf/mctpd.service
@@ -8,6 +8,8 @@ After=mctp-local.target
Type=dbus
BusName=au.com.codeconstruct.MCTP1
ExecStart=/usr/sbin/mctpd
+User=mctpd
+AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
[Install]
WantedBy=mctp.target
diff --git a/docs/mctpd.md b/docs/mctpd.md
index 236e1a54..5f5f8f11 100644
--- a/docs/mctpd.md
+++ b/docs/mctpd.md
@@ -503,3 +503,15 @@ match = { path = "/devices/pci0000:00/0000:00:08.3/*" }
```
Paths have the `/sys` prefix stripped.
+
+## Capabilities
+
+`mctpd` requires the `CAP_NET_BIND_SERVICE` and `CAP_NET_ADMIN` capabilites to run.
+If the service is not running as root these should be added to the `AmbientCapabilities` setting in the service's config.
+If the target platform has the `libcap` library available,
+the `mctpd` process will drop all other capabilities,
+only keeping the necessary capabilities in the effective set as needed.
+
+Because `mctpd` is must be a privileged process that is exposed to potentially hostile inputs,
+it shouldn't be given more capabilities than necessary.
+`mctpd` will emit a warning while starting on target platforms that do not have `libcap`.
\ No newline at end of file
diff --git a/meson.build b/meson.build
index 622978da..14643cf7 100644
--- a/meson.build
+++ b/meson.build
@@ -16,6 +16,8 @@ add_project_arguments('-Wno-unused-parameter', language : 'c')
libsystemd = dependency('libsystemd', version: '>=247', required: false)
+libcap = dependency('libcap', required: false)
+
conf = configuration_data()
conf.set10('HAVE_LINUX_MCTP_H',
cc.has_header('linux/mctp.h'),
@@ -37,6 +39,10 @@ conf.set10('MCTPD_WRITABLE_CONNECTIVITY',
get_option('unsafe-writable-connectivity'),
description: 'Allow writes to the Connectivity member of the au.com.codeconstruct.MCTP.Endpoint1 interface on endpoint objects')
+conf.set10('MCTPD_MANAGE_CAPABILITIES',
+ libcap.found(),
+ description: 'Require mctpd to minimise its capabilities (emits warning on start if false)')
+
conf.set_quoted('MCTPD_CONF_FILE_DEFAULT',
join_paths(get_option('prefix'), get_option('sysconfdir'), 'mctpd.conf'),
description: 'Default configuration file path',
@@ -89,7 +95,7 @@ if libsystemd.found()
sources: [
'src/mctpd.c',
] + netlink_sources + util_sources + ops_sources,
- dependencies: [libsystemd, toml_dep],
+ dependencies: [libsystemd, toml_dep, libcap],
install: true,
install_dir: get_option('sbindir'),
c_args: ['-DOPS_SD_EVENT=1'],
@@ -100,7 +106,7 @@ if libsystemd.found()
'src/mctpd.c',
] + test_ops_sources + netlink_sources + util_sources,
include_directories: include_directories('src'),
- dependencies: [libsystemd, toml_dep],
+ dependencies: [libsystemd, toml_dep, libcap],
c_args: ['-DOPS_SD_EVENT=1'],
)
endif
diff --git a/src/mctpd.c b/src/mctpd.c
index c9a41dbf..f2bb1111 100644
--- a/src/mctpd.c
+++ b/src/mctpd.c
@@ -9,6 +9,10 @@
#define _GNU_SOURCE
#include "config.h"
+#if MCTPD_MANAGE_CAPABILITIES
+#include
+#endif
+
#include
#include
#include
@@ -6342,6 +6346,39 @@ static int endpoint_allocate_eids(struct peer *peer)
return 0;
}
+int set_cap(char *str)
+{
+#if MCTPD_MANAGE_CAPABILITIES
+ cap_t cap = cap_from_text(str);
+ int rc;
+
+ if (!cap) {
+ rc = -errno;
+ warnx("Failed allocating capability state: %s, %s %d", str,
+ strerror(-rc), rc);
+ return rc;
+ }
+
+ rc = cap_set_proc(cap);
+ if (rc < 0) {
+ rc = -errno;
+ warnx("Could not set capabilites: %s, %s %d", str,
+ strerror(-rc), rc);
+ return rc;
+ }
+
+ rc = cap_free(cap);
+ if (rc < 0) {
+ rc = -errno;
+ warnx("Failed freeing capability state");
+ return rc;
+ }
+ return 0;
+#else
+ return 0;
+#endif
+}
+
int main(int argc, char **argv)
{
struct ctx ctxi = { 0 }, *ctx = &ctxi;
@@ -6349,6 +6386,14 @@ int main(int argc, char **argv)
setlinebuf(stdout);
+#if !MCTPD_MANAGE_CAPABILITIES
+ warnx("mctpd has been compiled without capability management and will not drop capabilities");
+#endif
+
+ rc = set_cap("CAP_NET_BIND_SERVICE=p CAP_NET_ADMIN=p");
+ if (rc < 0)
+ return 1;
+
setup_config_defaults(ctx);
setup_ctrl_cmd_defaults(ctx);
@@ -6390,6 +6435,10 @@ int main(int argc, char **argv)
if (rc < 0)
return 1;
+ rc = set_cap("CAP_NET_BIND_SERVICE=pe CAP_NET_ADMIN=p");
+ if (rc < 0)
+ return 1;
+
// TODO add net argument?
rc = listen_control_msg(ctx, MCTP_NET_ANY);
if (rc < 0) {
@@ -6397,6 +6446,10 @@ int main(int argc, char **argv)
return 1;
}
+ rc = set_cap("CAP_NET_ADMIN=pe");
+ if (rc < 0)
+ return 1;
+
// All setup must be complete by here, we might immediately
// get requests from waiting clients.
rc = request_dbus(ctx);