Re: KMSAN: uninit-value in __dev_mc_add

2018-09-27 Thread Vladis Dronov
Hello, Eric, all,

> I dunno, your patch looks quite not the right fix.

I agree, it looks more like a dirty hack. Unfortunately, I lack the deep
expertise in the network stack subsystem, so I've posted the patch to,
sort of, start a discussion and probably get some hints.
 
> If TUN is able to change dev->type,  how comes it does not set the
> appropriate dev->addr_len at the same time ?

Well,... probably, nobody cared to do so:

[drivers/net/tun.c]
case TUNSETLINK:
...
tun->dev->type = (int) arg; //<--- that's all!
tun_debug(KERN_INFO, tun, "linktype set to %d\n",
  tun->dev->type);
ret = 0;
}
break;

> Really the bug seems to be deeper, and without setting proper
> dev->addr_len, we'll need more 'fixes' like yours.

Absolutely. Unfortunately, I wasn't able to just write such deeper patch. 
Let me share what I have found and let me hope to get an advise.

- So setting just the tun->dev->type makes the dev struct inconsistent.

- There are more field to adjust, at least dev->broadcast. Also, there are
  a number of *_ops fields which are all set for the Ethernet type, most
  probably they must be adjusted also.

- There is no get_addr_len_by_link_type() or a simple way to get link layer
  properties by dev->type. Such settings are scattered in *_setup and
  *_init functions, like ipgre_tunnel_init() { ... dev->addr_len = 4; ...}

Having these, I can imagine 2 ways for a proper fix.

1) Destroy the net_device in question and recreate it when changing a link
type. This way all the dev fields are set right. Create it in a similar way
as rtnl_newlink() does. Again, we do not have get_X_by_link_type(), so it
probably will be some large switch()/case:

  $ grep '^#define ARPHRD_' include/uapi/linux/if_arp.h | wc -l
  59

2) Leave tun an Ethernet device, add some tun->pretend_to_be_this_link_type
field and change only it on TUNSETLINK. And use this field in cases for which
TUNSETLINK was invented in the first place. Unfortunately, I do not have such
a list. The initial the commit ff4cc3ac93e1 says:

  For use with
  wireless and other networking types it should be possible to set the
  ARP type via an ioctl.

Surely, there can be something else which I do not see. Could anyone suggest
an advice on this?

Best regards,
Vladis Dronov | Red Hat, Inc. | Product Security Engineer


Re: KMSAN: uninit-value in __dev_mc_add

2018-09-27 Thread Vladis Dronov
Hello,

This report is actually for the same bug which was reported in:

https://syzkaller.appspot.com/bug?id=088efeac32fdde781038a777a63e436c0d4d7036

The note there that the bug was fixed by "Commits: net: fix uninit-value in
__hw_addr_add_ex()" is wrong. A C-reproducer from the 2nd syzkaller report
can trigger the bug from this one.

I've researched this and a result is a proposed patch, the problem is the tun
device code allowing to set an arbitrary link type.

https://lkml.org/lkml/2018/9/26/416
https://lore.kernel.org/lkml/20180926093018.6646-1-vdro...@redhat.com/T/#u
https://marc.info/?l=linux-netdev=153795423320016=2

A simplified reproducer is attached.

