s390/hypfs: do not use stack buffers for hardware data
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 6 Sep 2018 08:06:57 +0000 (10:06 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 9 Oct 2018 09:20:53 +0000 (11:20 +0200)
With CONFIG_VMAP_STACK=y the stack is allocated from the vmalloc space.
Data structures passed to a hardware or a hypervisor interface that
requires V=R can not be allocated on the stack anymore.

Use kmalloc to get memory for the hypsfs_diag304 structure.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/hypfs/hypfs_sprp.c

index 5d85a03..601b707 100644 (file)
@@ -68,40 +68,44 @@ static int hypfs_sprp_create(void **data_ptr, void **free_ptr, size_t *size)
 
 static int __hypfs_sprp_ioctl(void __user *user_area)
 {
-       struct hypfs_diag304 diag304;
+       struct hypfs_diag304 *diag304;
        unsigned long cmd;
        void __user *udata;
        void *data;
        int rc;
 
-       if (copy_from_user(&diag304, user_area, sizeof(diag304)))
-               return -EFAULT;
-       if ((diag304.args[0] >> 8) != 0 || diag304.args[1] > DIAG304_CMD_MAX)
-               return -EINVAL;
-
+       rc = -ENOMEM;
        data = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!data)
-               return -ENOMEM;
-
-       udata = (void __user *)(unsigned long) diag304.data;
-       if (diag304.args[1] == DIAG304_SET_WEIGHTS ||
-           diag304.args[1] == DIAG304_SET_CAPPING)
-               if (copy_from_user(data, udata, PAGE_SIZE)) {
-                       rc = -EFAULT;
+       diag304 = kzalloc(sizeof(*diag304), GFP_KERNEL);
+       if (!data || !diag304)
+               goto out;
+
+       rc = -EFAULT;
+       if (copy_from_user(diag304, user_area, sizeof(*diag304)))
+               goto out;
+       rc = -EINVAL;
+       if ((diag304->args[0] >> 8) != 0 || diag304->args[1] > DIAG304_CMD_MAX)
+               goto out;
+
+       rc = -EFAULT;
+       udata = (void __user *)(unsigned long) diag304->data;
+       if (diag304->args[1] == DIAG304_SET_WEIGHTS ||
+           diag304->args[1] == DIAG304_SET_CAPPING)
+               if (copy_from_user(data, udata, PAGE_SIZE))
                        goto out;
-               }
 
-       cmd = *(unsigned long *) &diag304.args[0];
-       diag304.rc = hypfs_sprp_diag304(data, cmd);
+       cmd = *(unsigned long *) &diag304->args[0];
+       diag304->rc = hypfs_sprp_diag304(data, cmd);
 
-       if (diag304.args[1] == DIAG304_QUERY_PRP)
+       if (diag304->args[1] == DIAG304_QUERY_PRP)
                if (copy_to_user(udata, data, PAGE_SIZE)) {
                        rc = -EFAULT;
                        goto out;
                }
 
-       rc = copy_to_user(user_area, &diag304, sizeof(diag304)) ? -EFAULT : 0;
+       rc = copy_to_user(user_area, diag304, sizeof(*diag304)) ? -EFAULT : 0;
 out:
+       kfree(diag304);
        free_page((unsigned long) data);
        return rc;
 }