All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arjun Roy <arjunroy@google.com>
To: Dan Carpenter <dan.carpenter@oracle.com>
Cc: David Ahern <dsahern@gmail.com>,
	kbuild@lists.01.org, Arjun Roy <arjunroy.kdev@gmail.com>,
	David Miller <davem@davemloft.net>,
	netdev <netdev@vger.kernel.org>,
	lkp@intel.com, kbuild-all@lists.01.org,
	Eric Dumazet <edumazet@google.com>,
	Soheil Hassas Yeganeh <soheil@google.com>,
	Leon Romanovsky <leon@kernel.org>,
	Jakub Kicinski <kuba@kernel.org>
Subject: Re: [net-next] tcp: Sanitize CMSG flags and reserved args in tcp_zerocopy_receive.
Date: Thu, 25 Feb 2021 15:00:20 -0800	[thread overview]
Message-ID: <CAOFY-A250ZDuE3PgFHueLWWRP187uEXFPw78XR_O_eFzS9p-Fg@mail.gmail.com> (raw)
In-Reply-To: <20210215160222.GE2222@kadam>

On Mon, Feb 15, 2021 at 8:02 AM Dan Carpenter <dan.carpenter@oracle.com> wrote:
>
> On Mon, Feb 15, 2021 at 08:04:11AM -0700, David Ahern wrote:
> > On 2/15/21 5:03 AM, Dan Carpenter wrote:
> > > Hi Arjun,
> > >
> > > url:    https://github.com/0day-ci/linux/commits/Arjun-Roy/tcp-Sanitize-CMSG-flags-and-reserved-args-in-tcp_zerocopy_receive/20210212-052537
> > > base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git  e4b62cf7559f2ef9a022de235e5a09a8d7ded520
> > > config: x86_64-randconfig-m001-20210209 (attached as .config)
> > > compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
> > >
> > > If you fix the issue, kindly add following tag as appropriate
> > > Reported-by: kernel test robot <lkp@intel.com>
> > > Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> > >
> > > smatch warnings:
> > > net/ipv4/tcp.c:4158 do_tcp_getsockopt() warn: check for integer overflow 'len'
> > >
> > > vim +/len +4158 net/ipv4/tcp.c
> > >
> > > 3fdadf7d27e3fb Dmitry Mishin            2006-03-20  3896  static int do_tcp_getsockopt(struct sock *sk, int level,
> > > 3fdadf7d27e3fb Dmitry Mishin            2006-03-20  3897            int optname, char __user *optval, int __user *optlen)
> > > ^1da177e4c3f41 Linus Torvalds           2005-04-16  3898  {
> > > 295f7324ff8d9e Arnaldo Carvalho de Melo 2005-08-09  3899    struct inet_connection_sock *icsk = inet_csk(sk);
> > > ^1da177e4c3f41 Linus Torvalds           2005-04-16  3900    struct tcp_sock *tp = tcp_sk(sk);
> > > 6fa251663069e0 Nikolay Borisov          2016-02-03  3901    struct net *net = sock_net(sk);
> > > ^1da177e4c3f41 Linus Torvalds           2005-04-16  3902    int val, len;
> > >
> > > "len" is int.
> > >
> > > [ snip ]
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4146  #ifdef CONFIG_MMU
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4147    case TCP_ZEROCOPY_RECEIVE: {
> > > 7eeba1706eba6d Arjun Roy                2021-01-20  4148            struct scm_timestamping_internal tss;
> > > e0fecb289ad3fd Arjun Roy                2020-12-10  4149            struct tcp_zerocopy_receive zc = {};
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4150            int err;
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4151
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4152            if (get_user(len, optlen))
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4153                    return -EFAULT;
> > > c8856c05145490 Arjun Roy                2020-02-14  4154            if (len < offsetofend(struct tcp_zerocopy_receive, length))
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4155                    return -EINVAL;
> > >
> > >
> > > The problem is that negative values of "len" are type promoted to high
> > > positive values.  So the fix is to write this as:
> > >
> > >     if (len < 0 || len < offsetofend(struct tcp_zerocopy_receive, length))
> > >             return -EINVAL;
> > >
> > > 110912bdf28392 Arjun Roy                2021-02-11  4156            if (unlikely(len > sizeof(zc))) {
> > > 110912bdf28392 Arjun Roy                2021-02-11  4157                    err = check_zeroed_user(optval + sizeof(zc),
> > > 110912bdf28392 Arjun Roy                2021-02-11 @4158                                            len - sizeof(zc));
> > >                                                                                                         ^^^^^^^^^^^^^^^^
> > > Potentially "len - a negative value".
> > >
> > >
> >
> > get_user(len, optlen) is called multiple times in that function. len < 0
> > was checked after the first one at the top.
> >
>
> What you're describing is a "Double Fetch" bug, where the attack is we
> get some data from the user, and we verify it, then we get it from the
> user a second time and trust it.  The problem is that the user modifies
> it between the first and second get_user() call so it ends up being a
> security vulnerability.
>
> But I'm glad you pointed out the first get_user() because it has an
> ancient, harmless pre git bug in it.
>
> net/ipv4/tcp.c
>   3888  static int do_tcp_getsockopt(struct sock *sk, int level,
>   3889                  int optname, char __user *optval, int __user *optlen)
>   3890  {
>   3891          struct inet_connection_sock *icsk = inet_csk(sk);
>   3892          struct tcp_sock *tp = tcp_sk(sk);
>   3893          struct net *net = sock_net(sk);
>   3894          int val, len;
>   3895
>   3896          if (get_user(len, optlen))
>   3897                  return -EFAULT;
>   3898
>   3899          len = min_t(unsigned int, len, sizeof(int));
>   3900
>   3901          if (len < 0)
>                     ^^^^^^^
> This is impossible.  "len" has to be in the 0-4 range because of the
> min_t() assignment.  It's harmless though and the condition should just
> be removed.
>
>   3902                  return -EINVAL;
>   3903
>   3904          switch (optname) {
>   3905          case TCP_MAXSEG:
>
> Anyway, I will create a new Smatch warning for this situation.
>
> > Also, maybe I am missing something here, but offsetofend can not return
> > a negative value, so this checks catches len < 0 as well:
> >
> >       if (len < offsetofend(struct tcp_zerocopy_receive, length))
> >               return -EINVAL;
> >
>
> offsetofend is (unsigned long)12.  If we compare a negative integer with
> (unsigned long)12 then negative number is type promoted to a high
> positive value.
>
>         if (-1 < (usigned long)12)
>                 printf("dan is wrong\n");
>
> regards,
> dan carpenter
>
>
Thank you for the catch. I will send out a fix momentarily.

Actually, now I'm curious - why does do_tcp_getsockopt get called so
many times, per getsockopt target - rather than just using the
originally read value?

-Arjun

WARNING: multiple messages have this Message-ID (diff)
From: Arjun Roy <arjunroy@google.com>
To: kbuild-all@lists.01.org
Subject: Re: [net-next] tcp: Sanitize CMSG flags and reserved args in tcp_zerocopy_receive.
Date: Thu, 25 Feb 2021 15:00:20 -0800	[thread overview]
Message-ID: <CAOFY-A250ZDuE3PgFHueLWWRP187uEXFPw78XR_O_eFzS9p-Fg@mail.gmail.com> (raw)
In-Reply-To: <20210215160222.GE2222@kadam>

[-- Attachment #1: Type: text/plain, Size: 5902 bytes --]

On Mon, Feb 15, 2021 at 8:02 AM Dan Carpenter <dan.carpenter@oracle.com> wrote:
>
> On Mon, Feb 15, 2021 at 08:04:11AM -0700, David Ahern wrote:
> > On 2/15/21 5:03 AM, Dan Carpenter wrote:
> > > Hi Arjun,
> > >
> > > url:    https://github.com/0day-ci/linux/commits/Arjun-Roy/tcp-Sanitize-CMSG-flags-and-reserved-args-in-tcp_zerocopy_receive/20210212-052537
> > > base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git  e4b62cf7559f2ef9a022de235e5a09a8d7ded520
> > > config: x86_64-randconfig-m001-20210209 (attached as .config)
> > > compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
> > >
> > > If you fix the issue, kindly add following tag as appropriate
> > > Reported-by: kernel test robot <lkp@intel.com>
> > > Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> > >
> > > smatch warnings:
> > > net/ipv4/tcp.c:4158 do_tcp_getsockopt() warn: check for integer overflow 'len'
> > >
> > > vim +/len +4158 net/ipv4/tcp.c
> > >
> > > 3fdadf7d27e3fb Dmitry Mishin            2006-03-20  3896  static int do_tcp_getsockopt(struct sock *sk, int level,
> > > 3fdadf7d27e3fb Dmitry Mishin            2006-03-20  3897            int optname, char __user *optval, int __user *optlen)
> > > ^1da177e4c3f41 Linus Torvalds           2005-04-16  3898  {
> > > 295f7324ff8d9e Arnaldo Carvalho de Melo 2005-08-09  3899    struct inet_connection_sock *icsk = inet_csk(sk);
> > > ^1da177e4c3f41 Linus Torvalds           2005-04-16  3900    struct tcp_sock *tp = tcp_sk(sk);
> > > 6fa251663069e0 Nikolay Borisov          2016-02-03  3901    struct net *net = sock_net(sk);
> > > ^1da177e4c3f41 Linus Torvalds           2005-04-16  3902    int val, len;
> > >
> > > "len" is int.
> > >
> > > [ snip ]
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4146  #ifdef CONFIG_MMU
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4147    case TCP_ZEROCOPY_RECEIVE: {
> > > 7eeba1706eba6d Arjun Roy                2021-01-20  4148            struct scm_timestamping_internal tss;
> > > e0fecb289ad3fd Arjun Roy                2020-12-10  4149            struct tcp_zerocopy_receive zc = {};
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4150            int err;
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4151
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4152            if (get_user(len, optlen))
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4153                    return -EFAULT;
> > > c8856c05145490 Arjun Roy                2020-02-14  4154            if (len < offsetofend(struct tcp_zerocopy_receive, length))
> > > 05255b823a6173 Eric Dumazet             2018-04-27  4155                    return -EINVAL;
> > >
> > >
> > > The problem is that negative values of "len" are type promoted to high
> > > positive values.  So the fix is to write this as:
> > >
> > >     if (len < 0 || len < offsetofend(struct tcp_zerocopy_receive, length))
> > >             return -EINVAL;
> > >
> > > 110912bdf28392 Arjun Roy                2021-02-11  4156            if (unlikely(len > sizeof(zc))) {
> > > 110912bdf28392 Arjun Roy                2021-02-11  4157                    err = check_zeroed_user(optval + sizeof(zc),
> > > 110912bdf28392 Arjun Roy                2021-02-11 @4158                                            len - sizeof(zc));
> > >                                                                                                         ^^^^^^^^^^^^^^^^
> > > Potentially "len - a negative value".
> > >
> > >
> >
> > get_user(len, optlen) is called multiple times in that function. len < 0
> > was checked after the first one at the top.
> >
>
> What you're describing is a "Double Fetch" bug, where the attack is we
> get some data from the user, and we verify it, then we get it from the
> user a second time and trust it.  The problem is that the user modifies
> it between the first and second get_user() call so it ends up being a
> security vulnerability.
>
> But I'm glad you pointed out the first get_user() because it has an
> ancient, harmless pre git bug in it.
>
> net/ipv4/tcp.c
>   3888  static int do_tcp_getsockopt(struct sock *sk, int level,
>   3889                  int optname, char __user *optval, int __user *optlen)
>   3890  {
>   3891          struct inet_connection_sock *icsk = inet_csk(sk);
>   3892          struct tcp_sock *tp = tcp_sk(sk);
>   3893          struct net *net = sock_net(sk);
>   3894          int val, len;
>   3895
>   3896          if (get_user(len, optlen))
>   3897                  return -EFAULT;
>   3898
>   3899          len = min_t(unsigned int, len, sizeof(int));
>   3900
>   3901          if (len < 0)
>                     ^^^^^^^
> This is impossible.  "len" has to be in the 0-4 range because of the
> min_t() assignment.  It's harmless though and the condition should just
> be removed.
>
>   3902                  return -EINVAL;
>   3903
>   3904          switch (optname) {
>   3905          case TCP_MAXSEG:
>
> Anyway, I will create a new Smatch warning for this situation.
>
> > Also, maybe I am missing something here, but offsetofend can not return
> > a negative value, so this checks catches len < 0 as well:
> >
> >       if (len < offsetofend(struct tcp_zerocopy_receive, length))
> >               return -EINVAL;
> >
>
> offsetofend is (unsigned long)12.  If we compare a negative integer with
> (unsigned long)12 then negative number is type promoted to a high
> positive value.
>
>         if (-1 < (usigned long)12)
>                 printf("dan is wrong\n");
>
> regards,
> dan carpenter
>
>
Thank you for the catch. I will send out a fix momentarily.

Actually, now I'm curious - why does do_tcp_getsockopt get called so
many times, per getsockopt target - rather than just using the
originally read value?

-Arjun

  parent reply	other threads:[~2021-02-25 23:01 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-11 21:21 [net-next] tcp: Sanitize CMSG flags and reserved args in tcp_zerocopy_receive Arjun Roy
2021-02-12  2:08 ` Jakub Kicinski
2021-02-12  3:10 ` patchwork-bot+netdevbpf
2021-02-15 12:03 ` Dan Carpenter
2021-02-15 12:03   ` Dan Carpenter
2021-02-15 12:03   ` Dan Carpenter
2021-02-15 15:04   ` David Ahern
2021-02-15 16:02     ` Dan Carpenter
2021-02-15 16:02       ` Dan Carpenter
2021-02-15 16:02       ` Dan Carpenter
2021-02-25 22:59       ` Arjun Roy
2021-02-25 23:00       ` Arjun Roy [this message]
2021-02-25 23:00         ` Arjun Roy
2021-02-12  2:28 kernel test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAOFY-A250ZDuE3PgFHueLWWRP187uEXFPw78XR_O_eFzS9p-Fg@mail.gmail.com \
    --to=arjunroy@google.com \
    --cc=arjunroy.kdev@gmail.com \
    --cc=dan.carpenter@oracle.com \
    --cc=davem@davemloft.net \
    --cc=dsahern@gmail.com \
    --cc=edumazet@google.com \
    --cc=kbuild-all@lists.01.org \
    --cc=kbuild@lists.01.org \
    --cc=kuba@kernel.org \
    --cc=leon@kernel.org \
    --cc=lkp@intel.com \
    --cc=netdev@vger.kernel.org \
    --cc=soheil@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.