* [PATCH] net: check the return value of the copy_from_sockptr
@ 2024-09-11 5:04 Qianqiang Liu
2024-09-11 6:51 ` D. Wythe
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Qianqiang Liu @ 2024-09-11 5:04 UTC (permalink / raw)
To: xiyou.wangcong, davem, edumazet, kuba, pabeni
Cc: netdev, linux-kernel, Qianqiang Liu
We must check the return value of the copy_from_sockptr. Otherwise, it
may cause some weird issues.
Signed-off-by: Qianqiang Liu <qianqiang.liu@163.com>
---
net/socket.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/socket.c b/net/socket.c
index 0a2bd22ec105..6b9a414d01d5 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2370,8 +2370,11 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level,
if (err)
return err;
- if (!compat)
- copy_from_sockptr(&max_optlen, optlen, sizeof(int));
+ if (!compat) {
+ err = copy_from_sockptr(&max_optlen, optlen, sizeof(int));
+ if (err)
+ return -EFAULT;
+ }
ops = READ_ONCE(sock->ops);
if (level == SOL_SOCKET) {
--
2.39.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 5:04 [PATCH] net: check the return value of the copy_from_sockptr Qianqiang Liu
@ 2024-09-11 6:51 ` D. Wythe
2024-09-11 7:13 ` Eric Dumazet
2024-09-18 13:11 ` David Laight
2 siblings, 0 replies; 16+ messages in thread
From: D. Wythe @ 2024-09-11 6:51 UTC (permalink / raw)
To: Qianqiang Liu, xiyou.wangcong, davem, edumazet, kuba, pabeni
Cc: netdev, linux-kernel
On 9/11/24 1:04 PM, Qianqiang Liu wrote:
> We must check the return value of the copy_from_sockptr. Otherwise, it
> may cause some weird issues.
>
> Signed-off-by: Qianqiang Liu <qianqiang.liu@163.com>
> ---
> net/socket.c | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
Looks like a fix patch, maybe you could add a fix tag.
> diff --git a/net/socket.c b/net/socket.c
> index 0a2bd22ec105..6b9a414d01d5 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -2370,8 +2370,11 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level,
> if (err)
> return err;
>
> - if (!compat)
> - copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> + if (!compat) {
> + err = copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> + if (err)
> + return -EFAULT;
> + }
>
> ops = READ_ONCE(sock->ops);
> if (level == SOL_SOCKET) {
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 5:04 [PATCH] net: check the return value of the copy_from_sockptr Qianqiang Liu
2024-09-11 6:51 ` D. Wythe
@ 2024-09-11 7:13 ` Eric Dumazet
2024-09-11 8:23 ` Qianqiang Liu
2024-09-18 13:11 ` David Laight
2 siblings, 1 reply; 16+ messages in thread
From: Eric Dumazet @ 2024-09-11 7:13 UTC (permalink / raw)
To: Qianqiang Liu; +Cc: xiyou.wangcong, davem, kuba, pabeni, netdev, linux-kernel
On Wed, Sep 11, 2024 at 7:06 AM Qianqiang Liu <qianqiang.liu@163.com> wrote:
>
> We must check the return value of the copy_from_sockptr. Otherwise, it
> may cause some weird issues.
What issues precisely ?
I do not think it matters, because the copy is performed later, with
all the needed checks.
eg :
if (copy_from_sockptr(&len, optlen, sizeof(int)))
return -EFAULT;
...
len = min_t(unsigned int, sizeof(int), len);
if (copy_to_sockptr(optlen, &len, sizeof(int)))
return -EFAULT;
if (copy_to_sockptr(optval, &val, len))
return -EFAULT;
return 0;
>
> Signed-off-by: Qianqiang Liu <qianqiang.liu@163.com>
> ---
> net/socket.c | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/net/socket.c b/net/socket.c
> index 0a2bd22ec105..6b9a414d01d5 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -2370,8 +2370,11 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level,
> if (err)
> return err;
>
> - if (!compat)
> - copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> + if (!compat) {
> + err = copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> + if (err)
> + return -EFAULT;
> + }
>
> ops = READ_ONCE(sock->ops);
> if (level == SOL_SOCKET) {
> --
> 2.39.2
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 7:13 ` Eric Dumazet
@ 2024-09-11 8:23 ` Qianqiang Liu
2024-09-11 9:12 ` Eric Dumazet
0 siblings, 1 reply; 16+ messages in thread
From: Qianqiang Liu @ 2024-09-11 8:23 UTC (permalink / raw)
To: Eric Dumazet; +Cc: xiyou.wangcong, davem, kuba, pabeni, netdev, linux-kernel
> I do not think it matters, because the copy is performed later, with
> all the needed checks.
No, there is no checks at all.
--
Best,
Qianqiang Liu
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 8:23 ` Qianqiang Liu
@ 2024-09-11 9:12 ` Eric Dumazet
2024-09-11 10:24 ` Qianqiang Liu
2024-09-11 16:58 ` Cong Wang
0 siblings, 2 replies; 16+ messages in thread
From: Eric Dumazet @ 2024-09-11 9:12 UTC (permalink / raw)
To: Qianqiang Liu; +Cc: xiyou.wangcong, davem, kuba, pabeni, netdev, linux-kernel
On Wed, Sep 11, 2024 at 10:23 AM Qianqiang Liu <qianqiang.liu@163.com> wrote:
>
> > I do not think it matters, because the copy is performed later, with
> > all the needed checks.
>
> No, there is no checks at all.
>
Please elaborate ?
Why should maintainers have to spend time to provide evidence to
support your claims ?
Have you thought about the (compat) case ?
There are plenty of checks. They were there before Stanislav commit.
Each getsockopt() handler must perform the same actions.
For instance, look at do_ipv6_getsockopt()
If you find one getsockopt() method failing to perform the checks,
please report to us.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 9:12 ` Eric Dumazet
@ 2024-09-11 10:24 ` Qianqiang Liu
2024-09-11 12:40 ` Eric Dumazet
2024-09-11 16:58 ` Cong Wang
1 sibling, 1 reply; 16+ messages in thread
From: Qianqiang Liu @ 2024-09-11 10:24 UTC (permalink / raw)
To: Eric Dumazet
Cc: Tze-nan.Wu, xiyou.wangcong, davem, kuba, pabeni, netdev,
linux-kernel
On Wed, Sep 11, 2024 at 11:12:24AM +0200, Eric Dumazet wrote:
> On Wed, Sep 11, 2024 at 10:23 AM Qianqiang Liu <qianqiang.liu@163.com> wrote:
> >
> > > I do not think it matters, because the copy is performed later, with
> > > all the needed checks.
> >
> > No, there is no checks at all.
> >
>
> Please elaborate ?
> Why should maintainers have to spend time to provide evidence to
> support your claims ?
> Have you thought about the (compat) case ?
>
> There are plenty of checks. They were there before Stanislav commit.
>
> Each getsockopt() handler must perform the same actions.
>
> For instance, look at do_ipv6_getsockopt()
>
> If you find one getsockopt() method failing to perform the checks,
> please report to us.
Sorry, let me explain a little bit.
The issue was introduced in this commit: 33f339a1ba54e ("bpf, net: Fix a
potential race in do_sock_getsockopt()")
diff --git a/net/socket.c b/net/socket.c
index fcbdd5bc47ac..0a2bd22ec105 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2362,7 +2362,7 @@ INDIRECT_CALLABLE_DECLARE(bool tcp_bpf_bypass_getsockopt(int level,
int do_sock_getsockopt(struct socket *sock, bool compat, int level,
int optname, sockptr_t optval, sockptr_t optlen)
{
- int max_optlen __maybe_unused;
+ int max_optlen __maybe_unused = 0;
const struct proto_ops *ops;
int err;
@@ -2371,7 +2371,7 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level,
return err;
if (!compat)
- max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen);
+ copy_from_sockptr(&max_optlen, optlen, sizeof(int));
ops = READ_ONCE(sock->ops);
if (level == SOL_SOCKET) {
The return value of "copy_from_sockptr()" in "do_sock_getsockopt()" was
not checked. So, I added the following patch:
diff --git a/net/socket.c b/net/socket.c
index 0a2bd22ec105..6b9a414d01d5 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2370,8 +2370,11 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level,
if (err)
return err;
- if (!compat)
- copy_from_sockptr(&max_optlen, optlen, sizeof(int));
+ if (!compat) {
+ err = copy_from_sockptr(&max_optlen, optlen, sizeof(int));
+ if (err)
+ return -EFAULT;
+ }
ops = READ_ONCE(sock->ops);
if (level == SOL_SOCKET) {
Maybe I missed something?
If you think it's not an issue, then I'm OK with it.
--
Best,
Qianqiang Liu
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 10:24 ` Qianqiang Liu
@ 2024-09-11 12:40 ` Eric Dumazet
0 siblings, 0 replies; 16+ messages in thread
From: Eric Dumazet @ 2024-09-11 12:40 UTC (permalink / raw)
To: Qianqiang Liu
Cc: Tze-nan.Wu, xiyou.wangcong, davem, kuba, pabeni, netdev,
linux-kernel
On Wed, Sep 11, 2024 at 1:14 PM Qianqiang Liu <qianqiang.liu@163.com> wrote:
>
> On Wed, Sep 11, 2024 at 11:12:24AM +0200, Eric Dumazet wrote:
> > On Wed, Sep 11, 2024 at 10:23 AM Qianqiang Liu <qianqiang.liu@163.com> wrote:
> > >
> > > > I do not think it matters, because the copy is performed later, with
> > > > all the needed checks.
> > >
> > > No, there is no checks at all.
> > >
> >
> > Please elaborate ?
> > Why should maintainers have to spend time to provide evidence to
> > support your claims ?
> > Have you thought about the (compat) case ?
> >
> > There are plenty of checks. They were there before Stanislav commit.
> >
> > Each getsockopt() handler must perform the same actions.
> >
> > For instance, look at do_ipv6_getsockopt()
> >
> > If you find one getsockopt() method failing to perform the checks,
> > please report to us.
>
> Sorry, let me explain a little bit.
>
> The issue was introduced in this commit: 33f339a1ba54e ("bpf, net: Fix a
> potential race in do_sock_getsockopt()")
Not really.
Code before this commit also ignored copy_from_sockptr() return code.
>
> diff --git a/net/socket.c b/net/socket.c
> index fcbdd5bc47ac..0a2bd22ec105 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -2362,7 +2362,7 @@ INDIRECT_CALLABLE_DECLARE(bool tcp_bpf_bypass_getsockopt(int level,
> int do_sock_getsockopt(struct socket *sock, bool compat, int level,
> int optname, sockptr_t optval, sockptr_t optlen)
> {
> - int max_optlen __maybe_unused;
> + int max_optlen __maybe_unused = 0;
> const struct proto_ops *ops;
> int err;
>
> @@ -2371,7 +2371,7 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level,
> return err;
>
> if (!compat)
> - max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen);
> + copy_from_sockptr(&max_optlen, optlen, sizeof(int));
>
> ops = READ_ONCE(sock->ops);
> if (level == SOL_SOCKET) {
>
> The return value of "copy_from_sockptr()" in "do_sock_getsockopt()" was
> not checked. So, I added the following patch:
>
> diff --git a/net/socket.c b/net/socket.c
> index 0a2bd22ec105..6b9a414d01d5 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -2370,8 +2370,11 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level,
> if (err)
> return err;
>
> - if (!compat)
> - copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> + if (!compat) {
> + err = copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> + if (err)
> + return -EFAULT;
> + }
>
> ops = READ_ONCE(sock->ops);
> if (level == SOL_SOCKET) {
>
> Maybe I missed something?
>
> If you think it's not an issue, then I'm OK with it.
It is not an issue, just adding extra code for an unlikely condition
that must be tested later anyway.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 9:12 ` Eric Dumazet
2024-09-11 10:24 ` Qianqiang Liu
@ 2024-09-11 16:58 ` Cong Wang
2024-09-11 17:15 ` Eric Dumazet
1 sibling, 1 reply; 16+ messages in thread
From: Cong Wang @ 2024-09-11 16:58 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Qianqiang Liu, davem, kuba, pabeni, netdev, linux-kernel
On Wed, Sep 11, 2024 at 11:12:24AM +0200, Eric Dumazet wrote:
> On Wed, Sep 11, 2024 at 10:23 AM Qianqiang Liu <qianqiang.liu@163.com> wrote:
> >
> > > I do not think it matters, because the copy is performed later, with
> > > all the needed checks.
> >
> > No, there is no checks at all.
> >
>
> Please elaborate ?
> Why should maintainers have to spend time to provide evidence to
> support your claims ?
> Have you thought about the (compat) case ?
>
> There are plenty of checks. They were there before Stanislav commit.
>
> Each getsockopt() handler must perform the same actions.
But in line 2379 we have ops->getsockopt==NULL case:
2373 if (!compat)
2374 copy_from_sockptr(&max_optlen, optlen, sizeof(int));
2375
2376 ops = READ_ONCE(sock->ops);
2377 if (level == SOL_SOCKET) {
2378 err = sk_getsockopt(sock->sk, level, optname, optval, optlen);
2379 } else if (unlikely(!ops->getsockopt)) {
2380 err = -EOPNOTSUPP; // <--- HERE
2381 } else {
2382 if (WARN_ONCE(optval.is_kernel || optlen.is_kernel,
2383 "Invalid argument type"))
2384 return -EOPNOTSUPP;
2385
2386 err = ops->getsockopt(sock, level, optname, optval.user,
2387 optlen.user);
2388 }
where we simply continue with calling BPF_CGROUP_RUN_PROG_GETSOCKOPT()
which actually needs the 'max_optlen' we copied via copy_from_sockptr().
Do I miss anything here?
Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 16:58 ` Cong Wang
@ 2024-09-11 17:15 ` Eric Dumazet
2024-09-11 17:35 ` Cong Wang
0 siblings, 1 reply; 16+ messages in thread
From: Eric Dumazet @ 2024-09-11 17:15 UTC (permalink / raw)
To: Cong Wang; +Cc: Qianqiang Liu, davem, kuba, pabeni, netdev, linux-kernel
On Wed, Sep 11, 2024 at 6:58 PM Cong Wang <xiyou.wangcong@gmail.com> wrote:
>
> On Wed, Sep 11, 2024 at 11:12:24AM +0200, Eric Dumazet wrote:
> > On Wed, Sep 11, 2024 at 10:23 AM Qianqiang Liu <qianqiang.liu@163.com> wrote:
> > >
> > > > I do not think it matters, because the copy is performed later, with
> > > > all the needed checks.
> > >
> > > No, there is no checks at all.
> > >
> >
> > Please elaborate ?
> > Why should maintainers have to spend time to provide evidence to
> > support your claims ?
> > Have you thought about the (compat) case ?
> >
> > There are plenty of checks. They were there before Stanislav commit.
> >
> > Each getsockopt() handler must perform the same actions.
>
>
> But in line 2379 we have ops->getsockopt==NULL case:
>
> 2373 if (!compat)
> 2374 copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> 2375
> 2376 ops = READ_ONCE(sock->ops);
> 2377 if (level == SOL_SOCKET) {
> 2378 err = sk_getsockopt(sock->sk, level, optname, optval, optlen);
> 2379 } else if (unlikely(!ops->getsockopt)) {
> 2380 err = -EOPNOTSUPP; // <--- HERE
> 2381 } else {
> 2382 if (WARN_ONCE(optval.is_kernel || optlen.is_kernel,
> 2383 "Invalid argument type"))
> 2384 return -EOPNOTSUPP;
> 2385
> 2386 err = ops->getsockopt(sock, level, optname, optval.user,
> 2387 optlen.user);
> 2388 }
>
> where we simply continue with calling BPF_CGROUP_RUN_PROG_GETSOCKOPT()
> which actually needs the 'max_optlen' we copied via copy_from_sockptr().
>
> Do I miss anything here?
This is another great reason why we should not change current behavior.
err will be -EOPNOTSUPP, which was the original error code before
Stanislav patch.
Surely the eBPF program will use this value first, and not even look
at max_optlen
Returning -EFAULT might break some user programs, I don't know.
I feel we are making the kernel slower just because we can.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 17:15 ` Eric Dumazet
@ 2024-09-11 17:35 ` Cong Wang
2024-09-11 18:49 ` Stanislav Fomichev
0 siblings, 1 reply; 16+ messages in thread
From: Cong Wang @ 2024-09-11 17:35 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Qianqiang Liu, davem, kuba, pabeni, netdev, linux-kernel
On Wed, Sep 11, 2024 at 07:15:27PM +0200, Eric Dumazet wrote:
> On Wed, Sep 11, 2024 at 6:58 PM Cong Wang <xiyou.wangcong@gmail.com> wrote:
> >
> > On Wed, Sep 11, 2024 at 11:12:24AM +0200, Eric Dumazet wrote:
> > > On Wed, Sep 11, 2024 at 10:23 AM Qianqiang Liu <qianqiang.liu@163.com> wrote:
> > > >
> > > > > I do not think it matters, because the copy is performed later, with
> > > > > all the needed checks.
> > > >
> > > > No, there is no checks at all.
> > > >
> > >
> > > Please elaborate ?
> > > Why should maintainers have to spend time to provide evidence to
> > > support your claims ?
> > > Have you thought about the (compat) case ?
> > >
> > > There are plenty of checks. They were there before Stanislav commit.
> > >
> > > Each getsockopt() handler must perform the same actions.
> >
> >
> > But in line 2379 we have ops->getsockopt==NULL case:
> >
> > 2373 if (!compat)
> > 2374 copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> > 2375
> > 2376 ops = READ_ONCE(sock->ops);
> > 2377 if (level == SOL_SOCKET) {
> > 2378 err = sk_getsockopt(sock->sk, level, optname, optval, optlen);
> > 2379 } else if (unlikely(!ops->getsockopt)) {
> > 2380 err = -EOPNOTSUPP; // <--- HERE
> > 2381 } else {
> > 2382 if (WARN_ONCE(optval.is_kernel || optlen.is_kernel,
> > 2383 "Invalid argument type"))
> > 2384 return -EOPNOTSUPP;
> > 2385
> > 2386 err = ops->getsockopt(sock, level, optname, optval.user,
> > 2387 optlen.user);
> > 2388 }
> >
> > where we simply continue with calling BPF_CGROUP_RUN_PROG_GETSOCKOPT()
> > which actually needs the 'max_optlen' we copied via copy_from_sockptr().
> >
> > Do I miss anything here?
>
> This is another great reason why we should not change current behavior.
Hm? But the current behavior is buggy?
>
> err will be -EOPNOTSUPP, which was the original error code before
> Stanislav patch.
You mean we should continue calling BPF_CGROUP_RUN_PROG_GETSOCKOPT()
despite -EFAULT?
>
> Surely the eBPF program will use this value first, and not even look
> at max_optlen
>
> Returning -EFAULT might break some user programs, I don't know.
As you mentioned above, other ->getsockopt() already returns -EFAULT, so
what is breaking? :)
>
> I feel we are making the kernel slower just because we can.
Safety and correctness also matter.
Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 17:35 ` Cong Wang
@ 2024-09-11 18:49 ` Stanislav Fomichev
2024-09-11 19:48 ` Cong Wang
0 siblings, 1 reply; 16+ messages in thread
From: Stanislav Fomichev @ 2024-09-11 18:49 UTC (permalink / raw)
To: Cong Wang
Cc: Eric Dumazet, Qianqiang Liu, davem, kuba, pabeni, netdev,
linux-kernel
On 09/11, Cong Wang wrote:
> On Wed, Sep 11, 2024 at 07:15:27PM +0200, Eric Dumazet wrote:
> > On Wed, Sep 11, 2024 at 6:58 PM Cong Wang <xiyou.wangcong@gmail.com> wrote:
> > >
> > > On Wed, Sep 11, 2024 at 11:12:24AM +0200, Eric Dumazet wrote:
> > > > On Wed, Sep 11, 2024 at 10:23 AM Qianqiang Liu <qianqiang.liu@163.com> wrote:
> > > > >
> > > > > > I do not think it matters, because the copy is performed later, with
> > > > > > all the needed checks.
> > > > >
> > > > > No, there is no checks at all.
> > > > >
> > > >
> > > > Please elaborate ?
> > > > Why should maintainers have to spend time to provide evidence to
> > > > support your claims ?
> > > > Have you thought about the (compat) case ?
> > > >
> > > > There are plenty of checks. They were there before Stanislav commit.
> > > >
> > > > Each getsockopt() handler must perform the same actions.
> > >
> > >
> > > But in line 2379 we have ops->getsockopt==NULL case:
> > >
> > > 2373 if (!compat)
> > > 2374 copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> > > 2375
> > > 2376 ops = READ_ONCE(sock->ops);
> > > 2377 if (level == SOL_SOCKET) {
> > > 2378 err = sk_getsockopt(sock->sk, level, optname, optval, optlen);
> > > 2379 } else if (unlikely(!ops->getsockopt)) {
> > > 2380 err = -EOPNOTSUPP; // <--- HERE
> > > 2381 } else {
> > > 2382 if (WARN_ONCE(optval.is_kernel || optlen.is_kernel,
> > > 2383 "Invalid argument type"))
> > > 2384 return -EOPNOTSUPP;
> > > 2385
> > > 2386 err = ops->getsockopt(sock, level, optname, optval.user,
> > > 2387 optlen.user);
> > > 2388 }
> > >
> > > where we simply continue with calling BPF_CGROUP_RUN_PROG_GETSOCKOPT()
> > > which actually needs the 'max_optlen' we copied via copy_from_sockptr().
> > >
> > > Do I miss anything here?
> >
> > This is another great reason why we should not change current behavior.
>
> Hm? But the current behavior is buggy?
>
> >
> > err will be -EOPNOTSUPP, which was the original error code before
> > Stanislav patch.
>
> You mean we should continue calling BPF_CGROUP_RUN_PROG_GETSOCKOPT()
> despite -EFAULT?
>
> >
> > Surely the eBPF program will use this value first, and not even look
> > at max_optlen
> >
> > Returning -EFAULT might break some user programs, I don't know.
>
> As you mentioned above, other ->getsockopt() already returns -EFAULT, so
> what is breaking? :)
>
> >
> > I feel we are making the kernel slower just because we can.
>
> Safety and correctness also matter.
Can you explain what is not correct?
Calling BPF_CGROUP_RUN_PROG_GETSOCKOPT with max_optlen=0 should not be
a problem I think? (the buffer simply won't be accessible to the bpf prog)
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 18:49 ` Stanislav Fomichev
@ 2024-09-11 19:48 ` Cong Wang
2024-09-11 20:05 ` Stanislav Fomichev
0 siblings, 1 reply; 16+ messages in thread
From: Cong Wang @ 2024-09-11 19:48 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: Eric Dumazet, Qianqiang Liu, davem, kuba, pabeni, netdev,
linux-kernel
On Wed, Sep 11, 2024 at 11:49:32AM -0700, Stanislav Fomichev wrote:
> Can you explain what is not correct?
>
> Calling BPF_CGROUP_RUN_PROG_GETSOCKOPT with max_optlen=0 should not be
> a problem I think? (the buffer simply won't be accessible to the bpf prog)
Sure. Sorry for not providing all the details.
If I understand the behavior of copy_from_user() correctly, it may
return partially copied data in case of error, which then leads to a
partially-copied 'max_optlen'.
So, do you expect a partially-copied max_optlen to be passed to the
eBPF program meanwhile the user still expects a complete one (since no
-EFAULT)?
Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 19:48 ` Cong Wang
@ 2024-09-11 20:05 ` Stanislav Fomichev
2024-09-14 0:49 ` Cong Wang
0 siblings, 1 reply; 16+ messages in thread
From: Stanislav Fomichev @ 2024-09-11 20:05 UTC (permalink / raw)
To: Cong Wang
Cc: Eric Dumazet, Qianqiang Liu, davem, kuba, pabeni, netdev,
linux-kernel
On 09/11, Cong Wang wrote:
> On Wed, Sep 11, 2024 at 11:49:32AM -0700, Stanislav Fomichev wrote:
> > Can you explain what is not correct?
> >
> > Calling BPF_CGROUP_RUN_PROG_GETSOCKOPT with max_optlen=0 should not be
> > a problem I think? (the buffer simply won't be accessible to the bpf prog)
>
> Sure. Sorry for not providing all the details.
>
> If I understand the behavior of copy_from_user() correctly, it may
> return partially copied data in case of error, which then leads to a
> partially-copied 'max_optlen'.
>
> So, do you expect a partially-copied max_optlen to be passed to the
> eBPF program meanwhile the user still expects a complete one (since no
> -EFAULT)?
>
> Thanks.
Partial copy is basically the same as user giving us garbage input, right?
That should still be handled correctly I think.
__cgroup_bpf_run_filter_getsockopt (via sockopt_alloc_buf) should handle both cases correctly:
- garbage input / partial copy resulting in negative number -> EINVAL
- garbage input / partial copy resulting in too large number -> potentially
EFAULT when trying to copy PAGE_SIZE-worth of data
Also, for the EOPNOTSUPP case, we shouldn't even bother copying any data.
Am I missing something?
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 20:05 ` Stanislav Fomichev
@ 2024-09-14 0:49 ` Cong Wang
2024-09-14 18:01 ` Stanislav Fomichev
0 siblings, 1 reply; 16+ messages in thread
From: Cong Wang @ 2024-09-14 0:49 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: Eric Dumazet, Qianqiang Liu, davem, kuba, pabeni, netdev,
linux-kernel
On Wed, Sep 11, 2024 at 01:05:27PM -0700, Stanislav Fomichev wrote:
> On 09/11, Cong Wang wrote:
> > On Wed, Sep 11, 2024 at 11:49:32AM -0700, Stanislav Fomichev wrote:
> > > Can you explain what is not correct?
> > >
> > > Calling BPF_CGROUP_RUN_PROG_GETSOCKOPT with max_optlen=0 should not be
> > > a problem I think? (the buffer simply won't be accessible to the bpf prog)
> >
> > Sure. Sorry for not providing all the details.
> >
> > If I understand the behavior of copy_from_user() correctly, it may
> > return partially copied data in case of error, which then leads to a
> > partially-copied 'max_optlen'.
> >
> > So, do you expect a partially-copied max_optlen to be passed to the
> > eBPF program meanwhile the user still expects a complete one (since no
> > -EFAULT)?
> >
> > Thanks.
>
> Partial copy is basically the same as user giving us garbage input, right?
> That should still be handled correctly I think.
Not to me.
For explict garbage input, users (mostly syzbot) already expect it is a
garbage.
For partial copy, users expect either an error (like EFAULT) or a success
with the _original_ value.
It is all about expectation of the API.
Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-14 0:49 ` Cong Wang
@ 2024-09-14 18:01 ` Stanislav Fomichev
0 siblings, 0 replies; 16+ messages in thread
From: Stanislav Fomichev @ 2024-09-14 18:01 UTC (permalink / raw)
To: Cong Wang
Cc: Eric Dumazet, Qianqiang Liu, davem, kuba, pabeni, netdev,
linux-kernel
On 09/13, Cong Wang wrote:
> On Wed, Sep 11, 2024 at 01:05:27PM -0700, Stanislav Fomichev wrote:
> > On 09/11, Cong Wang wrote:
> > > On Wed, Sep 11, 2024 at 11:49:32AM -0700, Stanislav Fomichev wrote:
> > > > Can you explain what is not correct?
> > > >
> > > > Calling BPF_CGROUP_RUN_PROG_GETSOCKOPT with max_optlen=0 should not be
> > > > a problem I think? (the buffer simply won't be accessible to the bpf prog)
> > >
> > > Sure. Sorry for not providing all the details.
> > >
> > > If I understand the behavior of copy_from_user() correctly, it may
> > > return partially copied data in case of error, which then leads to a
> > > partially-copied 'max_optlen'.
> > >
> > > So, do you expect a partially-copied max_optlen to be passed to the
> > > eBPF program meanwhile the user still expects a complete one (since no
> > > -EFAULT)?
> > >
> > > Thanks.
> >
> > Partial copy is basically the same as user giving us garbage input, right?
> > That should still be handled correctly I think.
>
> Not to me.
>
> For explict garbage input, users (mostly syzbot) already expect it is a
> garbage.
>
> For partial copy, users expect either an error (like EFAULT) or a success
> with the _original_ value.
>
> It is all about expectation of the API.
>
> Thanks.
The best way to move this forward is for you to showcase what is exactly
broken by adding a test case to one of the tools/testing/selftests/bpf/*sockopt*
files.
We can then discuss whether it warrants the copy_from_sockptr check or
some other remediation.
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH] net: check the return value of the copy_from_sockptr
2024-09-11 5:04 [PATCH] net: check the return value of the copy_from_sockptr Qianqiang Liu
2024-09-11 6:51 ` D. Wythe
2024-09-11 7:13 ` Eric Dumazet
@ 2024-09-18 13:11 ` David Laight
2 siblings, 0 replies; 16+ messages in thread
From: David Laight @ 2024-09-18 13:11 UTC (permalink / raw)
To: 'Qianqiang Liu', xiyou.wangcong@gmail.com,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
From: Qianqiang Liu
> Sent: 11 September 2024 06:05
>
> We must check the return value of the copy_from_sockptr. Otherwise, it
> may cause some weird issues.
Actually there is no point doing the copy for optlen in absolutely every function.
'optlen' can be passed as a kernel address and any user copy done by the caller.
Someone should have spotted that before sockptr_t was used for optlen.
The wrapper code can then also do a correct check for (optlen >= 0) which has
been pretty much broken in most protocols for ~ever.
(I wonder if any (important) userspace relies on a negative optlen
being treated as 4.)
It might mean that the final 'copy_to_user' are done in the opposite
order so that an kernel side side effects aren't reversed if the length
can't be copied out - but I suspect that doesn't matter and the paths
are likely to be untested and buggy.
I have toyed with making the getsockopt() functions return a +ve length
or -ve error - but there are a few strange places that need to update
the length and return an error.
David
>
> Signed-off-by: Qianqiang Liu <qianqiang.liu@163.com>
> ---
> net/socket.c | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/net/socket.c b/net/socket.c
> index 0a2bd22ec105..6b9a414d01d5 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -2370,8 +2370,11 @@ int do_sock_getsockopt(struct socket *sock, bool compat, int level,
> if (err)
> return err;
>
> - if (!compat)
> - copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> + if (!compat) {
> + err = copy_from_sockptr(&max_optlen, optlen, sizeof(int));
> + if (err)
> + return -EFAULT;
> + }
>
> ops = READ_ONCE(sock->ops);
> if (level == SOL_SOCKET) {
> --
> 2.39.2
>
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2024-09-18 13:12 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-11 5:04 [PATCH] net: check the return value of the copy_from_sockptr Qianqiang Liu
2024-09-11 6:51 ` D. Wythe
2024-09-11 7:13 ` Eric Dumazet
2024-09-11 8:23 ` Qianqiang Liu
2024-09-11 9:12 ` Eric Dumazet
2024-09-11 10:24 ` Qianqiang Liu
2024-09-11 12:40 ` Eric Dumazet
2024-09-11 16:58 ` Cong Wang
2024-09-11 17:15 ` Eric Dumazet
2024-09-11 17:35 ` Cong Wang
2024-09-11 18:49 ` Stanislav Fomichev
2024-09-11 19:48 ` Cong Wang
2024-09-11 20:05 ` Stanislav Fomichev
2024-09-14 0:49 ` Cong Wang
2024-09-14 18:01 ` Stanislav Fomichev
2024-09-18 13:11 ` David Laight
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).