Best regards,
Vladis Dronov
#define _GNU_SOURCE
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
  int ret, sockfd, tunfd;

  syscall(__NR_mmap, 0x2000, 0x100, 3, 0x32, -1, 0);

  // socket(AF_PACKET, SOCK_DGRAM|SOCK_NONBLOCK, 0)
  sockfd = syscall(__NR_socket, 0x11, 0x10802, 0);
  if (sockfd < 0) {
perror("socket()");
ret = 1;
goto exit_end;
  }

  memcpy((void*)0x2240, "/dev/net/tun", 13);
  tunfd = open((char *)0x2240, 0);
  if (tunfd < 0) {
perror("open()");
ret = 2;
goto exit_sock_close;
  }

  memcpy((void*)0x20c0, 
"\x69\x67\x62\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
  *(uint16_t*)0x20d0 = 0x4012;
  ret = syscall(__NR_ioctl, tunfd, 0x400454ca, 0x20c0); // TUNSETIFF 
_IOW('T', 202, int)
  if (ret < 0) {
perror("ioctl(TUNSETIFF)");
ret = 3;
goto exit_tun_close;
  }

  // TUNSETLINK _IOW('T', 205, int) / 0x30a = 778 = ARPHRD_IPGRE
  if (argc < 2)
ret = syscall(__NR_ioctl, tunfd, 0x400454cd, 0x30a);
  else
ret = syscall(__NR_ioctl, tunfd, 0x400454cd, atoi(argv[1]));
  if (ret < 0) {
perror("ioctl(TUNSETLINK)");
ret = 4;
goto exit_tun_close;
  }

  memcpy((void*)0x2040, 
"\x69\x67\x62\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
  *(uint16_t*)0x2050 = 0xa201;
  ret = syscall(__NR_ioctl, sockfd, 0x8914, 0x2040); // SIOCSIFFLAGS 0x8914
  if (ret < 0) {
perror("ioctl(SIOCSIFFLAGS)");
ret = 5;
goto exit_tun_close;
  }

  printf("done:\n");
  system("/usr/sbin/ip -details link show igb0");

exit_tun_close:
  close(tunfd);
exit_sock_close:
  close(sockfd);
exit_end:
  munmap((void *)0x2000, 0x100);
  return 0;
}

Re: KMSAN: uninit-value in memcmp (2)

2018-09-27 Thread Vladis Dronov
Hello, Dmirty,

Thank you for the explanation of how syzkaller/syzbot works in this and
other emails. I understand that is it a complicated task to determine
and categorize bugs based on just crash dump and messages, and syzkaller
does a great job of doing so.

> Re __hw_addr_add_ex bug, as Alex noted the crash was detected _after_
> the fixing commit went in. So it's something new and different and
> can't be fixed by the older commit.

Indeed, you're right, there is another issue with tun/tap devices which
leads to this bug. I've posted a patch (https://lkml.org/lkml/2018/9/26/416)
to fix it.

I hope I did not do much damage, reporting previous fix as a fix for this bug,
as syzkaller will probably create another "KMSAN: uninit-value in <...>"
report.

Best regards,
Vladis Dronov | Red Hat, Inc. | Product Security Engineer

- Original Message -
> From: "Dmitry Vyukov" 
> To: "Alexander Potapenko" 
> Cc: "Vladis Dronov" , "syzbot" 
> ,
> "syzkaller-bugs" , "David Miller" 
> , "Eric Dumazet"
> , "LKML" , "Networking" 
> , "sunlianwen"
> 
> Sent: Monday, September 24, 2018 11:39:08 AM
> Subject: Re: KMSAN: uninit-value in memcmp (2)
> 
> On Mon, Sep 24, 2018 at 8:53 AM, Alexander Potapenko 
> wrote:
> > On Mon, Sep 24, 2018 at 12:09 AM Vladis Dronov  wrote:
> >>
> >> Hello, Dmirty,
> >>
> >> Thank you for the reply. Can we please, discuss this further?
> > Hi Vladis,
> >> > You can see on dashboard that the last crash
> >> > for the second version (2) happened just few days ago. So this is a
> >> > different bug.
> > FWIW I've just double-checked that the reproducer provided by
> > syzkaller in the original message still triggers the report from the
> > original message in the latest KMSAN tree (which already contains the
> > __hw_addr_add_ex() fix from April).
> >> Well... yes and no. When I was looking at this bug (bug?id=088efeac32fd) I
> >> was looking
> >> at the report at "2018/05/09 18:55"
> >> (https://syzkaller.appspot.com/text?tag=CrashReport=141b707b80),
> >> since it was the only report with a reproducer. This was my error.
> >>
> >> The error and the call trace in this report are:
> >>
> >> >>>
> >> BUG: KMSAN: uninit-value in memcmp+0x119/0x180 lib/string.c:861
> >> CPU: 0 PID: 38 Comm: kworker/0:1 Not tainted 4.17.0-rc3+ #88
> >> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
> >> Google 01/01/2011
> >> Workqueue: ipv6_addrconf addrconf_dad_work
> >> Call Trace:
> >>  __dump_stack lib/dump_stack.c:77 [inline]
> >>  dump_stack+0x185/0x1d0 lib/dump_stack.c:113
> >>  kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067
> >>  __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:683
> >>  memcmp+0x119/0x180 lib/string.c:861
> >>  __hw_addr_add_ex net/core/dev_addr_lists.c:61 [inline]
> >>  __dev_mc_add+0x1fc/0x900 net/core/dev_addr_lists.c:670
> >>  dev_mc_add+0x6d/0x80 net/core/dev_addr_lists.c:687
> >>  igmp6_group_added+0x2db/0xa00 net/ipv6/mcast.c:662
> >>  ipv6_dev_mc_inc+0xe9e/0x1130 net/ipv6/mcast.c:914
> >>  addrconf_join_solict net/ipv6/addrconf.c:2103 [inline]
> >>  addrconf_dad_begin net/ipv6/addrconf.c:3853 [inline]
> >>  addrconf_dad_work+0x462/0x2a20 net/ipv6/addrconf.c:3979
> >>  process_one_work+0x12c6/0x1f60 kernel/workqueue.c:2145
> >>  worker_thread+0x113c/0x24f0 kernel/workqueue.c:2279
> >>  kthread+0x539/0x720 kernel/kthread.c:239
> >>  ret_from_fork+0x35/0x40 arch/x86/entry/entry_64.S:412
> >>
> >> Local variable description: buf@igmp6_group_added
> >> Variable was created at:
> >>  igmp6_group_added+0x4a/0xa00 net/ipv6/mcast.c:650
> >>  ipv6_dev_mc_inc+0xe9e/0x1130 net/ipv6/mcast.c:914
> >> <<<
> >>
> >> It is the same like in bug?id=3887c0d99aecb27d085180c5222d245d08a30806
> >> which, after some more test, made me believe these bugs are duplicate
> >> and are fixed by the same commit.
> >>
> >> But let's look at another report at "2018/09/12 21:00"
> >> (https://syzkaller.appspot.com/text?tag=CrashReport=14f99b7140)
> >> at the bug (bug?id=088efeac32fd), the one you've mentioned as
> >> "the last crash for the second version (2) happened just few days ago".
> >>
> >> Its error and the call trace are completely different:
> >>
> >> >>>
> >> BUG: KMS

[PATCH] xfrm: policy: check policy direction value

2017-08-02 Thread Vladis Dronov
The 'dir' parameter in xfrm_migrate() is a user-controlled byte which is used
as an array index. This can lead to an out-of-bound access, kernel lockup and
DoS. Add a check for the 'dir' value.

This fixes CVE-2017-11600.

References: https://bugzilla.redhat.com/show_bug.cgi?id=1474928
Fixes: 80c9abaabf42 ("[XFRM]: Extension for dynamic update of endpoint 
address(es)")
Cc: <sta...@vger.kernel.org> # v2.6.21-rc1
Reported-by: "bo Zhang" <zhangbo5891...@gmail.com>
Signed-off-by: Vladis Dronov <vdro...@redhat.com>
---
 net/xfrm/xfrm_policy.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index ff61d85..6f5a0dad 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -3308,9 +3308,15 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 
dir, u8 type,
struct xfrm_state *x_new[XFRM_MAX_DEPTH];
struct xfrm_migrate *mp;
 
+   /* Stage 0 - sanity checks */
if ((err = xfrm_migrate_check(m, num_migrate)) < 0)
goto out;
 
+   if (dir >= XFRM_POLICY_MAX) {
+   err = -EINVAL;
+   goto out;
+   }
+
/* Stage 1 - find policy */
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
err = -ENOENT;
-- 
2.9.4



[PATCH v2 net] ipv4: Fix misplaced EXPORT_SYMBOL_GPL(ping_hash) in net/ipv4/ping.c

2017-05-09 Thread Vladis Dronov
Signed-off-by: Vladis Dronov <vdro...@redhat.com>
---
This is quite a smaill patch, please, feel free not to accept in separately,
but use as a part of any patch of yours.

 net/ipv4/ping.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index ccfbce1..19f0b7b 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -71,7 +71,6 @@ static inline u32 ping_hashfn(const struct net *net, u32 num, 
u32 mask)
pr_debug("hash(%u) = %u\n", num, res);
return res;
 }
-EXPORT_SYMBOL_GPL(ping_hash);
 
 static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table,
 struct net *net, unsigned int num)
@@ -152,6 +151,7 @@ int ping_hash(struct sock *sk)
 
return 0;
 }
+EXPORT_SYMBOL_GPL(ping_hash);
 
 void ping_unhash(struct sock *sk)
 {
-- 
2.9.3



[PATCH] misplaced EXPORT_SYMBOL_GPL(ping_hash) in net/ipv4/ping.c

2017-05-05 Thread Vladis Dronov
Move misplaced EXPORT_SYMBOL_GPL(ping_hash) to a proper place.

Signed-off-by: Vladis Dronov <vdro...@redhat.com>
---

Actually, this is so small and unimportant (it just hurts my perfectionism),
so does not worth a separate patch. Please, feel free to make it a part of
some patch of yours.

 net/ipv4/ping.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index ccfbce1..19f0b7b 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -71,7 +71,6 @@ static inline u32 ping_hashfn(const struct net *net, u32 num, 
u32 mask)
pr_debug("hash(%u) = %u\n", num, res);
return res;
 }
-EXPORT_SYMBOL_GPL(ping_hash);
 
 static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table,
 struct net *net, unsigned int num)
