diff -urN linux-2.4.30-pre2/Documentation/Configure.help linux-2.4.30-pre2-pspa/Documentation/Configure.help --- linux-2.4.30-pre2/Documentation/Configure.help Mon Jan 31 22:01:10 2005 +++ linux-2.4.30-pre2-pspa/Documentation/Configure.help Sun Mar 6 11:39:11 2005 @@ -3683,6 +3683,73 @@ 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 (tcp/udp 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]/ip_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 the 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://killa.net/infosec/acls/index.htm + +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://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/core/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. + + For more info, check http://killa.net/infosec/acls/index.html + # Choice: alphatype Alpha system type CONFIG_ALPHA_GENERIC diff -urN linux-2.4.30-pre2/include/linux/sysctl.h linux-2.4.30-pre2-pspa/include/linux/sysctl.h --- linux-2.4.30-pre2/include/linux/sysctl.h Sat Mar 5 22:47:01 2005 +++ linux-2.4.30-pre2-pspa/include/linux/sysctl.h Sun Mar 6 11:40:52 2005 @@ -224,6 +224,7 @@ NET_CORE_MOD_CONG=16, NET_CORE_DEV_WEIGHT=17, NET_CORE_SOMAXCONN=18, + NET_CORE_SOCK_PACKET_GID=19, }; /* /proc/sys/net/ethernet */ @@ -327,6 +328,8 @@ NET_TCP_DEFAULT_WIN_SCALE=105, NET_TCP_MODERATE_RCVBUF=106, NET_TCP_BIC_BETA=108, + NET_IPV4_PORT_ACL_GID=109, + NET_IPV4_SOCK_RAW_GID=110, }; enum { @@ -430,7 +433,9 @@ NET_IPV6_DAD_TRANSMITS=7, NET_IPV6_RTR_SOLICITS=8, NET_IPV6_RTR_SOLICIT_INTERVAL=9, - NET_IPV6_RTR_SOLICIT_DELAY=10 + NET_IPV6_RTR_SOLICIT_DELAY=10, + NET_IPV6_PORT_ACL_GID=11, + NET_IPV6_SOCK_RAW_GID=12 }; /* /proc/sys/net/ipv6/icmp */ diff -urN linux-2.4.30-pre2/net/Config.in linux-2.4.30-pre2-pspa/net/Config.in --- linux-2.4.30-pre2/net/Config.in Mon Jan 31 22:01:10 2005 +++ linux-2.4.30-pre2-pspa/net/Config.in Sun Mar 6 11:39:11 2005 @@ -15,6 +15,26 @@ bool ' Network packet filtering debugging' CONFIG_NETFILTER_DEBUG fi bool 'Socket Filtering' CONFIG_FILTER + +#mainmenu_option next_comment +#comment 'Port/Socket Pseudo ACLs' +if [ "$CONFIG_SYSCTL" = "y" ] +then + bool 'Port/Socket Pseudo ACLs' CONFIG_PSEUDO_ACLS + if [ "$CONFIG_PSEUDO_ACLS" = "y" ]; then + bool ' Port ACLs' CONFIG_PORT_ACLS + bool ' 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 +#endmenu + tristate 'Unix domain sockets' CONFIG_UNIX bool 'TCP/IP networking' CONFIG_INET if [ "$CONFIG_INET" = "y" ]; then @@ -103,5 +123,6 @@ comment 'Network testing' dep_tristate 'Packet Generator (USE WITH CAUTION)' CONFIG_NET_PKTGEN $CONFIG_PROC_FS endmenu + endmenu diff -urN linux-2.4.30-pre2/net/core/sysctl_net_core.c linux-2.4.30-pre2-pspa/net/core/sysctl_net_core.c --- linux-2.4.30-pre2/net/core/sysctl_net_core.c Fri Feb 20 07:38:35 2004 +++ linux-2.4.30-pre2-pspa/net/core/sysctl_net_core.c Sun Mar 6 11:39:11 2005 @@ -35,6 +35,10 @@ extern char sysctl_divert_version[]; #endif /* CONFIG_NET_DIVERT */ +#ifdef CONFIG_SOCK_PACKET_GROUP +extern int sysctl_sock_packet_gid; +#endif /* CONFIG_SOCK_PACKET_GROUP */ + ctl_table core_table[] = { #ifdef CONFIG_NET {NET_CORE_WMEM_MAX, "wmem_max", @@ -89,6 +93,11 @@ (void *)sysctl_divert_version, 32, 0444, NULL, &proc_dostring}, #endif /* CONFIG_NET_DIVERT */ +#ifdef CONFIG_SOCK_PACKET_GROUP + {NET_CORE_SOCK_PACKET_GID, "sock_packet_gid", + &sysctl_sock_packet_gid, sizeof(int), 0644, NULL, + &proc_dointvec}, +#endif /* CONFIG_SOCK_PACKET_GROUP */ {NET_CORE_SOMAXCONN, "somaxconn", &sysctl_somaxconn, sizeof(int), 0644, NULL, &proc_dointvec }, diff -urN linux-2.4.30-pre2/net/ipv4/af_inet.c linux-2.4.30-pre2-pspa/net/ipv4/af_inet.c --- linux-2.4.30-pre2/net/ipv4/af_inet.c Sun Dec 19 21:18:28 2004 +++ linux-2.4.30-pre2-pspa/net/ipv4/af_inet.c Sun Mar 6 11:39:11 2005 @@ -147,6 +147,14 @@ int (*vlan_ioctl_hook)(unsigned long arg); #endif +#ifdef CONFIG_PORT_ACLS +int sysctl_ipv4_port_acl_gid; +#endif /* CONFIG_PORT_ACLS */ + +#ifdef CONFIG_SOCK_RAW_GROUP +int sysctl_ipv4_sock_raw_gid; +#endif /* CONFIG_SOCK_RAW_GROUP */ + /* The inetsw table contains everything that inet_create needs to * build a new socket. */ @@ -352,7 +360,12 @@ 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_ipv4_sock_raw_gid)) +#endif /*CONFIG_SOCK_RAW_GROUP */ + ) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -503,7 +516,12 @@ 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_ipv4_port_acl_gid)) +#endif /* CONFIG_PORT_ACLS */ + ) return -EACCES; /* We keep a pair of addresses. rcv_saddr is the one diff -urN linux-2.4.30-pre2/net/ipv4/sysctl_net_ipv4.c linux-2.4.30-pre2-pspa/net/ipv4/sysctl_net_ipv4.c --- linux-2.4.30-pre2/net/ipv4/sysctl_net_ipv4.c Sat Mar 5 22:47:01 2005 +++ linux-2.4.30-pre2-pspa/net/ipv4/sysctl_net_ipv4.c Sun Mar 6 11:39:11 2005 @@ -60,6 +60,14 @@ extern ctl_table ipv4_route_table[]; +#ifdef CONFIG_PORT_ACLS +extern int sysctl_ipv4_port_acl_gid; +#endif /* CONFIG_PORT_ACLS */ + +#ifdef CONFIG_SOCK_RAW_GROUP +extern int sysctl_ipv4_sock_raw_gid; +#endif /* CONFIG_SOCK_RAW_GROUP */ + #ifdef CONFIG_SYSCTL static @@ -271,6 +279,14 @@ {NET_TCP_BIC_BETA, "tcp_bic_beta", &sysctl_tcp_bic_beta, sizeof(int), 0644, NULL, &proc_dointvec}, +#ifdef CONFIG_PORT_ACLS + {NET_IPV4_PORT_ACL_GID, "ip_port_acl_gid", + &sysctl_ipv4_port_acl_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif /*CONFIG_PORT_ACLS */ +#ifdef CONFIG_SOCK_RAW_GROUP + {NET_IPV4_SOCK_RAW_GID, "ip_sock_raw_gid", + &sysctl_ipv4_sock_raw_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif /* CONFIG_SOCK_RAW_GROUP */ {0} }; diff -urN linux-2.4.30-pre2/net/ipv6/af_inet6.c linux-2.4.30-pre2-pspa/net/ipv6/af_inet6.c --- linux-2.4.30-pre2/net/ipv6/af_inet6.c Sun Dec 19 21:18:28 2004 +++ linux-2.4.30-pre2-pspa/net/ipv6/af_inet6.c Sun Mar 6 11:39:11 2005 @@ -73,6 +73,14 @@ MODULE_PARM(unloadable, "i"); #endif +#ifdef CONFIG_PORT_ACLS +int sysctl_ipv6_port_acl_gid; +#endif /* CONFIG_PORT_ACLS */ + +#ifdef CONFIG_SOCK_RAW_GROUP +int sysctl_ipv6_sock_raw_gid; +#endif /* CONFIG_SOCK_RAW_GROUP */ + /* IPv6 procfs goodies... */ #ifdef CONFIG_PROC_FS @@ -145,7 +153,12 @@ 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_ipv6_sock_raw_gid)) +#endif /* CONFIG_SOCK_RAW_GROUP */ + ) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -270,7 +283,12 @@ } 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_ipv6_port_acl_gid)) +#endif /* CONFIG_PORT_ACLS */ + ) return -EACCES; lock_sock(sk); diff -urN linux-2.4.30-pre2/net/ipv6/sysctl_net_ipv6.c linux-2.4.30-pre2-pspa/net/ipv6/sysctl_net_ipv6.c --- linux-2.4.30-pre2/net/ipv6/sysctl_net_ipv6.c Sat Mar 20 10:08:21 2004 +++ linux-2.4.30-pre2-pspa/net/ipv6/sysctl_net_ipv6.c Sun Mar 6 11:39:11 2005 @@ -17,6 +17,14 @@ extern ctl_table ipv6_route_table[]; extern ctl_table ipv6_icmp_table[]; +#ifdef CONFIG_PORT_ACLS +extern int sysctl_ipv6_port_acl_gid; +#endif /* CONFIG_PORT_ACLS */ + +#ifdef CONFIG_SOCK_RAW_GROUP +extern int sysctl_ipv6_sock_raw_gid; +#endif /* CONFIG_SOCK_RAW_GROUP */ + #ifdef CONFIG_SYSCTL ctl_table ipv6_table[] = { @@ -26,6 +34,14 @@ &sysctl_ipv6_bindv6only, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV6_MLD_MAX_MSF, "mld_max_msf", &sysctl_mld_max_msf, sizeof(int), 0644, NULL, &proc_dointvec}, +#ifdef CONFIG_PORT_ACLS + {NET_IPV6_PORT_ACL_GID, "ip_port_acl_gid", + &sysctl_ipv6_port_acl_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif /* CONFIG_PORT_ACLS */ +#ifdef CONFIG_SOCK_RAW_GROUP + {NET_IPV6_SOCK_RAW_GID, "ip_sock_raw_gid", + &sysctl_ipv6_sock_raw_gid, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif /* CONFIG_SOCK_RAW_GROUP */ {0} }; diff -urN linux-2.4.30-pre2/net/packet/af_packet.c linux-2.4.30-pre2-pspa/net/packet/af_packet.c --- linux-2.4.30-pre2/net/packet/af_packet.c Sun Dec 12 12:06:28 2004 +++ linux-2.4.30-pre2-pspa/net/packet/af_packet.c Sun Mar 6 11:39:11 2005 @@ -85,6 +85,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. @@ -959,7 +967,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