diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-08-08 08:37:53 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-08-08 08:37:53 +0200 |
commit | 6d33b3069ed84be9b8430ccc7705d0e747542a4f (patch) | |
tree | 495801abfd12692d4f9d0b0bffc234ee299baa4c | |
parent | a39284ae9d2ad09975c8ae33f1bd0f05fbfbf6ee (diff) | |
parent | 15e2a7218c2788d79c5633336d17cb9428c221e7 (diff) |
Merge tag 'fsi-updates-2018-08-08' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/linux-fsi into char-misc-next
Ben writes:
FSI Updates for 4.19
This adds two FSI fixes:
- Fix a NULL dereference in the scom driver
- Fix a command buffer size issue in the sbefifo driver that
breaks some operations with POWER system debugger (cronus)
-rw-r--r-- | drivers/fsi/fsi-sbefifo.c | 39 | ||||
-rw-r--r-- | drivers/fsi/fsi-scom.c | 1 |
2 files changed, 33 insertions, 7 deletions
diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c index 7550497da8ef..ae861342626e 100644 --- a/drivers/fsi/fsi-sbefifo.c +++ b/drivers/fsi/fsi-sbefifo.c @@ -30,6 +30,7 @@ #include <linux/delay.h> #include <linux/uio.h> #include <linux/vmalloc.h> +#include <linux/mm.h> /* * The SBEFIFO is a pipe-like FSI device for communicating with @@ -110,7 +111,7 @@ enum sbe_state #define SBEFIFO_TIMEOUT_IN_RSP 1000 /* Other constants */ -#define SBEFIFO_MAX_CMD_LEN PAGE_SIZE +#define SBEFIFO_MAX_USER_CMD_LEN (0x100000 + PAGE_SIZE) #define SBEFIFO_RESET_MAGIC 0x52534554 /* "RSET" */ struct sbefifo { @@ -128,6 +129,7 @@ struct sbefifo { struct sbefifo_user { struct sbefifo *sbefifo; struct mutex file_lock; + void *cmd_page; void *pending_cmd; size_t pending_len; }; @@ -726,7 +728,7 @@ int sbefifo_submit(struct device *dev, const __be32 *command, size_t cmd_len, return -ENODEV; if (WARN_ON_ONCE(sbefifo->magic != SBEFIFO_MAGIC)) return -ENODEV; - if (!resp_len || !command || !response || cmd_len > SBEFIFO_MAX_CMD_LEN) + if (!resp_len || !command || !response) return -EINVAL; /* Prepare iov iterator */ @@ -751,6 +753,15 @@ EXPORT_SYMBOL_GPL(sbefifo_submit); /* * Char device interface */ + +static void sbefifo_release_command(struct sbefifo_user *user) +{ + if (is_vmalloc_addr(user->pending_cmd)) + vfree(user->pending_cmd); + user->pending_cmd = NULL; + user->pending_len = 0; +} + static int sbefifo_user_open(struct inode *inode, struct file *file) { struct sbefifo *sbefifo = container_of(inode->i_cdev, struct sbefifo, cdev); @@ -762,8 +773,8 @@ static int sbefifo_user_open(struct inode *inode, struct file *file) file->private_data = user; user->sbefifo = sbefifo; - user->pending_cmd = (void *)__get_free_page(GFP_KERNEL); - if (!user->pending_cmd) { + user->cmd_page = (void *)__get_free_page(GFP_KERNEL); + if (!user->cmd_page) { kfree(user); return -ENOMEM; } @@ -816,7 +827,7 @@ static ssize_t sbefifo_user_read(struct file *file, char __user *buf, /* Extract the response length */ rc = len - iov_iter_count(&resp_iter); bail: - user->pending_len = 0; + sbefifo_release_command(user); mutex_unlock(&user->file_lock); return rc; } @@ -831,13 +842,23 @@ static ssize_t sbefifo_user_write(struct file *file, const char __user *buf, if (!user) return -EINVAL; sbefifo = user->sbefifo; - if (len > SBEFIFO_MAX_CMD_LEN) + if (len > SBEFIFO_MAX_USER_CMD_LEN) return -EINVAL; if (len & 3) return -EINVAL; mutex_lock(&user->file_lock); + /* Can we use the pre-allocate buffer ? If not, allocate */ + if (len <= PAGE_SIZE) + user->pending_cmd = user->cmd_page; + else + user->pending_cmd = vmalloc(len); + if (!user->pending_cmd) { + rc = -ENOMEM; + goto bail; + } + /* Copy the command into the staging buffer */ if (copy_from_user(user->pending_cmd, buf, len)) { rc = -EFAULT; @@ -863,6 +884,9 @@ static ssize_t sbefifo_user_write(struct file *file, const char __user *buf, /* Update the staging buffer size */ user->pending_len = len; bail: + if (!user->pending_len) + sbefifo_release_command(user); + mutex_unlock(&user->file_lock); /* And that's it, we'll issue the command on a read */ @@ -876,7 +900,8 @@ static int sbefifo_user_release(struct inode *inode, struct file *file) if (!user) return -EINVAL; - free_page((unsigned long)user->pending_cmd); + sbefifo_release_command(user); + free_page((unsigned long)user->cmd_page); kfree(user); return 0; diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c index 0f303a700f69..df94021dd9d1 100644 --- a/drivers/fsi/fsi-scom.c +++ b/drivers/fsi/fsi-scom.c @@ -598,6 +598,7 @@ static int scom_probe(struct device *dev) kfree(scom); return -ENODEV; } + scom->fsi_dev = fsi_dev; /* Create chardev for userspace access */ scom->dev.type = &fsi_cdev_type; |