* [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
@ 2023-02-24 10:58 Hangyu Hua
2023-02-24 12:06 ` Florian Westphal
0 siblings, 1 reply; 10+ messages in thread
From: Hangyu Hua @ 2023-02-24 10:58 UTC (permalink / raw)
To: borisp, john.fastabend, kuba, davem, edumazet, pabeni,
davejwatson, aviadye, ilyal, sd
Cc: netdev, linux-kernel, Hangyu Hua
ctx->crypto_send.info is not protected by lock_sock in
do_tls_getsockopt_conf(). A race condition between do_tls_getsockopt_conf()
and do_tls_setsockopt_conf() can cause a NULL point dereference or
use-after-free read when memcpy.
Fixes: 3c4d7559159b ("tls: kernel TLS support")
Signed-off-by: Hangyu Hua <hbh25y@gmail.com>
---
net/tls/tls_main.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 3735cb00905d..4956f5149b8e 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -374,6 +374,7 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
}
/* get user crypto info */
+ lock_sock(sk);
if (tx) {
crypto_info = &ctx->crypto_send.info;
cctx = &ctx->tx;
@@ -381,6 +382,7 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
crypto_info = &ctx->crypto_recv.info;
cctx = &ctx->rx;
}
+ release_sock(sk);
if (!TLS_CRYPTO_INFO_READY(crypto_info)) {
rc = -EBUSY;
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-24 10:58 [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf() Hangyu Hua
@ 2023-02-24 12:06 ` Florian Westphal
2023-02-24 18:55 ` Jakub Kicinski
0 siblings, 1 reply; 10+ messages in thread
From: Florian Westphal @ 2023-02-24 12:06 UTC (permalink / raw)
To: Hangyu Hua
Cc: borisp, john.fastabend, kuba, davem, edumazet, pabeni,
davejwatson, aviadye, ilyal, sd, netdev, linux-kernel
Hangyu Hua <hbh25y@gmail.com> wrote:
> ctx->crypto_send.info is not protected by lock_sock in
> do_tls_getsockopt_conf(). A race condition between do_tls_getsockopt_conf()
> and do_tls_setsockopt_conf() can cause a NULL point dereference or
> use-after-free read when memcpy.
Its good practice to quote the relevant parts of the splat here.
> Fixes: 3c4d7559159b ("tls: kernel TLS support")
> Signed-off-by: Hangyu Hua <hbh25y@gmail.com>
> ---
> net/tls/tls_main.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
> index 3735cb00905d..4956f5149b8e 100644
> --- a/net/tls/tls_main.c
> +++ b/net/tls/tls_main.c
> @@ -374,6 +374,7 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
> }
>
> /* get user crypto info */
> + lock_sock(sk);
> if (tx) {
> crypto_info = &ctx->crypto_send.info;
> cctx = &ctx->tx;
> @@ -381,6 +382,7 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
> crypto_info = &ctx->crypto_recv.info;
> cctx = &ctx->rx;
> }
> + release_sock(sk);
Could you elaborate how this fixes a UAF bug?
AFAIU do_tls_setsockopt_conf uses ctx-> as scratch space, but this means
that getsockopt can see partial states.
If so, can the setsockopt part be changed so that reads only see
consistent states?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-24 12:06 ` Florian Westphal
@ 2023-02-24 18:55 ` Jakub Kicinski
2023-02-24 20:22 ` Sabrina Dubroca
0 siblings, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2023-02-24 18:55 UTC (permalink / raw)
To: Hangyu Hua
Cc: Florian Westphal, borisp, john.fastabend, davem, edumazet, pabeni,
davejwatson, aviadye, ilyal, sd, netdev, linux-kernel
On Fri, 24 Feb 2023 13:06:06 +0100 Florian Westphal wrote:
> Hangyu Hua <hbh25y@gmail.com> wrote:
> > ctx->crypto_send.info is not protected by lock_sock in
> > do_tls_getsockopt_conf(). A race condition between do_tls_getsockopt_conf()
> > and do_tls_setsockopt_conf() can cause a NULL point dereference or
> > use-after-free read when memcpy.
>
> Its good practice to quote the relevant parts of the splat here.
Right, the bug and the fix seem completely bogus.
Please make sure the bugs are real and the fixes you sent actually
fix them.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-24 18:55 ` Jakub Kicinski
@ 2023-02-24 20:22 ` Sabrina Dubroca
2023-02-24 21:06 ` Jakub Kicinski
0 siblings, 1 reply; 10+ messages in thread
From: Sabrina Dubroca @ 2023-02-24 20:22 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Hangyu Hua, Florian Westphal, borisp, john.fastabend, davem,
edumazet, pabeni, davejwatson, aviadye, ilyal, netdev,
linux-kernel
2023-02-24, 10:55:08 -0800, Jakub Kicinski wrote:
> On Fri, 24 Feb 2023 13:06:06 +0100 Florian Westphal wrote:
> > Hangyu Hua <hbh25y@gmail.com> wrote:
> > > ctx->crypto_send.info is not protected by lock_sock in
> > > do_tls_getsockopt_conf(). A race condition between do_tls_getsockopt_conf()
> > > and do_tls_setsockopt_conf() can cause a NULL point dereference or
> > > use-after-free read when memcpy.
> >
> > Its good practice to quote the relevant parts of the splat here.
>
> Right, the bug and the fix seem completely bogus.
> Please make sure the bugs are real and the fixes you sent actually
> fix them.
I suggested a change of locking in do_tls_getsockopt_conf this
morning [1]. The issue reported last seemed valid, but this patch is not
at all what I had in mind.
[1] https://lore.kernel.org/all/Y/ht6gQL+u6fj3dG@hog/
do_tls_setsockopt_conf fills crypto_info immediately from what
userspace gives us (and clears it on exit in case of failure), which
getsockopt could see since it's not locking the socket when it checks
TLS_CRYPTO_INFO_READY. So getsockopt would progress up to the point it
finally locks the socket, but if setsockopt failed, we could have
cleared TLS_CRYPTO_INFO_READY and freed iv/rec_seq.
--
Sabrina
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-24 20:22 ` Sabrina Dubroca
@ 2023-02-24 21:06 ` Jakub Kicinski
2023-02-24 21:48 ` Sabrina Dubroca
0 siblings, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2023-02-24 21:06 UTC (permalink / raw)
To: Sabrina Dubroca
Cc: Hangyu Hua, Florian Westphal, borisp, john.fastabend, davem,
edumazet, pabeni, davejwatson, aviadye, ilyal, netdev,
linux-kernel
On Fri, 24 Feb 2023 21:22:43 +0100 Sabrina Dubroca wrote:
> > Right, the bug and the fix seem completely bogus.
> > Please make sure the bugs are real and the fixes you sent actually
> > fix them.
>
> I suggested a change of locking in do_tls_getsockopt_conf this
> morning [1]. The issue reported last seemed valid, but this patch is not
> at all what I had in mind.
> [1] https://lore.kernel.org/all/Y/ht6gQL+u6fj3dG@hog/
Ack, I read the messages out of order, sorry.
> do_tls_setsockopt_conf fills crypto_info immediately from what
> userspace gives us (and clears it on exit in case of failure), which
> getsockopt could see since it's not locking the socket when it checks
> TLS_CRYPTO_INFO_READY. So getsockopt would progress up to the point it
> finally locks the socket, but if setsockopt failed, we could have
> cleared TLS_CRYPTO_INFO_READY and freed iv/rec_seq.
Makes sense. We should just take the socket lock around all of
do_tls_getsockopt(), then?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-24 21:06 ` Jakub Kicinski
@ 2023-02-24 21:48 ` Sabrina Dubroca
2023-02-24 22:17 ` Jakub Kicinski
0 siblings, 1 reply; 10+ messages in thread
From: Sabrina Dubroca @ 2023-02-24 21:48 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Hangyu Hua, Florian Westphal, borisp, john.fastabend, davem,
edumazet, pabeni, davejwatson, aviadye, ilyal, netdev,
linux-kernel
2023-02-24, 13:06:25 -0800, Jakub Kicinski wrote:
> On Fri, 24 Feb 2023 21:22:43 +0100 Sabrina Dubroca wrote:
> > > Right, the bug and the fix seem completely bogus.
> > > Please make sure the bugs are real and the fixes you sent actually
> > > fix them.
> >
> > I suggested a change of locking in do_tls_getsockopt_conf this
> > morning [1]. The issue reported last seemed valid, but this patch is not
> > at all what I had in mind.
> > [1] https://lore.kernel.org/all/Y/ht6gQL+u6fj3dG@hog/
>
> Ack, I read the messages out of order, sorry.
>
> > do_tls_setsockopt_conf fills crypto_info immediately from what
> > userspace gives us (and clears it on exit in case of failure), which
> > getsockopt could see since it's not locking the socket when it checks
> > TLS_CRYPTO_INFO_READY. So getsockopt would progress up to the point it
> > finally locks the socket, but if setsockopt failed, we could have
> > cleared TLS_CRYPTO_INFO_READY and freed iv/rec_seq.
>
> Makes sense. We should just take the socket lock around all of
> do_tls_getsockopt(), then?
That would make things simple and consistent. My idea was just taking
the existing lock_sock in do_tls_getsockopt_conf out of the switch and
put it just above TLS_CRYPTO_INFO_READY.
While we're at it, should we move the
ctx->prot_info.version != TLS_1_3_VERSION
check in do_tls_setsockopt_no_pad under lock_sock? I don't think that
can do anything wrong (we'd have to get past this check just before a
failing setsockopt clears crypto_info, and even then we're just
reading a bit from the context), it just looks a bit strange. Or just
lock the socket around all of do_tls_setsockopt_no_pad, like the other
options we have.
--
Sabrina
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-24 21:48 ` Sabrina Dubroca
@ 2023-02-24 22:17 ` Jakub Kicinski
2023-02-27 3:26 ` Hangyu Hua
0 siblings, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2023-02-24 22:17 UTC (permalink / raw)
To: Sabrina Dubroca
Cc: Hangyu Hua, Florian Westphal, borisp, john.fastabend, davem,
edumazet, pabeni, davejwatson, aviadye, ilyal, netdev,
linux-kernel
On Fri, 24 Feb 2023 22:48:57 +0100 Sabrina Dubroca wrote:
> 2023-02-24, 13:06:25 -0800, Jakub Kicinski wrote:
> > On Fri, 24 Feb 2023 21:22:43 +0100 Sabrina Dubroca wrote:
> [...]
> > >
> > > I suggested a change of locking in do_tls_getsockopt_conf this
> > > morning [1]. The issue reported last seemed valid, but this patch is not
> > > at all what I had in mind.
> > > [1] https://lore.kernel.org/all/Y/ht6gQL+u6fj3dG@hog/
> >
> > Ack, I read the messages out of order, sorry.
> >
> > > do_tls_setsockopt_conf fills crypto_info immediately from what
> > > userspace gives us (and clears it on exit in case of failure), which
> > > getsockopt could see since it's not locking the socket when it checks
> > > TLS_CRYPTO_INFO_READY. So getsockopt would progress up to the point it
> > > finally locks the socket, but if setsockopt failed, we could have
> > > cleared TLS_CRYPTO_INFO_READY and freed iv/rec_seq.
> >
> > Makes sense. We should just take the socket lock around all of
> > do_tls_getsockopt(), then?
>
> That would make things simple and consistent. My idea was just taking
> the existing lock_sock in do_tls_getsockopt_conf out of the switch and
> put it just above TLS_CRYPTO_INFO_READY.
>
> While we're at it, should we move the
>
> ctx->prot_info.version != TLS_1_3_VERSION
>
> check in do_tls_setsockopt_no_pad under lock_sock?
Yes, or READ_ONCE(), same for do_tls_getsockopt_tx_zc() and its access
on ctx->zerocopy_sendfile.
> I don't think that
> can do anything wrong (we'd have to get past this check just before a
> failing setsockopt clears crypto_info, and even then we're just
> reading a bit from the context), it just looks a bit strange. Or just
> lock the socket around all of do_tls_setsockopt_no_pad, like the other
> options we have.
The delayed locking feels like a premature optimization, we'll keep
having such issues with new options. Hence my vote to lock all of
do_tls_getsockopt().
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-24 22:17 ` Jakub Kicinski
@ 2023-02-27 3:26 ` Hangyu Hua
2023-02-27 19:07 ` Jakub Kicinski
0 siblings, 1 reply; 10+ messages in thread
From: Hangyu Hua @ 2023-02-27 3:26 UTC (permalink / raw)
To: Jakub Kicinski, Sabrina Dubroca
Cc: Florian Westphal, borisp, john.fastabend, davem, edumazet, pabeni,
davejwatson, aviadye, ilyal, netdev, linux-kernel
On 25/2/2023 06:17, Jakub Kicinski wrote:
> On Fri, 24 Feb 2023 22:48:57 +0100 Sabrina Dubroca wrote:
>> 2023-02-24, 13:06:25 -0800, Jakub Kicinski wrote:
>>> On Fri, 24 Feb 2023 21:22:43 +0100 Sabrina Dubroca wrote:
>> [...]
>>>>
>>>> I suggested a change of locking in do_tls_getsockopt_conf this
>>>> morning [1]. The issue reported last seemed valid, but this patch is not
>>>> at all what I had in mind.
>>>> [1] https://lore.kernel.org/all/Y/ht6gQL+u6fj3dG@hog/
>>>
>>> Ack, I read the messages out of order, sorry.
>>>
>>>> do_tls_setsockopt_conf fills crypto_info immediately from what
>>>> userspace gives us (and clears it on exit in case of failure), which
>>>> getsockopt could see since it's not locking the socket when it checks
>>>> TLS_CRYPTO_INFO_READY. So getsockopt would progress up to the point it
>>>> finally locks the socket, but if setsockopt failed, we could have
>>>> cleared TLS_CRYPTO_INFO_READY and freed iv/rec_seq.
>>>
>>> Makes sense. We should just take the socket lock around all of
>>> do_tls_getsockopt(), then?
>>
>> That would make things simple and consistent. My idea was just taking
>> the existing lock_sock in do_tls_getsockopt_conf out of the switch and
>> put it just above TLS_CRYPTO_INFO_READY.
I know what you mean. I just think lock crypto_info can fix this simply.
The original situation is:
thread1 thread2(do_tls_getsockopt_conf)
lock_sock(sk)
do_tls_setsockopt_conf(crypto_info->cipher_type set)
crypto_info = xxx
cctx = &ctx->tx
if(!TLS_CRYPTO_INFO_READY(crypto_info))
tls_set_device_offload(kmalloc cctx->iv)
tls_set_sw_offload(fail and cctx->iv may not set to NULL)
do_tls_setsockopt_conf(set crypto_info->cipher_type to NULL)
release_sock(sk)
lock_sock(sk)
memcpy(xxx, cctx->iv, xxx)
release_sock(sk)
If we lock crypto_info:
thread1 thread2(do_tls_getsockopt_conf)
lock_sock(sk)
do_tls_setsockopt_conf(crypto_info->cipher_type set)
tls_set_device_offload(kmalloc cctx->iv)
tls_set_sw_offload(fail and cctx->iv may not set to NULL)
do_tls_setsockopt_conf(set crypto_info->cipher_type to NULL)
release_sock(sk)
lock_sock(sk)
crypto_info = xxx
cctx = &ctx->tx
release_sock(sk)
if(!TLS_CRYPTO_INFO_READY(crypto_info))
lock_sock(sk)
memcpy(xxx, cctx->iv, xxx)
release_sock(sk)
>>
>> While we're at it, should we move the
>>
>> ctx->prot_info.version != TLS_1_3_VERSION
>>
>> check in do_tls_setsockopt_no_pad under lock_sock?
>
> Yes, or READ_ONCE(), same for do_tls_getsockopt_tx_zc() and its access
> on ctx->zerocopy_sendfile.
>
>> I don't think that
>> can do anything wrong (we'd have to get past this check just before a
>> failing setsockopt clears crypto_info, and even then we're just
>> reading a bit from the context), it just looks a bit strange. Or just
>> lock the socket around all of do_tls_setsockopt_no_pad, like the other
>> options we have.
>
> The delayed locking feels like a premature optimization, we'll keep
> having such issues with new options. Hence my vote to lock all of
> do_tls_getsockopt().
In order to reduce ambiguity, I think it may be a good idea only to
lock do_tls_getsockopt_conf() like we did in do_tls_setsockopt()
It will look like:
static int do_tls_getsockopt(struct sock *sk, int optname,
char __user *optval, int __user *optlen)
{
int rc = 0;
switch (optname) {
case TLS_TX:
case TLS_RX:
+ lock_sock(sk);
rc = do_tls_getsockopt_conf(sk, optval, optlen,
optname == TLS_TX);
+ release_sock(sk);
break;
case TLS_TX_ZEROCOPY_RO:
rc = do_tls_getsockopt_tx_zc(sk, optval, optlen);
break;
case TLS_RX_EXPECT_NO_PAD:
rc = do_tls_getsockopt_no_pad(sk, optval, optlen);
break;
default:
rc = -ENOPROTOOPT;
break;
}
return rc;
}
Of cause, I will clean the lock in do_tls_getsockopt_conf(). What do you
guys think?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-27 3:26 ` Hangyu Hua
@ 2023-02-27 19:07 ` Jakub Kicinski
2023-02-28 1:48 ` Hangyu Hua
0 siblings, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2023-02-27 19:07 UTC (permalink / raw)
To: Hangyu Hua
Cc: Sabrina Dubroca, Florian Westphal, borisp, john.fastabend, davem,
edumazet, pabeni, davejwatson, aviadye, ilyal, netdev,
linux-kernel
On Mon, 27 Feb 2023 11:26:18 +0800 Hangyu Hua wrote:
> In order to reduce ambiguity, I think it may be a good idea only to
> lock do_tls_getsockopt_conf() like we did in do_tls_setsockopt()
>
> It will look like:
>
> static int do_tls_getsockopt(struct sock *sk, int optname,
> char __user *optval, int __user *optlen)
> {
> int rc = 0;
>
> switch (optname) {
> case TLS_TX:
> case TLS_RX:
> + lock_sock(sk);
> rc = do_tls_getsockopt_conf(sk, optval, optlen,
> optname == TLS_TX);
> + release_sock(sk);
> break;
> case TLS_TX_ZEROCOPY_RO:
> rc = do_tls_getsockopt_tx_zc(sk, optval, optlen);
> break;
> case TLS_RX_EXPECT_NO_PAD:
> rc = do_tls_getsockopt_no_pad(sk, optval, optlen);
> break;
> default:
> rc = -ENOPROTOOPT;
> break;
> }
> return rc;
> }
>
> Of cause, I will clean the lock in do_tls_getsockopt_conf(). What do you
> guys think?
I'd suggest to take the lock around the entire switch statement.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf()
2023-02-27 19:07 ` Jakub Kicinski
@ 2023-02-28 1:48 ` Hangyu Hua
0 siblings, 0 replies; 10+ messages in thread
From: Hangyu Hua @ 2023-02-28 1:48 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Sabrina Dubroca, Florian Westphal, borisp, john.fastabend, davem,
edumazet, pabeni, davejwatson, aviadye, ilyal, netdev,
linux-kernel
On 28/2/2023 03:07, Jakub Kicinski wrote:
> On Mon, 27 Feb 2023 11:26:18 +0800 Hangyu Hua wrote:
>> In order to reduce ambiguity, I think it may be a good idea only to
>> lock do_tls_getsockopt_conf() like we did in do_tls_setsockopt()
>>
>> It will look like:
>>
>> static int do_tls_getsockopt(struct sock *sk, int optname,
>> char __user *optval, int __user *optlen)
>> {
>> int rc = 0;
>>
>> switch (optname) {
>> case TLS_TX:
>> case TLS_RX:
>> + lock_sock(sk);
>> rc = do_tls_getsockopt_conf(sk, optval, optlen,
>> optname == TLS_TX);
>> + release_sock(sk);
>> break;
>> case TLS_TX_ZEROCOPY_RO:
>> rc = do_tls_getsockopt_tx_zc(sk, optval, optlen);
>> break;
>> case TLS_RX_EXPECT_NO_PAD:
>> rc = do_tls_getsockopt_no_pad(sk, optval, optlen);
>> break;
>> default:
>> rc = -ENOPROTOOPT;
>> break;
>> }
>> return rc;
>> }
>>
>> Of cause, I will clean the lock in do_tls_getsockopt_conf(). What do you
>> guys think?
>
> I'd suggest to take the lock around the entire switch statement.
I get it. I will send a v2 later.
Thanks,
Hangyu
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-02-28 1:48 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-02-24 10:58 [PATCH] net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf() Hangyu Hua
2023-02-24 12:06 ` Florian Westphal
2023-02-24 18:55 ` Jakub Kicinski
2023-02-24 20:22 ` Sabrina Dubroca
2023-02-24 21:06 ` Jakub Kicinski
2023-02-24 21:48 ` Sabrina Dubroca
2023-02-24 22:17 ` Jakub Kicinski
2023-02-27 3:26 ` Hangyu Hua
2023-02-27 19:07 ` Jakub Kicinski
2023-02-28 1:48 ` Hangyu Hua
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).