[POWERPC] spufs: fix possible memory corruption is spufs_mem_write
authorArnd Bergmann <arnd.bergmann@de.ibm.com>
Fri, 9 Mar 2007 23:05:35 +0000 (00:05 +0100)
committerArnd Bergmann <arnd@klappe.arndb.de>
Fri, 9 Mar 2007 23:07:48 +0000 (00:07 +0100)
Due to a buggy unsigned comparison, it was possible to write
beyond the end of the local store file in spufs under some
circumstances.

This rewrites the buggy function to look more like
simple_copy_from_buffer.

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Cc: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
arch/powerpc/platforms/cell/spufs/file.c

index b00653d69c01cd654749d9a51231f6db7f258072..505266a568d4221d9305c9e4ef1b0e99cc3ffc88 100644 (file)
@@ -63,8 +63,8 @@ static ssize_t
 spufs_mem_read(struct file *file, char __user *buffer,
                                size_t size, loff_t *pos)
 {
-       int ret;
        struct spu_context *ctx = file->private_data;
+       ssize_t ret;
 
        spu_acquire(ctx);
        ret = __spufs_mem_read(ctx, buffer, size, pos);
@@ -74,25 +74,29 @@ spufs_mem_read(struct file *file, char __user *buffer,
 
 static ssize_t
 spufs_mem_write(struct file *file, const char __user *buffer,
-                                       size_t size, loff_t *pos)
+                                       size_t size, loff_t *ppos)
 {
        struct spu_context *ctx = file->private_data;
        char *local_store;
+       loff_t pos = *ppos;
        int ret;
 
-       size = min_t(ssize_t, LS_SIZE - *pos, size);
-       if (size <= 0)
+       if (pos < 0)
+               return -EINVAL;
+       if (pos > LS_SIZE)
                return -EFBIG;
-       *pos += size;
+       if (size > LS_SIZE - pos)
+               size = LS_SIZE - pos;
 
        spu_acquire(ctx);
-
        local_store = ctx->ops->get_ls(ctx);
-       ret = copy_from_user(local_store + *pos - size,
-                            buffer, size) ? -EFAULT : size;
-
+       ret = copy_from_user(local_store + pos, buffer, size);
        spu_release(ctx);
-       return ret;
+
+       if (ret)
+               return -EFAULT;
+       *ppos = pos + size;
+       return size;
 }
 
 static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,