Creating an AF_PACKET SOCK_RAW socket requires the CAP_NET_RAW capability. Without it the qemu_socket() call fails with EPERM, producing a generic error that gives no hint about the missing capability.
Add an explicit capget()-based check in filter_redirector_netdev_setup() before the socket call. Signed-off-by: Cindy Lu <[email protected]> --- net/filter-mirror.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/net/filter-mirror.c b/net/filter-mirror.c index dabf52275a..a07ae61b2d 100644 --- a/net/filter-mirror.c +++ b/net/filter-mirror.c @@ -34,6 +34,8 @@ #include <net/if.h> #include <linux/if_packet.h> #include <netinet/if_ether.h> +#include <linux/capability.h> +#include <sys/syscall.h> typedef struct MirrorState MirrorState; DECLARE_INSTANCE_CHECKER(MirrorState, FILTER_MIRROR, @@ -690,6 +692,21 @@ static void filter_redirector_maybe_enable_read_poll(NetFilterState *nf) } } +static bool filter_redirector_has_cap_net_raw(void) +{ + struct __user_cap_header_struct hdr = { + .version = _LINUX_CAPABILITY_VERSION_3, + .pid = 0, + }; + struct __user_cap_data_struct data[2] = {}; + + if (syscall(SYS_capget, &hdr, data) < 0) { + return false; + } + + return data[CAP_NET_RAW >> 5].effective & (1u << (CAP_NET_RAW & 31)); +} + static bool filter_redirector_netdev_setup(NetFilterState *nf, Error **errp) { MirrorState *s = FILTER_REDIRECTOR(nf); @@ -724,6 +741,13 @@ static bool filter_redirector_netdev_setup(NetFilterState *nf, Error **errp) return false; } + if (!filter_redirector_has_cap_net_raw()) { + error_setg(errp, + "AF_PACKET raw socket requires CAP_NET_RAW; " + "run with 'setcap cap_net_raw+ep <qemu-binary>' or as root"); + return false; + } + fd = qemu_socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL)); if (fd < 0) { error_setg_errno(errp, errno, "failed to create AF_PACKET socket"); -- 2.52.0
