aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/mtdchar.c255
-rw-r--r--fs/compat_ioctl.c51
2 files changed, 180 insertions, 126 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index ad4b8618977d..51bb0b092003 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -14,6 +14,7 @@
14#include <linux/sched.h> 14#include <linux/sched.h>
15#include <linux/smp_lock.h> 15#include <linux/smp_lock.h>
16#include <linux/backing-dev.h> 16#include <linux/backing-dev.h>
17#include <linux/compat.h>
17 18
18#include <linux/mtd/mtd.h> 19#include <linux/mtd/mtd.h>
19#include <linux/mtd/compatmac.h> 20#include <linux/mtd/compatmac.h>
@@ -355,6 +356,100 @@ static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
355# define otp_select_filemode(f,m) -EOPNOTSUPP 356# define otp_select_filemode(f,m) -EOPNOTSUPP
356#endif 357#endif
357 358
359static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,
360 uint64_t start, uint32_t length, void __user *ptr,
361 uint32_t __user *retp)
362{
363 struct mtd_oob_ops ops;
364 uint32_t retlen;
365 int ret = 0;
366
367 if (!(file->f_mode & FMODE_WRITE))
368 return -EPERM;
369
370 if (length > 4096)
371 return -EINVAL;
372
373 if (!mtd->write_oob)
374 ret = -EOPNOTSUPP;
375 else
376 ret = access_ok(VERIFY_READ, ptr, length) ? 0 : EFAULT;
377
378 if (ret)
379 return ret;
380
381 ops.ooblen = length;
382 ops.ooboffs = start & (mtd->oobsize - 1);
383 ops.datbuf = NULL;
384 ops.mode = MTD_OOB_PLACE;
385
386 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
387 return -EINVAL;
388
389 ops.oobbuf = kmalloc(length, GFP_KERNEL);
390 if (!ops.oobbuf)
391 return -ENOMEM;
392
393 if (copy_from_user(ops.oobbuf, ptr, length)) {
394 kfree(ops.oobbuf);
395 return -EFAULT;
396 }
397
398 start &= ~((uint64_t)mtd->oobsize - 1);
399 ret = mtd->write_oob(mtd, start, &ops);
400
401 if (ops.oobretlen > 0xFFFFFFFFU)
402 ret = -EOVERFLOW;
403 retlen = ops.oobretlen;
404 if (copy_to_user(retp, &retlen, sizeof(length)))
405 ret = -EFAULT;
406
407 kfree(ops.oobbuf);
408 return ret;
409}
410
411static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
412 uint32_t length, void __user *ptr, uint32_t __user *retp)
413{
414 struct mtd_oob_ops ops;
415 int ret = 0;
416
417 if (length > 4096)
418 return -EINVAL;
419
420 if (!mtd->read_oob)
421 ret = -EOPNOTSUPP;
422 else
423 ret = access_ok(VERIFY_WRITE, ptr,
424 length) ? 0 : -EFAULT;
425 if (ret)
426 return ret;
427
428 ops.ooblen = length;
429 ops.ooboffs = start & (mtd->oobsize - 1);
430 ops.datbuf = NULL;
431 ops.mode = MTD_OOB_PLACE;
432
433 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
434 return -EINVAL;
435
436 ops.oobbuf = kmalloc(length, GFP_KERNEL);
437 if (!ops.oobbuf)
438 return -ENOMEM;
439
440 start &= ~((uint64_t)mtd->oobsize - 1);
441 ret = mtd->read_oob(mtd, start, &ops);
442
443 if (put_user(ops.oobretlen, retp))
444 ret = -EFAULT;
445 else if (ops.oobretlen && copy_to_user(ptr, ops.oobbuf,
446 ops.oobretlen))
447 ret = -EFAULT;
448
449 kfree(ops.oobbuf);
450 return ret;
451}
452
358static int mtd_ioctl(struct inode *inode, struct file *file, 453static int mtd_ioctl(struct inode *inode, struct file *file,
359 u_int cmd, u_long arg) 454 u_int cmd, u_long arg)
360{ 455{
@@ -487,100 +582,28 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
487 case MEMWRITEOOB: 582 case MEMWRITEOOB:
488 { 583 {
489 struct mtd_oob_buf buf; 584 struct mtd_oob_buf buf;
490 struct mtd_oob_ops ops; 585 struct mtd_oob_buf __user *buf_user = argp;
491 struct mtd_oob_buf __user *user_buf = argp;
492 uint32_t retlen;
493
494 if(!(file->f_mode & FMODE_WRITE))
495 return -EPERM;
496
497 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
498 return -EFAULT;
499
500 if (buf.length > 4096)
501 return -EINVAL;
502
503 if (!mtd->write_oob)
504 ret = -EOPNOTSUPP;
505 else
506 ret = access_ok(VERIFY_READ, buf.ptr,
507 buf.length) ? 0 : EFAULT;
508
509 if (ret)
510 return ret;
511
512 ops.ooblen = buf.length;
513 ops.ooboffs = buf.start & (mtd->oobsize - 1);
514 ops.datbuf = NULL;
515 ops.mode = MTD_OOB_PLACE;
516
517 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
518 return -EINVAL;
519
520 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
521 if (!ops.oobbuf)
522 return -ENOMEM;
523
524 if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) {
525 kfree(ops.oobbuf);
526 return -EFAULT;
527 }
528
529 buf.start &= ~(mtd->oobsize - 1);
530 ret = mtd->write_oob(mtd, buf.start, &ops);
531 586
532 if (ops.oobretlen > 0xFFFFFFFFU) 587 /* NOTE: writes return length to buf_user->length */
533 ret = -EOVERFLOW; 588 if (copy_from_user(&buf, argp, sizeof(buf)))
534 retlen = ops.oobretlen;
535 if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length)))
536 ret = -EFAULT; 589 ret = -EFAULT;
537 590 else
538 kfree(ops.oobbuf); 591 ret = mtd_do_writeoob(file, mtd, buf.start, buf.length,
592 buf.ptr, &buf_user->length);
539 break; 593 break;
540
541 } 594 }
542 595
543 case MEMREADOOB: 596 case MEMREADOOB:
544 { 597 {
545 struct mtd_oob_buf buf; 598 struct mtd_oob_buf buf;
546 struct mtd_oob_ops ops; 599 struct mtd_oob_buf __user *buf_user = argp;
547
548 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
549 return -EFAULT;
550
551 if (buf.length > 4096)
552 return -EINVAL;
553
554 if (!mtd->read_oob)
555 ret = -EOPNOTSUPP;
556 else
557 ret = access_ok(VERIFY_WRITE, buf.ptr,
558 buf.length) ? 0 : -EFAULT;
559 if (ret)
560 return ret;
561
562 ops.ooblen = buf.length;
563 ops.ooboffs = buf.start & (mtd->oobsize - 1);
564 ops.datbuf = NULL;
565 ops.mode = MTD_OOB_PLACE;
566 600
567 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) 601 /* NOTE: writes return length to buf_user->start */
568 return -EINVAL; 602 if (copy_from_user(&buf, argp, sizeof(buf)))
569
570 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
571 if (!ops.oobbuf)
572 return -ENOMEM;
573
574 buf.start &= ~(mtd->oobsize - 1);
575 ret = mtd->read_oob(mtd, buf.start, &ops);
576
577 if (put_user(ops.oobretlen, (uint32_t __user *)argp))
578 ret = -EFAULT;
579 else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf,
580 ops.oobretlen))
581 ret = -EFAULT; 603 ret = -EFAULT;
582 604 else
583 kfree(ops.oobbuf); 605 ret = mtd_do_readoob(mtd, buf.start, buf.length,
606 buf.ptr, &buf_user->start);
584 break; 607 break;
585 } 608 }
586 609
@@ -771,6 +794,67 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
771 return ret; 794 return ret;
772} /* memory_ioctl */ 795} /* memory_ioctl */
773 796
797#ifdef CONFIG_COMPAT
798
799struct mtd_oob_buf32 {
800 u_int32_t start;
801 u_int32_t length;
802 compat_caddr_t ptr; /* unsigned char* */
803};
804
805#define MEMWRITEOOB32 _IOWR('M', 3, struct mtd_oob_buf32)
806#define MEMREADOOB32 _IOWR('M', 4, struct mtd_oob_buf32)
807
808static long mtd_compat_ioctl(struct file *file, unsigned int cmd,
809 unsigned long arg)
810{
811 struct mtd_file_info *mfi = file->private_data;
812 struct mtd_info *mtd = mfi->mtd;
813 void __user *argp = (void __user *)arg;
814 int ret = 0;
815
816 lock_kernel();
817
818 switch (cmd) {
819 case MEMWRITEOOB32:
820 {
821 struct mtd_oob_buf32 buf;
822 struct mtd_oob_buf32 __user *buf_user = argp;
823
824 if (copy_from_user(&buf, argp, sizeof(buf)))
825 ret = -EFAULT;
826 else
827 ret = mtd_do_writeoob(file, mtd, buf.start,
828 buf.length, compat_ptr(buf.ptr),
829 &buf_user->length);
830 break;
831 }
832
833 case MEMREADOOB32:
834 {
835 struct mtd_oob_buf32 buf;
836 struct mtd_oob_buf32 __user *buf_user = argp;
837
838 /* NOTE: writes return length to buf->start */
839 if (copy_from_user(&buf, argp, sizeof(buf)))
840 ret = -EFAULT;
841 else
842 ret = mtd_do_readoob(mtd, buf.start,
843 buf.length, compat_ptr(buf.ptr),
844 &buf_user->start);
845 break;
846 }
847 default:
848 ret = -ENOIOCTLCMD;
849 }
850
851 unlock_kernel();
852
853 return ret;
854}
855
856#endif /* CONFIG_COMPAT */
857
774/* 858/*
775 * try to determine where a shared mapping can be made 859 * try to determine where a shared mapping can be made
776 * - only supported for NOMMU at the moment (MMU can't doesn't copy private 860 * - only supported for NOMMU at the moment (MMU can't doesn't copy private
@@ -830,6 +914,9 @@ static const struct file_operations mtd_fops = {
830 .read = mtd_read, 914 .read = mtd_read,
831 .write = mtd_write, 915 .write = mtd_write,
832 .ioctl = mtd_ioctl, 916 .ioctl = mtd_ioctl,
917#ifdef CONFIG_COMPAT
918 .compat_ioctl = mtd_compat_ioctl,
919#endif
833 .open = mtd_open, 920 .open = mtd_open,
834 .release = mtd_close, 921 .release = mtd_close,
835 .mmap = mtd_mmap, 922 .mmap = mtd_mmap,
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index c603ca2c223a..196397bff086 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1411,46 +1411,6 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
1411#define HIDPGETCONNLIST _IOR('H', 210, int) 1411#define HIDPGETCONNLIST _IOR('H', 210, int)
1412#define HIDPGETCONNINFO _IOR('H', 211, int) 1412#define HIDPGETCONNINFO _IOR('H', 211, int)
1413 1413
1414struct mtd_oob_buf32 {
1415 u_int32_t start;
1416 u_int32_t length;
1417 compat_caddr_t ptr; /* unsigned char* */
1418};
1419
1420#define MEMWRITEOOB32 _IOWR('M',3,struct mtd_oob_buf32)
1421#define MEMREADOOB32 _IOWR('M',4,struct mtd_oob_buf32)
1422
1423static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
1424{
1425 struct mtd_oob_buf __user *buf = compat_alloc_user_space(sizeof(*buf));
1426 struct mtd_oob_buf32 __user *buf32 = compat_ptr(arg);
1427 u32 data;
1428 char __user *datap;
1429 unsigned int real_cmd;
1430 int err;
1431
1432 real_cmd = (cmd == MEMREADOOB32) ?
1433 MEMREADOOB : MEMWRITEOOB;
1434
1435 if (copy_in_user(&buf->start, &buf32->start,
1436 2 * sizeof(u32)) ||
1437 get_user(data, &buf32->ptr))
1438 return -EFAULT;
1439 datap = compat_ptr(data);
1440 if (put_user(datap, &buf->ptr))
1441 return -EFAULT;
1442
1443 err = sys_ioctl(fd, real_cmd, (unsigned long) buf);
1444
1445 if (!err) {
1446 if (copy_in_user(&buf32->start, &buf->start,
1447 2 * sizeof(u32)))
1448 err = -EFAULT;
1449 }
1450
1451 return err;
1452}
1453
1454#ifdef CONFIG_BLOCK 1414#ifdef CONFIG_BLOCK
1455struct raw32_config_request 1415struct raw32_config_request
1456{ 1416{
@@ -2439,8 +2399,17 @@ COMPATIBLE_IOCTL(MEMLOCK)
2439COMPATIBLE_IOCTL(MEMUNLOCK) 2399COMPATIBLE_IOCTL(MEMUNLOCK)
2440COMPATIBLE_IOCTL(MEMGETREGIONCOUNT) 2400COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
2441COMPATIBLE_IOCTL(MEMGETREGIONINFO) 2401COMPATIBLE_IOCTL(MEMGETREGIONINFO)
2402COMPATIBLE_IOCTL(MEMSETOOBSEL)
2403COMPATIBLE_IOCTL(MEMGETOOBSEL)
2442COMPATIBLE_IOCTL(MEMGETBADBLOCK) 2404COMPATIBLE_IOCTL(MEMGETBADBLOCK)
2443COMPATIBLE_IOCTL(MEMSETBADBLOCK) 2405COMPATIBLE_IOCTL(MEMSETBADBLOCK)
2406COMPATIBLE_IOCTL(OTPSELECT)
2407COMPATIBLE_IOCTL(OTPGETREGIONCOUNT)
2408COMPATIBLE_IOCTL(OTPGETREGIONINFO)
2409COMPATIBLE_IOCTL(OTPLOCK)
2410COMPATIBLE_IOCTL(ECCGETLAYOUT)
2411COMPATIBLE_IOCTL(ECCGETSTATS)
2412COMPATIBLE_IOCTL(MTDFILEMODE)
2444COMPATIBLE_IOCTL(MEMERASE64) 2413COMPATIBLE_IOCTL(MEMERASE64)
2445/* NBD */ 2414/* NBD */
2446ULONG_IOCTL(NBD_SET_SOCK) 2415ULONG_IOCTL(NBD_SET_SOCK)
@@ -2551,8 +2520,6 @@ COMPATIBLE_IOCTL(JSIOCGBUTTONS)
2551COMPATIBLE_IOCTL(JSIOCGNAME(0)) 2520COMPATIBLE_IOCTL(JSIOCGNAME(0))
2552 2521
2553/* now things that need handlers */ 2522/* now things that need handlers */
2554HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
2555HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
2556#ifdef CONFIG_NET 2523#ifdef CONFIG_NET
2557HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) 2524HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
2558HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) 2525HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)