@@ -152,6 +151,7 @@ int ping_hash(struct sock *sk)
 
return 0;
 }
+EXPORT_SYMBOL_GPL(ping_hash);
 
 void ping_unhash(struct sock *sk)
 {
-- 
2.9.3



Re: BUG() can be hit in tcp_collapse()

2016-11-30 Thread Vladis Dronov
Hello, Eric, Marco, all,

This is JFYI and a follow-up message.

A further investigation was made to find out the Linux kernel commit which has
introduced the flaw. It appeared that previous Linux kernel versions are 
vulnerable,
down to v3.6-rc1. This fact was hidden by 'net.ipv4.tcp_fastopen' set to 0 by 
default,
and now it is easier to notice since kernel v3.12 due to commit 0d41cca490 
where the
default was changed to 1. With 'net.ipv4.tcp_fastopen' set to 1, previous Linux
kernels (including RHEL-7 ones) are also vulnerable.

The bug is here since tcp-fastopen feature was introduced in kernel v3.6-rc1, 
the first
commit when the reproducer starts to panic the kernel with 
net.ipv4.tcp_fastopen=1 set
is cf60af03ca, which is a part of commit sequence 2100c8d2d9..67da22d23f 
introducing
net-tcp-fastopen feature:

$ git bisect bad cf60af03ca4e71134206809ea892e49b92a88896
cf60af03ca4e71134206809ea892e49b92a88896 is the first bad commit
commit cf60af03ca4e71134206809ea892e49b92a88896
Author: Yuchung Cheng <ych...@google.com>
Date:   Thu Jul 19 06:43:09 2012 +

So, ideally, the upstream commit ac6e780070 which fixes the bug should have
"Fixes: cf60af03ca" statement, unfortunately, this investigation was not 
completed at
the time the patch was accepted upstream. And unfortunately I do not see other 
way
to add this information except making notes in a comment in the related code, 
which
seems weird.

Best regards,
Vladis Dronov | Red Hat, Inc. | Product Security Engineer


Re: BUG() can be hit in tcp_collapse()

2016-11-11 Thread Vladis Dronov
Hello, Eric,

> Another sk_filter() is used in tcp v6.
> So the correct patch would be :

Thank you much for your research. I'm happy my report
has resulted as the proposed patch.

Best regards,
Vladis Dronov | Red Hat, Inc. | Product Security Engineer


BUG() can be hit in tcp_collapse()

2016-11-10 Thread Vladis Dronov
ing the BUG()). This
is why I'm emailing not only to stable@, but also to netdev@, asking to review 
the
data above and probably develop a fix.

Best regards,
Vladis Dronov | Red Hat, Inc. | Product Security Engineer#ifndef __NR_mmap
#define __NR_mmap 9
#endif
#ifndef __NR_syz_fuse_mount
#define __NR_syz_fuse_mount 104
#endif
#ifndef __NR_syz_test
#define __NR_syz_test 101
#endif
#ifndef __NR_syz_open_dev
#define __NR_syz_open_dev 102
#endif
#ifndef __NR_syz_open_pts
#define __NR_syz_open_pts 103
#endif
#ifndef __NR_socket
#define __NR_socket 41
#endif
#ifndef __NR_bind
#define __NR_bind 49
#endif
#ifndef __NR_sendto
#define __NR_sendto 44
#endif
#ifndef __NR_setsockopt
#define __NR_setsockopt 54
#endif
#ifndef __NR_syz_fuseblk_mount
#define __NR_syz_fuseblk_mount 105
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

__thread int skip_segv;
__thread jmp_buf segv_env;

static void segv_handler(int sig, siginfo_t* info, void* uctx)
{
  if (__atomic_load_n(_segv, __ATOMIC_RELAXED))
_longjmp(segv_env, 1);
  exit(sig);
}

static void install_segv_handler()
{
  struct sigaction sa;
  memset(, 0, sizeof(sa));
  sa.sa_sigaction = segv_handler;
  sa.sa_flags = SA_NODEFER | SA_SIGINFO;
  sigaction(SIGSEGV, , NULL);
  sigaction(SIGBUS, , NULL);
}

