Skip to content

Commit

Permalink
Merge tag 'fsi-updates-2018-08-08' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/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)
  • Loading branch information
Greg Kroah-Hartman committed Aug 8, 2018
2 parents a39284a + 15e2a72 commit 6d33b30
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 7 deletions.
39 changes: 32 additions & 7 deletions drivers/fsi/fsi-sbefifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
};
Expand Down Expand Up @@ -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 */
Expand All @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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 */
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/fsi/fsi-scom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 6d33b30

Please sign in to comment.