nspawn: Add --restrict-address-families= option
Add a new --restrict-address-families= command line option and corresponding RestrictAddressFamilies= setting for .nspawn files to restrict which socket address families may be used inside a container. Many address families such as AF_VSOCK and AF_NETLINK are not network-namespaced, so restricting access to them in containers improves isolation. The option supports allowlist and denylist modes (via ~ prefix), as well as "none" to block all families, matching the semantics of RestrictAddressFamilies= in unit files. The address family parsing logic is extracted into a shared parse_address_families() helper in parse-helpers.c, which is now also used by config_parse_address_families() in load-fragment.c. This is currently opt-in. In a future version, the default will be changed to restrict address families to AF_INET, AF_INET6 and AF_UNIX.
This commit is contained in:
+11
-58
@@ -10,7 +10,6 @@
|
||||
#include "sd-bus.h"
|
||||
#include "sd-messages.h"
|
||||
|
||||
#include "af-list.h"
|
||||
#include "all-units.h"
|
||||
#include "alloc-util.h"
|
||||
#include "bpf-program.h"
|
||||
@@ -3474,72 +3473,26 @@ int config_parse_address_families(
|
||||
void *userdata) {
|
||||
|
||||
ExecContext *c = data;
|
||||
bool invert = false;
|
||||
bool is_allowlist = c->address_families_allow_list;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
/* Empty assignment resets the list */
|
||||
c->address_families = set_free(c->address_families);
|
||||
c->address_families_allow_list = false;
|
||||
r = parse_address_families(rvalue, &c->address_families, &is_allowlist);
|
||||
/* Copy back unconditionally: parse_address_families() may have partially populated
|
||||
* c->address_families before failing, so keep is_allowlist in sync with that state. */
|
||||
c->address_families_allow_list = is_allowlist;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse address family, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq(rvalue, "none")) {
|
||||
/* Forbid all address families. */
|
||||
c->address_families = set_free(c->address_families);
|
||||
c->address_families_allow_list = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rvalue[0] == '~') {
|
||||
invert = true;
|
||||
rvalue++;
|
||||
}
|
||||
|
||||
if (!c->address_families) {
|
||||
c->address_families = set_new(NULL);
|
||||
if (!c->address_families)
|
||||
return log_oom();
|
||||
|
||||
c->address_families_allow_list = !invert;
|
||||
}
|
||||
|
||||
for (const char *p = rvalue;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
int af;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Invalid syntax, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
af = af_from_name(word);
|
||||
if (af < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, af,
|
||||
"Failed to parse address family, ignoring: %s", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we previously wanted to forbid an address family and now
|
||||
* we want to allow it, then just remove it from the list.
|
||||
*/
|
||||
if (!invert == c->address_families_allow_list) {
|
||||
r = set_put(c->address_families, INT_TO_PTR(af));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
} else
|
||||
set_remove(c->address_families, INT_TO_PTR(af));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user