Skip to content

Commit 9f33051

Browse files
mctpd: Allow mctpd to manage its capabilities.
Added the set_cap() function to mctpd, allowing the process to drop CAP_NET_BIND_SERVICE when it is no longer needed. This requires libcap on the target device. If libcap is missing drop_bind_cap() will be a stub, and mctpd will emit a warning when it starts. Because mctpd requires additional capabilities and may recieve hostile inputs, dropping the capability when it is no longer needed is useful to increase safety. libcap has been added as a possible dependency to the meson build and mcpd now uses the MCTPD_MANAGING_CAPABILITIES macro to determine if libcap is available. mctpd.md has been updated to reflect the new capability management. Signed-off-by: James Lee <james@codeconstruct.com.au>
1 parent 3cd2da6 commit 9f33051

3 files changed

Lines changed: 73 additions & 2 deletions

File tree

docs/mctpd.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,3 +503,14 @@ match = { path = "/devices/pci0000:00/0000:00:08.3/*" }
503503
```
504504

505505
Paths have the `/sys` prefix stripped.
506+
507+
## Capabilities
508+
509+
`mctpd` requires the `CAP_NET_BIND_SERVICE` and `CAP_NET_ADMIN` capabilites to run.
510+
If the service is not running as root these should be added to the `AmbientCapabilities` setting in the service's config.
511+
If the target platform has the `libcap` library available,
512+
the `mctpd` process will drop `CAP_NET_BIND_SERVICE` when it is no longer needed.
513+
514+
Because `mctpd` may be exposed to potentially hostile inputs,
515+
it shouldn't be given more capabilities than necessary.
516+
`mctpd` will emit a warning while starting on target platforms that do not have `libcap`.

meson.build

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ add_project_arguments('-Wno-unused-parameter', language : 'c')
1616

1717
libsystemd = dependency('libsystemd', version: '>=247', required: false)
1818

19+
libcap = dependency('libcap', required: false)
20+
1921
conf = configuration_data()
2022
conf.set10('HAVE_LINUX_MCTP_H',
2123
cc.has_header('linux/mctp.h'),
@@ -37,6 +39,10 @@ conf.set10('MCTPD_WRITABLE_CONNECTIVITY',
3739
get_option('unsafe-writable-connectivity'),
3840
description: 'Allow writes to the Connectivity member of the au.com.codeconstruct.MCTP.Endpoint1 interface on endpoint objects')
3941

42+
conf.set10('MCTPD_MANAGE_CAPABILITIES',
43+
libcap.found(),
44+
description: 'Require mctpd to minimise its capabilities (emits warning on start if false)')
45+
4046
conf.set_quoted('MCTPD_CONF_FILE_DEFAULT',
4147
join_paths(get_option('prefix'), get_option('sysconfdir'), 'mctpd.conf'),
4248
description: 'Default configuration file path',
@@ -89,7 +95,7 @@ if libsystemd.found()
8995
sources: [
9096
'src/mctpd.c',
9197
] + netlink_sources + util_sources + ops_sources,
92-
dependencies: [libsystemd, toml_dep],
98+
dependencies: [libsystemd, toml_dep, libcap],
9399
install: true,
94100
install_dir: get_option('sbindir'),
95101
c_args: ['-DOPS_SD_EVENT=1'],
@@ -100,7 +106,7 @@ if libsystemd.found()
100106
'src/mctpd.c',
101107
] + test_ops_sources + netlink_sources + util_sources,
102108
include_directories: include_directories('src'),
103-
dependencies: [libsystemd, toml_dep],
109+
dependencies: [libsystemd, toml_dep, libcap],
104110
c_args: ['-DOPS_SD_EVENT=1'],
105111
)
106112
endif

src/mctpd.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#define _GNU_SOURCE
1010
#include "config.h"
1111

12+
#if MCTPD_MANAGE_CAPABILITIES
13+
#include <sys/capability.h>
14+
#endif
15+
1216
#include <assert.h>
1317
#include <systemd/sd-bus-vtable.h>
1418
#include <time.h>
@@ -6342,13 +6346,56 @@ static int endpoint_allocate_eids(struct peer *peer)
63426346
return 0;
63436347
}
63446348

6349+
int drop_bind_cap(void)
6350+
{
6351+
#if MCTPD_MANAGE_CAPABILITIES
6352+
cap_flag_t flags[] = { CAP_EFFECTIVE, CAP_INHERITABLE, CAP_PERMITTED };
6353+
cap_value_t bind = CAP_NET_BIND_SERVICE;
6354+
cap_t cap;
6355+
size_t i;
6356+
int rc;
6357+
6358+
cap = cap_get_proc();
6359+
if (!cap)
6360+
return -errno;
6361+
6362+
for (i = 0; i < ARRAY_SIZE(flags); i++) {
6363+
rc = cap_set_flag(cap, flags[i], 1, &bind, CAP_CLEAR);
6364+
if (rc < 0) {
6365+
rc = -errno;
6366+
cap_free(cap);
6367+
return rc;
6368+
}
6369+
}
6370+
6371+
rc = cap_set_proc(cap);
6372+
if (rc < 0) {
6373+
rc = -errno;
6374+
cap_free(cap);
6375+
return rc;
6376+
}
6377+
6378+
rc = cap_free(cap);
6379+
if (rc < 0)
6380+
return -errno;
6381+
6382+
return 0;
6383+
#else
6384+
return 0;
6385+
#endif
6386+
}
6387+
63456388
int main(int argc, char **argv)
63466389
{
63476390
struct ctx ctxi = { 0 }, *ctx = &ctxi;
63486391
int rc;
63496392

63506393
setlinebuf(stdout);
63516394

6395+
#if !MCTPD_MANAGE_CAPABILITIES
6396+
warnx("mctpd has been compiled without capability management and will not drop CAP_NET_BIND_SERVICE");
6397+
#endif
6398+
63526399
setup_config_defaults(ctx);
63536400
setup_ctrl_cmd_defaults(ctx);
63546401

@@ -6397,6 +6444,13 @@ int main(int argc, char **argv)
63976444
return 1;
63986445
}
63996446

6447+
rc = drop_bind_cap();
6448+
if (rc < 0) {
6449+
warnx("Error dropping capabilities, returned %s %d",
6450+
strerror(-rc), rc);
6451+
return 1;
6452+
}
6453+
64006454
// All setup must be complete by here, we might immediately
64016455
// get requests from waiting clients.
64026456
rc = request_dbus(ctx);

0 commit comments

Comments
 (0)