[S390] Fix memory leak in /proc/cio_ignore
authorChristian Borntraeger <borntraeger@de.ibm.com>
Tue, 6 Oct 2009 08:34:00 +0000 (10:34 +0200)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Tue, 6 Oct 2009 08:35:07 +0000 (10:35 +0200)
There is a memory leak in /proc/cio_ignore. The iterator is allocated
in cio_ignore_proc_seq_start, but never freed in
cio_ignore_proc_seq_stop, because we cannot use the iterator
that was passed by seqfile. The seqfile interface passes the last
seen iterator to the stop function and not the first one. Since our
next function will return NULL at the end, the iter passed to
cio_ignore_proc_seq_stop is NULL. The original iter has leaked.
The solution is to use seq_open_private.

Found with kmemleak:
unreferenced object 0x1c720580 (size 32):
  comm "head", pid 973, jiffies 4294958302
  hex dump (first 32 bytes):
    00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00  ................
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  backtrace:
    [<0000000000203154>] kmem_cache_alloc+0x190/0x19c
    [<00000000003fb462>] cio_ignore_proc_seq_start+0x5e/0x128
    [<0000000000231018>] seq_read+0xc8/0x4bc
    [<0000000000273954>] proc_reg_read+0xa8/0xf4
    [<000000000020e3d8>] vfs_read+0xac/0x1a4
    [<000000000020e5c6>] SyS_read+0x52/0xa8
    [<000000000011836e>] sysc_noemu+0x10/0x16
    [<0000004690b7936c>] 0x4690b7936c

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/blacklist.c

index 6565f02..7eab9ab 100644 (file)
@@ -265,13 +265,11 @@ struct ccwdev_iter {
 static void *
 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
 {
-       struct ccwdev_iter *iter;
+       struct ccwdev_iter *iter = s->private;
 
        if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
                return NULL;
-       iter = kzalloc(sizeof(struct ccwdev_iter), GFP_KERNEL);
-       if (!iter)
-               return ERR_PTR(-ENOMEM);
+       memset(iter, 0, sizeof(*iter));
        iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
        iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
        return iter;
@@ -280,8 +278,6 @@ cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
 static void
 cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
 {
-       if (!IS_ERR(it))
-               kfree(it);
 }
 
 static void *
@@ -378,14 +374,15 @@ static const struct seq_operations cio_ignore_proc_seq_ops = {
 static int
 cio_ignore_proc_open(struct inode *inode, struct file *file)
 {
-       return seq_open(file, &cio_ignore_proc_seq_ops);
+       return seq_open_private(file, &cio_ignore_proc_seq_ops,
+                               sizeof(struct ccwdev_iter));
 }
 
 static const struct file_operations cio_ignore_proc_fops = {
        .open    = cio_ignore_proc_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
-       .release = seq_release,
+       .release = seq_release_private,
        .write   = cio_ignore_write,
 };