linux - Why does CAP_NET_RAW not work with SO_BINDTODEVICE? -
i have following simple test program create udp socket , bind specific interface so_bindtodevice
can bind()
inaddr_any
recieve udp broadcasts on interface.
//filename: bindtest.c #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <errno.h> #define my_port (333) #define my_device "enp0s3" #define buffersize (1000) /* global variables */ int sock; struct sockaddr_in sa; struct sockaddr_in my_addr; char buffer[buffersize]; int main(int argc, char *argv[]) { unsigned int echolen, clientlen; int rc, n; char opt_buffer[1000]; struct protoent *udp_protoent; struct timeval receive_timeout; int optval; socklen_t opt_length; sleep(1); /* create udp socket */ if ((sock = socket(af_inet, sock_dgram, ipproto_udp)) < 0) { printf ("%s: failed create udp socket (%s) \n", argv[0], strerror(errno)); exit (exit_failure); } printf ("udp socket created\n"); /* set recvfrom timeout value */ receive_timeout.tv_sec = 5; receive_timeout.tv_usec = 0; rc=setsockopt(sock, sol_socket, so_rcvtimeo, &receive_timeout, sizeof(receive_timeout)); if (rc != 0) { printf ("%s: not set so_rcvtimeo (%s)\n", argv[0], strerror(errno)); exit (exit_failure); } printf ("set timeout time [s]: %d time [ms]: %d\n", receive_timeout.tv_sec, receive_timeout.tv_usec); /* allow broadcast messages socket */ int true = 1; rc=setsockopt(sock, sol_socket, so_broadcast, &true, sizeof(true)); if (rc != 0) { printf ("%s: not set so_broadcast (%s)\n", argv[0], strerror(errno)); exit (exit_failure); } printf ("set so_broadcast worked\n"); /* bind specific interface */ char device[] = my_device; rc=setsockopt(sock, sol_socket, so_bindtodevice, device, sizeof(device)); if (rc != 0) { printf ("%s: not set so_bindtodevice (%s)\n", argv[0], strerror(errno)); exit (exit_failure); } printf ("so_bindtodevice worked\n"); /* bind own port */ my_addr.sin_family = af_inet; my_addr.sin_addr.s_addr = inaddr_any; my_addr.sin_port = htons(my_port); rc = bind (sock, (struct sockaddr *) &my_addr, sizeof(my_addr)); if (rc < 0) { printf ("%s: not bind port (%s)\n", argv[0], strerror(errno)); exit (exit_failure); } printf ("bind() worked\n"); sa.sin_family = af_inet; sa.sin_addr.s_addr = inaddr_broadcast; sa.sin_port = htons(my_port); char data[20]; sprintf(data,"foobar"); int res = sendto(sock, &data, strlen(data), 0, (struct sockaddr*)&sa, sizeof(sa)); if(res < 0){ printf("could not send\n"); } else { printf("data sent\n"); } close(sock); printf ("socket closed\n"); exit(0); }
when run program non-root user following output:
$ ./bindtest udp socket created set timeout time [s]: 5 time [ms]: 0 set so_broadcast worked ./bindtest: not set so_bindtodevice (operation not permitted)
which pretty logical because i'm not root
, so_bindtodevice
priviledged operation. included in capability cap_net_raw
understand this snippet of code linux kernel:
static int sock_setbindtodevice(struct sock *sk, char __user *optval, int optlen) { int ret = -enoprotoopt; #ifdef config_netdevices struct net *net = sock_net(sk); char devname[ifnamsiz]; int index; /* sorry... */ ret = -eperm; if (!ns_capable(net->user_ns, cap_net_raw)) goto out;
well still when do:
$ getcap bindtest $ sudo setcap cap_net_raw+ep bindtest $ getcap bindtest bindtest = cap_net_raw+ep
i same error output:
$ ./bindtest udp socket created set timeout time [s]: 5 time [ms]: 0 set so_broadcast worked ./bindtest: not set so_bindtodevice (operation not permitted)
and of course works root
:
$ sudo ./bindtest udp socket created set timeout time [s]: 5 time [ms]: 0 set so_broadcast worked so_bindtodevice worked bind() worked data sent socket closed
so why don't work expected?
the code correct, usage of getcap
/setcap
correct, else must blocking working.
and indeed because of done in /home/user
on system mounted nosuid
option among others.
so moving binary e.g. /usr/bin/
or other part not mounted nosuid
work expected in first place.
(although need cap_net_bind_service
bind()
work port 333 in example)
Comments
Post a Comment