* [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).