Skip to content

Commit f43dd6c

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 f43dd6c

3 files changed

Lines changed: 74 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`
511+
setting in the service's config.
512+
If the target platform has the `libcap` library available,
513+
the `mctpd` process will drop `CAP_NET_BIND_SERVICE` when it is no longer needed.
514+
515+
Because `mctpd` may be exposed to potentially hostile inputs,
516+
it shouldn't be given more capabilities than necessary.

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('HAVE_LIBCAP',
43+
libcap.found(),
44+
description: 'Require mctpd to minimise its capabilities')
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: 55 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 HAVE_LIBCAP
13+
#include <sys/capability.h>
14+
#endif
15+
1216
#include <assert.h>
1317
#include <systemd/sd-bus-vtable.h>
1418
#include <time.h>
@@ -6342,6 +6346,50 @@ static int endpoint_allocate_eids(struct peer *peer)
63426346
return 0;
63436347
}
63446348

6349+
#if HAVE_LIBCAP
6350+
6351+
static int drop_bind_cap(void)
6352+
{
6353+
cap_flag_t flags[] = { CAP_EFFECTIVE, CAP_INHERITABLE, CAP_PERMITTED };
6354+
cap_value_t bind = CAP_NET_BIND_SERVICE;
6355+
cap_t cap;
6356+
size_t i;
6357+
int rc;
6358+
6359+
cap = cap_get_proc();
6360+
if (!cap)
6361+
return -errno;
6362+
6363+
for (i = 0; i < ARRAY_SIZE(flags); i++) {
6364+
rc = cap_set_flag(cap, flags[i], 1, &bind, CAP_CLEAR);
6365+
if (rc < 0) {
6366+
rc = -errno;
6367+
cap_free(cap);
6368+
return rc;
6369+
}
6370+
}
6371+
6372+
rc = cap_set_proc(cap);
6373+
if (rc < 0) {
6374+
rc = -errno;
6375+
cap_free(cap);
6376+
return rc;
6377+
}
6378+
6379+
rc = cap_free(cap);
6380+
if (rc < 0)
6381+
return -errno;
6382+
6383+
return 0;
6384+
}
6385+
#else
6386+
6387+
static int drop_bind_cap(void)
6388+
{
6389+
return 0;
6390+
}
6391+
#endif
6392+
63456393
int main(int argc, char **argv)
63466394
{
63476395
struct ctx ctxi = { 0 }, *ctx = &ctxi;
@@ -6397,6 +6445,13 @@ int main(int argc, char **argv)
63976445
return 1;
63986446
}
63996447

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

0 commit comments

Comments
 (0)