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);