Commit f7e6b19b authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman Committed by Richard Weinberger

mtd: properly check all write ioctls for permissions

When doing a "write" ioctl call, properly check that we have permissions
to do so before copying anything from userspace or anything else so we
can "fail fast".  This includes also covering the MEMWRITE ioctl which
previously missed checking for this.

Cc: Miquel Raynal <miquel.raynal@bootlin.com>
Cc: Richard Weinberger <richard@nod.at>
Cc: Vignesh Raghavendra <vigneshr@ti.com>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
[rw: Fixed locking issue]
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent d15be546
...@@ -355,9 +355,6 @@ static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd, ...@@ -355,9 +355,6 @@ static int mtdchar_writeoob(struct file *file, struct mtd_info *mtd,
uint32_t retlen; uint32_t retlen;
int ret = 0; int ret = 0;
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
if (length > 4096) if (length > 4096)
return -EINVAL; return -EINVAL;
...@@ -643,6 +640,48 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) ...@@ -643,6 +640,48 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
pr_debug("MTD_ioctl\n"); pr_debug("MTD_ioctl\n");
/*
* Check the file mode to require "dangerous" commands to have write
* permissions.
*/
switch (cmd) {
/* "safe" commands */
case MEMGETREGIONCOUNT:
case MEMGETREGIONINFO:
case MEMGETINFO:
case MEMREADOOB:
case MEMREADOOB64:
case MEMLOCK:
case MEMUNLOCK:
case MEMISLOCKED:
case MEMGETOOBSEL:
case MEMGETBADBLOCK:
case MEMSETBADBLOCK:
case OTPSELECT:
case OTPGETREGIONCOUNT:
case OTPGETREGIONINFO:
case OTPLOCK:
case ECCGETLAYOUT:
case ECCGETSTATS:
case MTDFILEMODE:
case BLKPG:
case BLKRRPART:
break;
/* "dangerous" commands */
case MEMERASE:
case MEMERASE64:
case MEMWRITEOOB:
case MEMWRITEOOB64:
case MEMWRITE:
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
break;
default:
return -ENOTTY;
}
switch (cmd) { switch (cmd) {
case MEMGETREGIONCOUNT: case MEMGETREGIONCOUNT:
if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
...@@ -690,9 +729,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) ...@@ -690,9 +729,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
{ {
struct erase_info *erase; struct erase_info *erase;
if(!(file->f_mode & FMODE_WRITE))
return -EPERM;
erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL); erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);
if (!erase) if (!erase)
ret = -ENOMEM; ret = -ENOMEM;
...@@ -985,9 +1021,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) ...@@ -985,9 +1021,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
ret = 0; ret = 0;
break; break;
} }
default:
ret = -ENOTTY;
} }
return ret; return ret;
...@@ -1031,6 +1064,11 @@ static long mtdchar_compat_ioctl(struct file *file, unsigned int cmd, ...@@ -1031,6 +1064,11 @@ static long mtdchar_compat_ioctl(struct file *file, unsigned int cmd,
struct mtd_oob_buf32 buf; struct mtd_oob_buf32 buf;
struct mtd_oob_buf32 __user *buf_user = argp; struct mtd_oob_buf32 __user *buf_user = argp;
if (!(file->f_mode & FMODE_WRITE)) {
ret = -EPERM;
break;
}
if (copy_from_user(&buf, argp, sizeof(buf))) if (copy_from_user(&buf, argp, sizeof(buf)))
ret = -EFAULT; ret = -EFAULT;
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment