Skip to content

Commit df9fb86

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 df9fb86

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` 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: 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 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,6 +6346,50 @@ static int endpoint_allocate_eids(struct peer *peer)
63426346
return 0;
63436347
}
63446348

6349+
#if MCTPD_MANAGE_CAPABILITIES
6350+
6351+
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+
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)