Staging: lustre: error handling tweaks in obd_ioctl_getdata()
authorDan Carpenter <dan.carpenter@oracle.com>
Mon, 22 Dec 2014 07:52:39 +0000 (10:52 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 17 Jan 2015 23:46:22 +0000 (15:46 -0800)
1)  The places which called copy_from_user() were returning the number
of bytes not copied instead of -EFAULT.

2) The user could trigger a memory leak if the condition
"(hdr.ioc_len != data->ioc_len)" was true.  Instead of adding a new call
to OBD_FREE_LARGE(), I created a free_buf label and changed everything
to use that label.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/lustre/lustre/obdclass/linux/linux-module.c

index b5007b8..b94aeac 100644 (file)
@@ -83,9 +83,8 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
        int err;
        int offset = 0;
 
-       err = copy_from_user(&hdr, (void *)arg, sizeof(hdr));
-       if (err)
-               return err;
+       if (copy_from_user(&hdr, (void *)arg, sizeof(hdr)))
+               return -EFAULT;
 
        if (hdr.ioc_version != OBD_IOCTL_VERSION) {
                CERROR("Version mismatch kernel (%x) vs application (%x)\n",
@@ -117,18 +116,19 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
        *len = hdr.ioc_len;
        data = (struct obd_ioctl_data *)*buf;
 
-       err = copy_from_user(*buf, (void *)arg, hdr.ioc_len);
-       if (err) {
-               OBD_FREE_LARGE(*buf, hdr.ioc_len);
-               return err;
+       if (copy_from_user(*buf, (void *)arg, hdr.ioc_len)) {
+               err = -EFAULT;
+               goto free_buf;
+       }
+       if (hdr.ioc_len != data->ioc_len) {
+               err = -EINVAL;
+               goto free_buf;
        }
-       if (hdr.ioc_len != data->ioc_len)
-               return -EINVAL;
 
        if (obd_ioctl_is_invalid(data)) {
                CERROR("ioctl not correctly formatted\n");
-               OBD_FREE_LARGE(*buf, hdr.ioc_len);
-               return -EINVAL;
+               err = -EINVAL;
+               goto free_buf;
        }
 
        if (data->ioc_inllen1) {
@@ -151,6 +151,10 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
        }
 
        return 0;
+
+free_buf:
+       OBD_FREE_LARGE(*buf, hdr.ioc_len);
+       return err;
 }
 EXPORT_SYMBOL(obd_ioctl_getdata);