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 <lulu@redhat.com>
---
net/filter-mirror.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 165a7ee1ea..a521eec02b 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,
@@ -579,6 +581,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);
@@ -615,6 +632,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