#define NONFAILING(...)\
  {\
__atomic_fetch_add(_segv, 1, __ATOMIC_SEQ_CST);   \
if (_setjmp(segv_env) == 0) {  \
  __VA_ARGS__; \
}  \
__atomic_fetch_sub(_segv, 1, __ATOMIC_SEQ_CST);   \
  }

static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2)
{
  if (a0 == 0xc || a0 == 0xb) {
char buf[128];
sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block",
(uint8_t)a1, (uint8_t)a2);
return open(buf, O_RDWR, 0);
  } else {
char buf[1024];
char* hash;
strncpy(buf, (char*)a0, sizeof(buf));
buf[sizeof(buf) - 1] = 0;
while ((hash = strchr(buf, '#'))) {
  *hash = '0' + (char)(a1 % 10);
  a1 /= 10;
}
return open(buf, a2, 0);
  }
}

static uintptr_t syz_open_pts(uintptr_t a0, uintptr_t a1)
{
  int ptyno = 0;
  if (ioctl(a0, TIOCGPTN, ))
return -1;
  char buf[128];
  sprintf(buf, "/dev/pts/%d", ptyno);
  return open(buf, a1, 0);
}

static uintptr_t syz_fuse_mount(uintptr_t a0, uintptr_t a1,
uintptr_t a2, uintptr_t a3,
uintptr_t a4, uintptr_t a5)
{
  uint64_t target = a0;
  uint64_t mode = a1;
  uint64_t uid = a2;
  uint64_t gid = a3;
  uint64_t maxread = a4;
  uint64_t flags = a5;

  int fd = open("/dev/fuse", O_RDWR);
  if (fd == -1)
return fd;
  char buf[1024];
  sprintf(buf, "fd=%d,user_id=%ld,group_id=%ld,rootmode=0%o", fd,
  (long)uid, (long)gid, (unsigned)mode & ~3u);
  if (maxread != 0)
sprintf(buf + strlen(buf), ",max_read=%ld", (long)maxread);
  if (mode & 1)
strcat(buf, ",default_permissions");
  if (mode & 2)
strcat(buf, ",allow_other");
  syscall(SYS_mount, "", target, "fuse", flags, buf);
  return fd;
}

static uintptr_t syz_fuseblk_mount(uintptr_t a0, uintptr_t a1,
   uintptr_t a2, uintptr_t a3,
   uintptr_t a4, uintptr_t a5,
   uintptr_t a6, uintptr_t a7)
{
  uint64_t target = a0;
  uint64_t blkdev = a1;
  uint64_t mode = a2;
  uint64_t uid = a3;
  uint64_t gid = a4;
  uint64_t maxread = a5;
  uint64_t blksize = a6;
  uint64_t flags = a7;

  int fd = open("/dev/fuse", O_RDWR);
  if (fd == -1)
return fd;
  if (syscall(SYS_mknodat, AT_FDCWD, blkdev, S_IFBLK, makedev(7, 199)))
return fd;
  char buf[256];
  sprintf(buf, "fd=%d,user_id=%ld,group_id=%ld,rootmode=0%o", fd,
  (long)uid, (long)gid, (unsigned)mode & ~3u);
  if (maxread != 0)
sprintf(buf + strlen(buf), ",max_read=%ld", (long)maxread);
  if (blksize != 0)
sprintf(buf + strlen(buf), ",blksize=%ld", (long)blksize);
  if (mode & 1)
strcat(buf, ",default_permissions");
  if (mode & 2)
strcat(buf, ",allow_other");
  syscall(SYS_mount, blkdev, target, "fuseblk", flags, buf);
  return fd;
}

static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1,
 uintptr_t a2, uintptr_t a3,
 uintptr_t a4, uintptr_t a5,
 uintptr_t a6, uintptr_t a7,
 uintptr_t a8)
{
  switch (nr) {