Thread (15 messages) flat view 15 messages, 2 authors, 2016-02-11

Re: gigaset: memory leak in gigaset_initcshw

From: Dmitry Vyukov <dvyukov@google.com>
Date: 2016-02-04 10:40:58
Also in: lkml

On Wed, Feb 3, 2016 at 8:11 PM, Paul Bolle [off-list ref] wrote:
quoted hunk ↗ jump to hunk
Hi Dmitry,

On wo, 2016-02-03 at 17:16 +0100, Paul Bolle wrote:
quoted
The above should provide me with enough information to figure out
what's going on here.
I've instrumented ser_gigaset with some printk's. Basically I added the
stuff pasted at the end of this message. In 10.000 runs of the program
syzkaller generated the added printk's suggest that struct ser_cardstate
is freed every time.

(Note that this was done on a machine that, probably like the VM
syzkaller was running in, doesn't have the clunky hardware that this
driver manages attached.)

Before I dive deeper into this: can you reproduce this leak? Is it
perhaps a one in gazillion runs thing? Do you have the logs of a run
that warned about this leak at hand?

Thanks,


Paul Bolle
@@ -375,9 +377,12 @@ static void gigaset_device_release(struct device *dev)
 {
        struct cardstate *cs = dev_get_drvdata(dev);

-       if (!cs)
+       if (!cs) {
+               pr_info("%s: no cardstate", __func__);
                return;
+       }
        dev_set_drvdata(dev, NULL);
+       pr_info("%s: kfree(%p)", __func__, cs->hw.ser);
        kfree(cs->hw.ser);
        cs->hw.ser = NULL;
 }
@@ -392,6 +397,7 @@ static int gigaset_initcshw(struct cardstate *cs)
        struct ser_cardstate *scs;

        scs = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL);
+       pr_info("%s: scs = %p", __func__, scs);
        if (!scs) {
                pr_err("out of memory\n");
                return -ENOMEM;


Forgot to mention that you need to run it in a parallel loop, sorry.

This one should do:

// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void work()
{
  long r[7];
  memset(r, -1, sizeof(r));
  r[0] = syscall(SYS_mmap, 0x20000000ul, 0x10000ul, 0x3ul, 0x32ul,
                 0xfffffffffffffffful, 0x0ul);
  r[2] = syscall(SYS_open, "/dev/ptmx", 0x8002ul, 0x0ul, 0, 0, 0);
  *(uint32_t*)0x20002b1e = (uint32_t)0x10;
  r[4] = syscall(SYS_ioctl, r[2], 0x5423ul, 0x20002b1eul, 0, 0, 0);
  *(uint32_t*)0x20009000 = (uint32_t)0x7;
  r[6] = syscall(SYS_ioctl, r[2], 0x5423ul, 0x20009000ul, 0, 0, 0);
}

int main() {
  int running, status;

  for (;;) {
    while (running < 32) {
      if (fork() == 0) {
        work();
        exit(0);
      }
      running++;
    }
    if (wait(&status) > 0)
      running--;
  }
}


While running it, sample/proc/slabinfo with:

# cat /proc/slabinfo | egrep "^kmalloc-2048"

It constantly grows.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help