diff -Nurd linux-orig/Documentation/Configure.help linux/Documentation/Configure.help --- linux-orig/Documentation/Configure.help Fri Dec 21 09:41:53 2001 +++ linux/Documentation/Configure.help Fri Dec 21 18:19:02 2001 @@ -2786,6 +2786,74 @@ If unsure, say N. +IP: port/socket pseudo ACLs +CONFIG_PSEUDO_ACLS + If you say yes here, config will ask a few more questions about port + and socket ACLs. + +IP: port pseudo ACLs +CONFIG_PORT_ACLS + This simple hack allows root to delegate the ability to bind to + a reserved port (port < 1024) to non-privileged users, much like + CAP_NET_BIND_SERVICE; however, it allows much finer access control + than the capability. By setgid-ing any binary owned by the gid + specified in /proc/sys/net/ipv[46]/port_acl_gid, non-root users will + be able to use that binary to bind to the tcp or udp port equal to + their system uid. + + For instance, perhaps one would like to run snmpd as non-privileged + user "snmp," simply: + + Say yes here and compile a new kernel, then reboot into it. + Create a user "snmp" in /etc/passwd with a uid of 161. + Create a group "portacl" with an unused gid, $gid here. + # echo $gid > /proc/sys/net/ipv4/ip_port_acl_gid + # chown root.$gid /usr/sbin/snmpd + # chmod 2755 /usr/sbin/snmpd + # su - snmp -c /usr/sbin/snmpd -r + + You will most likely need to tweak the snmpd configs a bit, too. + + For more info, check http://original.killa.net/infosec/acls/index.html + +IP: Raw socket group +CONFIG_SOCK_RAW_GROUP + Say yes here if you wish to give a special group access to raw sockets. + Any raw-socket-needing binary setgid this group will not require root + access to do its duty. This may mitigate any as yet unknown exploits + for a class of setuid zero networking applications, such as ping, + traceroute or mtr. + + SOCK_RAW sockets work at the IP level, layer 3 (Network) in the + OSI model. + + You will need to setgid any binaries needing raw sockets to a new gid, + and specify that gid in /proc/sys/net/ipv[46]/ip_sock_raw_gid for it to + take effect. + + For more info, check http://original.killa.net/infosec/acls/index.html + +IP: Packet socket group +CONFIG_SOCK_PACKET_GROUP + This option allows you to split off packet socket privileges to a + seperate group. Unlike CAP_NET_RAW, you will have finer control over + which binaries will get SOCK_PACKET privs and which get SOCK_RAW privs. + + SOCK_PACKET sockets work at the device driver level, layer 2 (data link) + in the OSI model. As such, it is a lower level interface than SOCK_RAW. + The most common binaries that require packet socket access are those + which use the functionality of libpcap (e.g. tcpdump). + + You will need to setgid any binaries needing packet sockets to a new + gid, and specify that gid in /proc/sys/net/sock_packet_gid for it to + take effect. + + NOTE: I recommend you say yes, unless you have a (weird) application + that needs both raw and packet sockets. This will protect you from + any ping/traceroute exploits leading to a sniffer attack. + + For more info, check http://original.killa.net/infosec/acls/index.html + HCI EMU (virtual device) driver CONFIG_BLUEZ_HCIEMU Bluetooth Virtual HCI device driver. diff -Nurd linux-orig/include/linux/sysctl.h linux/include/linux/sysctl.h --- linux-orig/include/linux/sysctl.h Mon Nov 26 05:29:17 2001 +++ linux/include/linux/sysctl.h Fri Dec 21 18:19:02 2001 @@ -289,7 +289,11 @@ NET_TCP_ADV_WIN_SCALE=87, NET_IPV4_NONLOCAL_BIND=88, NET_IPV4_ICMP_RATELIMIT=89, - NET_IPV4_ICMP_RATEMASK=90 + NET_IPV4_ICMP_RATEMASK=90, + NET_IP_PORT_ACL_GID=91, + NET_IP_SOCK_RAW_GID=92, + NET_IP_SOCK_PACKET_GID=93 + }; enum { diff -Nurd linux-orig/net/ipv4/Config.in linux/net/ipv4/Config.in --- linux-orig/net/ipv4/Config.in Fri Dec 21 09:42:05 2001 +++ linux/net/ipv4/Config.in Fri Dec 21 18:19:02 2001 @@ -44,3 +44,19 @@ if [ "$CONFIG_NETFILTER" != "n" ]; then source net/ipv4/netfilter/Config.in fi +if [ "$CONFIG_SYSCTL" = "y" ] +then + bool ' IP: Port/socket pseudo acls' CONFIG_PSEUDO_ACLS + if [ "$CONFIG_PSEUDO_ACLS" = "y" ]; then + bool ' IP: Port ACLs' CONFIG_PORT_ACLS + bool ' IP: Raw socket group' CONFIG_SOCK_RAW_GROUP + if [ "$CONFIG_PACKET" != "n" -a "$CONFIG_SOCK_RAW_GROUP" = "y" ]; then + if [ "$CONFIG_PACKET" = "y" ]; then + bool ' Packet socket group' CONFIG_SOCK_PACKET_GROUP + else + comment ' Packet socket group not available in a module' + fi + fi + fi +fi + diff -Nurd linux-orig/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- linux-orig/net/ipv4/af_inet.c Fri Dec 21 09:42:05 2001 +++ linux/net/ipv4/af_inet.c Fri Dec 21 18:19:02 2001 @@ -123,6 +123,14 @@ atomic_t inet_sock_nr; #endif +#ifdef CONFIG_PORT_ACLS +int sysctl_port_acl_gid; +#endif + +#ifdef CONFIG_SOCK_RAW_GROUP +int sysctl_sock_raw_gid; +#endif + extern int raw_get_info(char *, char **, off_t, int); extern int snmp_get_info(char *, char **, off_t, int); extern int netstat_get_info(char *, char **, off_t, int); @@ -352,7 +360,11 @@ if (!answer) goto free_and_badtype; - if (answer->capability > 0 && !capable(answer->capability)) + if (answer->capability > 0 && !capable(answer->capability) +#ifdef CONFIG_SOCK_RAW_GROUP + && ((answer->type == SOCK_RAW) && (current->egid != sysctl_sock_raw_gid)) +#endif + ) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -503,7 +515,13 @@ return -EADDRNOTAVAIL; snum = ntohs(addr->sin_port); - if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE) +#ifdef CONFIG_PORT_ACLS + && !(current->uid == snum + && current->egid == sysctl_port_acl_gid) +#endif + ) + return -EACCES; /* We keep a pair of addresses. rcv_saddr is the one diff -Nurd linux-orig/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- linux-orig/net/ipv4/sysctl_net_ipv4.c Tue Oct 30 15:08:12 2001 +++ linux/net/ipv4/sysctl_net_ipv4.c Fri Dec 21 18:19:03 2001 @@ -55,6 +55,14 @@ extern ctl_table ipv4_route_table[]; +#ifdef CONFIG_PORT_ACLS +extern int sysctl_port_acl_gid; +#endif + +#ifdef CONFIG_SOCK_RAW_GROUP +extern int sysctl_sock_raw_gid; +#endif + #ifdef CONFIG_SYSCTL static @@ -219,6 +227,14 @@ &sysctl_icmp_ratelimit, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_ICMP_RATEMASK, "icmp_ratemask", &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec}, +#ifdef CONFIG_PORT_ACLS + {NET_IP_PORT_ACL_GID, "ip_port_acl_gid", + &sysctl_port_acl_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif +#ifdef CONFIG_SOCK_RAW_GROUP + {NET_IP_SOCK_RAW_GID, "ip_sock_raw_gid", + &sysctl_sock_raw_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif {0} }; diff -Nurd linux-orig/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- linux-orig/net/ipv6/af_inet6.c Wed Oct 17 14:16:39 2001 +++ linux/net/ipv6/af_inet6.c Fri Dec 21 18:19:03 2001 @@ -73,6 +73,14 @@ MODULE_PARM(unloadable, "i"); #endif +#ifdef CONFIG_PORT_ACLS +int sysctl_port_acl_gid; +#endif + +#ifdef CONFIG_SOCK_RAW_GROUP +int sysctl_sock_raw_gid; +#endif + /* IPv6 procfs goodies... */ #ifdef CONFIG_PROC_FS @@ -142,7 +150,11 @@ if (!answer) goto free_and_badtype; - if (answer->capability > 0 && !capable(answer->capability)) + if (answer->capability > 0 && !capable(answer->capability) +#ifdef CONFIG_SOCK_RAW_GROUP + && ((answer->type == SOCK_RAW) && (current->egid != sysctl_sock_raw_gid)) +#endif + ) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -265,7 +277,13 @@ } snum = ntohs(addr->sin6_port); - if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE) +#ifdef CONFIG_PORT_ACLS + && !(current->uid == snum + && current->egid == sysctl_port_acl_gid) +#endif + ) + return -EACCES; lock_sock(sk); diff -Nurd linux-orig/net/ipv6/sysctl_net_ipv6.c linux/net/ipv6/sysctl_net_ipv6.c --- linux-orig/net/ipv6/sysctl_net_ipv6.c Sun Mar 1 14:40:42 1998 +++ linux/net/ipv6/sysctl_net_ipv6.c Fri Dec 21 18:19:03 2001 @@ -13,10 +13,26 @@ extern ctl_table ipv6_route_table[]; +#ifdef CONFIG_PORT_ACLS +extern int sysctl_port_acl_gid; +#endif + +#ifdef CONFIG_SOCK_RAW_GROUP +extern int sysctl_sock_raw_gid; +#endif + #ifdef CONFIG_SYSCTL ctl_table ipv6_table[] = { {NET_IPV6_ROUTE, "route", NULL, 0, 0555, ipv6_route_table}, +#ifdef CONFIG_PORT_ACLS + {NET_IP_PORT_ACL_GID, "ip_port_acl_gid", + &sysctl_port_acl_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif +#ifdef CONFIG_SOCK_RAW_GROUP + {NET_IP_SOCK_RAW_GID, "ip_sock_raw_gid", + &sysctl_sock_raw_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif {0} }; diff -Nurd linux-orig/net/packet/af_packet.c linux/net/packet/af_packet.c --- linux-orig/net/packet/af_packet.c Fri Dec 21 09:42:06 2001 +++ linux/net/packet/af_packet.c Fri Dec 21 18:19:03 2001 @@ -83,6 +83,14 @@ #define CONFIG_SOCK_PACKET 1 +#ifdef CONFIG_SOCK_RAW_GROUP +#ifdef CONFIG_SOCK_PACKET_GROUP +int sysctl_sock_packet_gid; +#else +extern int sysctl_sock_raw_gid; +#endif /* CONFIG_SOCK_PACKET_GROUP */ +#endif /* CONFIG_SOCK_RAW_GROUP */ + /* Proposed replacement for SIOC{ADD,DEL}MULTI and IFF_PROMISC, IFF_ALLMULTI flags. @@ -938,7 +946,15 @@ struct sock *sk; int err; - if (!capable(CAP_NET_RAW)) + if (!capable(CAP_NET_RAW) +#ifdef CONFIG_SOCK_RAW_GROUP +#ifdef CONFIG_SOCK_PACKET_GROUP + && current->egid != sysctl_sock_packet_gid +#else + && current->egid != sysctl_sock_raw_gid +#endif /* CONFIG_SOCK_PACKET_GROUP */ +#endif /* CONFIG_SOCK_RAW_GROUP */ + ) return -EPERM; if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW #ifdef CONFIG_SOCK_PACKET diff -Nurd linux-orig/net/sysctl_net.c linux/net/sysctl_net.c --- linux-orig/net/sysctl_net.c Thu Apr 19 08:38:50 2001 +++ linux/net/sysctl_net.c Fri Dec 21 18:19:03 2001 @@ -34,6 +34,10 @@ extern ctl_table tr_table[]; #endif +#ifdef CONFIG_SOCK_PACKET_GROUP +extern int sysctl_sock_packet_gid; +#endif + ctl_table net_table[] = { {NET_CORE, "core", NULL, 0, 0555, core_table}, #ifdef CONFIG_NET @@ -49,5 +53,9 @@ #ifdef CONFIG_TR {NET_TR, "token-ring", NULL, 0, 0555, tr_table}, #endif +#ifdef CONFIG_SOCK_PACKET_GROUP + {NET_IP_SOCK_PACKET_GID, "sock_packet_gid", + &sysctl_sock_packet_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif {0} };