net/ipv6/calipso.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-)
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.
Signed-off-by: Debin Zhu <mowenroot@163.com>
Signed-off-by: Bitao Ouyang <1985755126@qq.com>
---
net/ipv6/calipso.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
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;
--
mowenroot@163.com
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
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.
This patch fixes the issue by checking if inet6_sk(sk)
returns a NULL pointer before accessing pinet6.
Fixes: ceba1832b1b2("calipso: Set the calipso socket label to match the secattr.")
Signed-off-by: Debin Zhu <mowenroot@163.com>
Signed-off-by: Bitao Ouyang <1985755126@qq.com>
Acked-by: Paul Moore <paul@paul-moore.com>
---
net/ipv6/calipso.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
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;
--
2.34.1
On Tue, Apr 01, 2025 at 08:40:18PM +0800, Debin Zhu wrote:
> 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.
>
> This patch fixes the issue by checking if inet6_sk(sk)
> returns a NULL pointer before accessing pinet6.
>
> Fixes: ceba1832b1b2("calipso: Set the calipso socket label to match the secattr.")
There is probably no need to repost for this, but
there is a missing space in the Fixes tag. It should be like this:
Fixes: ceba1832b1b2 ("calipso: Set the calipso socket label to match the secattr.")
> Signed-off-by: Debin Zhu <mowenroot@163.com>
> Signed-off-by: Bitao Ouyang <1985755126@qq.com>
> Acked-by: Paul Moore <paul@paul-moore.com>
...
On Wed, Apr 2, 2025 at 5:36 AM Simon Horman <horms@kernel.org> wrote:
> On Tue, Apr 01, 2025 at 08:40:18PM +0800, Debin Zhu wrote:
> > 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.
> >
> > This patch fixes the issue by checking if inet6_sk(sk)
> > returns a NULL pointer before accessing pinet6.
> >
> > Fixes: ceba1832b1b2("calipso: Set the calipso socket label to match the secattr.")
>
> There is probably no need to repost for this, but
> there is a missing space in the Fixes tag. It should be like this:
>
> Fixes: ceba1832b1b2 ("calipso: Set the calipso socket label to match the secattr.")
Thanks.
Not sure if the netdev folks are going to pick this up or if I'll end
up taking it, but if I end up taking it I'll update the tag while
merging.
> > Signed-off-by: Debin Zhu <mowenroot@163.com>
> > Signed-off-by: Bitao Ouyang <1985755126@qq.com>
> > Acked-by: Paul Moore <paul@paul-moore.com>
--
paul-moore.com
On Wed, 2 Apr 2025 14:28:40 -0400 Paul Moore wrote: > Not sure if the netdev folks are going to pick this up or if I'll end > up taking it, but if I end up taking it I'll update the tag while > merging. Fixed and applied to net, thanks!
On Tue, Apr 1, 2025 at 8:40 AM Debin Zhu <mowenroot@163.com> wrote:
>
> 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.
>
> This patch fixes the issue by checking if inet6_sk(sk)
> returns a NULL pointer before accessing pinet6.
>
> Fixes: ceba1832b1b2("calipso: Set the calipso socket label to match the secattr.")
> Signed-off-by: Debin Zhu <mowenroot@163.com>
> Signed-off-by: Bitao Ouyang <1985755126@qq.com>
> Acked-by: Paul Moore <paul@paul-moore.com>
As a FYI in case people aren't seeing the previous messages in this
thread, I did ACK an earlier version of this patch, and while there
have been some changes to the code, they are largely superficial and
my ACK still applies.
The commit description looks okay to me. Paolo, do you plan to take
this via the netdev tree or would you like me to take this?
Regardless, the patch should also be marked for stable.
> ---
> net/ipv6/calipso.c | 23 +++++++++++++++++++----
> 1 file changed, 19 insertions(+), 4 deletions(-)
>
> 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;
>
> --
> 2.34.1
--
paul-moore.com
© 2016 - 2025 Red Hat, Inc.