From dc317a9aed3ef43f76f05cb6eeb49c7c82c0e2ad Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Oct 2021 02:41:38 +0900 Subject: [PATCH 1/2] sd-netlink: introduce sd_netlink_attach_filter() --- src/libsystemd/sd-netlink/sd-netlink.c | 15 +++++++++++++++ src/systemd/sd-netlink.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 2bf26523bd..9de13f4c46 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -1023,3 +1023,18 @@ int sd_netlink_add_match( return netlink_add_match_internal(rtnl, ret_slot, groups, n_groups, type, 0, callback, destroy_callback, userdata, description); } + +int sd_netlink_attach_filter(sd_netlink *nl, size_t len, struct sock_filter *filter) { + assert_return(nl, -EINVAL); + assert_return(len == 0 || filter, -EINVAL); + + if (setsockopt(nl->fd, SOL_SOCKET, + len == 0 ? SO_DETACH_FILTER : SO_ATTACH_FILTER, + &(struct sock_fprog) { + .len = len, + .filter = filter, + }, sizeof(struct sock_fprog)) < 0) + return -errno; + + return 0; +} diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index fdf802041a..66a1bb6a33 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,7 @@ int sd_netlink_add_match(sd_netlink *nl, sd_netlink_slot **ret_slot, uint16_t ma int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority); int sd_netlink_detach_event(sd_netlink *nl); +int sd_netlink_attach_filter(sd_netlink *nl, size_t len, struct sock_filter *filter); /* message */ int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data); From 26a8be48bc53fdf1f67bc2ae91c80c7f11295d9d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 19 Oct 2021 03:55:24 +0900 Subject: [PATCH 2/2] network: introduce BPF to reject netlink messages about non-static neighbor Fixes #21031. --- src/network/networkd-manager.c | 36 +++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b4494d5182..eb4ee5cab3 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -263,6 +263,40 @@ static int manager_connect_genl(Manager *m) { return 0; } +static int manager_setup_rtnl_filter(Manager *manager) { + struct sock_filter filter[] = { + /* Check the packet length. */ + BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ + BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr), 1, 0), /* A (packet length) >= sizeof(struct nlmsghdr) ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ + /* Always accept multipart message. */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_flags)), /* A <- message flags */ + BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NLM_F_MULTI), 0, 1), /* message flags has NLM_F_MULTI ? */ + BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ + /* Accept all message types except for RTM_NEWNEIGH or RTM_DELNEIGH. */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct nlmsghdr, nlmsg_type)), /* A <- message type */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_NEWNEIGH), 2, 0), /* message type == RTM_NEWNEIGH ? */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htobe16(RTM_DELNEIGH), 1, 0), /* message type == RTM_DELNEIGH ? */ + BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ + /* Check the packet length. */ + BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ + BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct nlmsghdr) + sizeof(struct ndmsg), 1, 0), + /* packet length >= sizeof(struct nlmsghdr) + sizeof(struct ndmsg) ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ + /* Reject the message when the neighbor state does not have NUD_PERMANENT flag. */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, sizeof(struct nlmsghdr) + offsetof(struct ndmsg, ndm_state)), + /* A <- neighbor state */ + BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, htobe16(NUD_PERMANENT), 1, 0), /* neighbor state has NUD_PERMANENT ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* reject */ + BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ + }; + + assert(manager); + assert(manager->rtnl); + + return sd_netlink_attach_filter(manager->rtnl, ELEMENTSOF(filter), filter); +} + static int manager_connect_rtnl(Manager *m) { int fd, r; @@ -337,7 +371,7 @@ static int manager_connect_rtnl(Manager *m) { if (r < 0) return r; - return 0; + return manager_setup_rtnl_filter(m); } static int manager_dirty_handler(sd_event_source *s, void *userdata) {