Message ID | 20250330104039.31595-1-mowenroot@163.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [v2] netlabel: Fix NULL pointer exception caused by CALIPSO on IPv4 sockets | expand |
On 3/30/25 12:40 PM, Debin Zhu wrote: > Vulnerability Description: > > From Linux Kernel v4.0 to the latest version, > a type confusion issue exists in the `netlbl_conn_setattr` > function (`net/netlabel/netlabel_kapi.c`) within SELinux, > which can lead to a local DoS attack. > > When calling `netlbl_conn_setattr`, > `addr->sa_family` is used to determine the function behavior. > If `sk` is an IPv4 socket, > but the `connect` function is called with an IPv6 address, > the function `calipso_sock_setattr()` is triggered. > Inside this function, the following code is executed: > > sk_fullsock(__sk) ? inet_sk(__sk)->pinet6 : NULL; > > Since `sk` is an IPv4 socket, `pinet6` is `NULL`, > leading to a null pointer dereference and triggering a DoS attack. > > <TASK> > calipso_sock_setattr+0x4f/0x80 net/netlabel/netlabel_calipso.c:557 > netlbl_conn_setattr+0x12a/0x390 net/netlabel/netlabel_kapi.c:1152 > selinux_netlbl_socket_connect_helper > selinux_netlbl_socket_connect_locked+0xf5/0x1d0 > selinux_netlbl_socket_connect+0x22/0x40 security/selinux/netlabel.c:611 > selinux_socket_connect+0x60/0x80 security/selinux/hooks.c:4923 > security_socket_connect+0x71/0xb0 security/security.c:2260 > __sys_connect_file+0xa4/0x190 net/socket.c:2007 > __sys_connect+0x145/0x170 net/socket.c:2028 > __do_sys_connect net/socket.c:2038 [inline] > __se_sys_connect net/socket.c:2035 [inline] > __x64_sys_connect+0x6e/0xb0 net/socket.c:2035 > do_syscall_x64 arch/x86/entry/common.c:51 > > Affected Versions: > > - Linux 4.0 - Latest Linux Kernel version > > Reproduction Steps: > > Use the `netlabelctl` tool and > run the following commands to trigger the vulnerability: > > netlabelctl map del default > netlabelctl cipsov4 add pass doi:8 tags:1 > netlabelctl map add default address:192.168.1.0/24 protocol:cipsov4,8 > netlabelctl calipso add pass doi:7 > netlabelctl map add default address:2001:db8::1/32 protocol:calipso,7 > > Then, execute the following PoC code: > > int sockfd = socket(AF_INET, SOCK_STREAM, 0); > > struct sockaddr_in6 server_addr = {0}; > server_addr.sin6_family = AF_INET6; > server_addr.sin6_port = htons(8080); > > const char *ipv6_str = "2001:db8::1"; > inet_pton(AF_INET6, ipv6_str, &server_addr.sin6_addr); > > connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); > > Suggested Fix: > > When using an IPv4 address on an IPv6 UDP/datagram socket, > the operation will invoke the IPv4 datagram code through > the IPv6 datagram code and execute successfully. > It is necessary to check whether the `pinet6` pointer > returned by `inet6_sk()` is NULL; otherwise, > unexpected issues may occur. The fix makes sense to me, but the commit message could use a significant rewrite, avoiding the formatting and 'splitting' it in several 'sections' with 'headers'. The 'Affected Versions:' info is irrelevant, instead please include a suitable 'Fixes:' tag, like: Fixes: ceba1832b1b2 ("calipso: Set the calipso socket label to match the secattr.") and Paul's ack. Thanks, Paolo
diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c index dbcea9fee..a8a8736df 100644 --- a/net/ipv6/calipso.c +++ b/net/ipv6/calipso.c @@ -1072,8 +1072,13 @@ static int calipso_sock_getattr(struct sock *sk, struct ipv6_opt_hdr *hop; int opt_len, len, ret_val = -ENOMSG, offset; unsigned char *opt; - struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk)); + struct ipv6_pinfo *pinfo = inet6_sk(sk); + struct ipv6_txoptions *txopts; + if (!pinfo) + return -EAFNOSUPPORT; + + txopts = txopt_get(pinfo); if (!txopts || !txopts->hopopt) goto done; @@ -1125,8 +1130,13 @@ static int calipso_sock_setattr(struct sock *sk, { int ret_val; struct ipv6_opt_hdr *old, *new; - struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk)); - + struct ipv6_pinfo *pinfo = inet6_sk(sk); + struct ipv6_txoptions *txopts; + + if (!pinfo) + return -EAFNOSUPPORT; + + txopts = txopt_get(pinfo); old = NULL; if (txopts) old = txopts->hopopt; @@ -1153,8 +1163,13 @@ static int calipso_sock_setattr(struct sock *sk, static void calipso_sock_delattr(struct sock *sk) { struct ipv6_opt_hdr *new_hop; - struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk)); + struct ipv6_pinfo *pinfo = inet6_sk(sk); + struct ipv6_txoptions *txopts; + if (!pinfo) + return; + + txopts = txopt_get(pinfo); if (!txopts || !txopts->hopopt) goto done;