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


Reply via email to