Skip to content

Conversation

@mauriciovasquezbernal
Copy link
Contributor

@mauriciovasquezbernal mauriciovasquezbernal commented Jan 26, 2021

Add RestrictNetworkInterfaces= option to limit the network interfaces a program in a unit can use.

This PR uses the libbpf support introduced in #17655. The feature is implemented with BPF_PROG_TYPE_CGROUP_SKB programs attached to the BPF_CGROUP_INET_{INGRESS|EGRESS} hooks.

There are still some TODOs but I wanted to open the PR to start the discussion now.

TODO:

/cc @iaguis

@lgtm-com
Copy link

lgtm-com bot commented Feb 19, 2021

This pull request introduces 1 alert when merging a9c79a8 into fa98c99 - view on LGTM.com

new alerts:

  • 1 for Unused import

@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from a9c79a8 to c2d7499 Compare February 22, 2021 14:41
@lgtm-com
Copy link

lgtm-com bot commented Feb 22, 2021

This pull request introduces 1 alert when merging c2d7499 into 5735ab0 - view on LGTM.com

new alerts:

  • 1 for Unused import

Copy link
Member

@poettering poettering left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good! A few comments

dummy = 0;

SET_FOREACH(iface, restrict_network_interfaces) {
ifindex = if_nametoindex(iface);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use resolve_interface() from socket-netlink.c: it also supports resolving new-style "altnames" for interfaces

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean resolve_ifname()? resolve_interface() tries to parse the interface name to an integer before using netlink, I think it's not correct for this use case as an interface with an integer name can have a if_index different to the name.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, in networkd and elsewhere we generally explicitly check that people cannot name ifaces numerically, so that no ambiguity can happen, and so that ifindex and ifname can be used unambigiously interchangable.

For transient services it might make sense to pinpoint ifaces by ifindex, since they are generated programmatically on the fly. hence i see no eason why not to accept ifindexes here, if people want to specify them

@poettering poettering added pid1 reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks labels Feb 24, 2021
@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from c2d7499 to eee13b7 Compare February 25, 2021 00:29
@lgtm-com
Copy link

lgtm-com bot commented Feb 25, 2021

This pull request introduces 1 alert when merging eee13b7 into fa02711 - view on LGTM.com

new alerts:

  • 1 for Unused import

@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from eee13b7 to 56e90a5 Compare February 25, 2021 20:20
@lgtm-com
Copy link

lgtm-com bot commented Feb 25, 2021

This pull request introduces 1 alert when merging 56e90a5 into 584e9ba - view on LGTM.com

new alerts:

  • 1 for Unused import

@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from 56e90a5 to ca463a4 Compare February 26, 2021 01:13
@lgtm-com
Copy link

lgtm-com bot commented Feb 26, 2021

This pull request introduces 1 alert when merging ca463a4 into 8b2620e - view on LGTM.com

new alerts:

  • 1 for Unused import

@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from ca463a4 to c146e5b Compare February 26, 2021 12:09
@lgtm-com
Copy link

lgtm-com bot commented Feb 26, 2021

This pull request introduces 1 alert when merging c146e5b into 499c851 - view on LGTM.com

new alerts:

  • 1 for Unused import

@poettering
Copy link
Member

Any chance you can rebase now that #17655 has been merged? Should be an easy merge then

@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch 4 times, most recently from bb1568c to 05d4ac0 Compare May 19, 2021 19:35
@poettering poettering added the reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks label Aug 17, 2021
@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from 90d7a5f to 89028c4 Compare August 17, 2021 18:57
Copy link
Contributor Author

@mauriciovasquezbernal mauriciovasquezbernal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I handled the comments.

_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
char *iface;
uint8_t dummy = 0;
int ifindex;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved dummy and ifindex, others are needed outside.

log_syntax(unit, LOG_WARNING, filename, line, r,
"Trailing garbage in %s, ignoring: %s", lvalue, rvalue);
break;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, got it. Thanks for the clarification.

Copy link
Member

@poettering poettering left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks really good, we are close!

}

SEC("cgroup_skb/egress")
int sd_restrictif_e(struct __sk_buff *sk) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wondering, souldn't the param be const?


if (!c->restrict_network_interfaces) {
c->restrict_network_interfaces_is_allow_list = is_allow_list;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no {} around single line if blocks

return 1;
}

if (!c->restrict_network_interfaces) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd probably check for emptiness rathre than non-NULL here. i.e. if (set_isempty(c->restrict_network_interfaces). note that a NULL set is considered empty, hence such a check is mostly equivalent, but kinda underlines that the set is allocated lazily here

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

const volatile __u8 is_allow_list = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does this actually work? i.e. how does the consuming code get access to this, and in particular write access?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated skeleton includes a structure with those variables, they are filled by the user space part (obj->rodata->is_allow_list = is_allow_list; in restrict-ifaces.c) before loading the BPF object. When the object is loaded, libbpf creates an eBPF map that backes up those variables, libbpf copies the value of those to the map and freezes it to avoid further modifications in the case the variable is const.

@poettering
Copy link
Member

the ifname validity check is still missing...

@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from 89028c4 to b65230a Compare August 18, 2021 15:58
The code is composed by two BPF_PROG_TYPE_CGROUP_SKB programs that
are loaded in the cgroup inet ingress and egress hooks
(BPF_CGROUP_INET_{INGRESS|EGRESS}).

The decision to let a packet pass or not is based on a map that contains
the indexes of the interfaces.

Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
This commit introduces all the logic to load and attach the BPF
programs to restrict network interfaces when a unit specifying it is
loaded.

Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from b65230a to 294f3ef Compare August 18, 2021 20:56
@mauriciovasquezbernal
Copy link
Contributor Author

mauriciovasquezbernal commented Aug 18, 2021

the ifname validity check is still missing...

🙈 I added it to both, load-fragment.c and dbus-cgroup.c.

@poettering
Copy link
Member

Excellent! Found one indenting nit, but doesn#t matter. Let's get this baby landed.

@poettering poettering added good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed good-to-merge/with-minor-suggestions and removed reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed labels Aug 19, 2021
Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
@mauriciovasquezbernal mauriciovasquezbernal force-pushed the mauricio/restrict-network-interfaces branch from 294f3ef to 4368984 Compare August 19, 2021 12:25
@poettering poettering added good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed and removed good-to-merge/with-minor-suggestions labels Aug 19, 2021
@poettering poettering merged commit dc13195 into systemd:main Aug 20, 2021
@jameshilliard
Copy link
Contributor

FYI I refactored the meson build for this in #20429 to try and fix cross compilation, probably good to try and test everything still works there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

good-to-merge/waiting-for-ci 👍 PR is good to merge, but CI hasn't passed at time of review. Please merge if you see CI has passed pid1 systemctl

Development

Successfully merging this pull request may close these issues.

6 participants