2019-03-15 09:33:20

by Gaurav Kohli

[permalink] [raw]
Subject: [PATCH] nvmem: core: Set no-read-write provider to avoid userspace read/write

Current nvmem framework allows user space to read all register space
populated by nvmem binary file, In case we don't want to expose value
of registers to userspace and only want kernel space to read cell
value from nvmem_cell_read_u32.

To protect the same, Add no-read-write property to prevent read
from userspace.

Signed-off-by: Gaurav Kohli <[email protected]>

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index f24008b..edd0e9f 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -27,6 +27,7 @@ struct nvmem_device {
struct kref refcnt;
size_t size;
bool read_only;
+ bool no_read_write;
int flags;
enum nvmem_type type;
struct bin_attribute eeprom;
@@ -120,6 +121,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
dev = container_of(kobj, struct device, kobj);
nvmem = to_nvmem_device(dev);

+ /* if no-read-write, then stop from reading */
+ if (nvmem->no_read_write)
+ return -EPERM;
/* Stop the user from reading */
if (pos >= nvmem->size)
return 0;
@@ -154,6 +158,10 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
dev = container_of(kobj, struct device, kobj);
nvmem = to_nvmem_device(dev);

+ /* if no-read-write, then stop from writing */
+ if (nvmem->no_read_write)
+ return -EPERM;
+
/* Stop the user from writing */
if (pos >= nvmem->size)
return -EFBIG;
@@ -651,6 +659,8 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->read_only = device_property_present(config->dev, "read-only") ||
config->read_only || !nvmem->reg_write;

+ nvmem->no_read_write = of_property_read_bool(np, "no-read-write") |
+ config->read_only;
if (config->root_only)
nvmem->dev.groups = nvmem->read_only ?
nvmem_ro_root_dev_groups :
--
1.9.1



2019-03-17 05:24:04

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] nvmem: core: Set no-read-write provider to avoid userspace read/write

Hi Gaurav,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.0 next-20190306]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Gaurav-Kohli/nvmem-core-Set-no-read-write-provider-to-avoid-userspace-read-write/20190317-105219
config: i386-randconfig-x010-201911 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

drivers//nvmem/core.c: In function 'nvmem_register':
>> drivers//nvmem/core.c:662:47: error: 'np' undeclared (first use in this function); did you mean 'up'?
nvmem->no_read_write = of_property_read_bool(np, "no-read-write") |
^~
up
drivers//nvmem/core.c:662:47: note: each undeclared identifier is reported only once for each function it appears in

vim +662 drivers//nvmem/core.c

602
603 /**
604 * nvmem_register() - Register a nvmem device for given nvmem_config.
605 * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
606 *
607 * @config: nvmem device configuration with which nvmem device is created.
608 *
609 * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
610 * on success.
611 */
612
613 struct nvmem_device *nvmem_register(const struct nvmem_config *config)
614 {
615 struct nvmem_device *nvmem;
616 int rval;
617
618 if (!config->dev)
619 return ERR_PTR(-EINVAL);
620
621 nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
622 if (!nvmem)
623 return ERR_PTR(-ENOMEM);
624
625 rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
626 if (rval < 0) {
627 kfree(nvmem);
628 return ERR_PTR(rval);
629 }
630
631 kref_init(&nvmem->refcnt);
632 INIT_LIST_HEAD(&nvmem->cells);
633
634 nvmem->id = rval;
635 nvmem->owner = config->owner;
636 if (!nvmem->owner && config->dev->driver)
637 nvmem->owner = config->dev->driver->owner;
638 nvmem->stride = config->stride ?: 1;
639 nvmem->word_size = config->word_size ?: 1;
640 nvmem->size = config->size;
641 nvmem->dev.type = &nvmem_provider_type;
642 nvmem->dev.bus = &nvmem_bus_type;
643 nvmem->dev.parent = config->dev;
644 nvmem->priv = config->priv;
645 nvmem->type = config->type;
646 nvmem->reg_read = config->reg_read;
647 nvmem->reg_write = config->reg_write;
648 if (!config->no_of_node)
649 nvmem->dev.of_node = config->dev->of_node;
650
651 if (config->id == -1 && config->name) {
652 dev_set_name(&nvmem->dev, "%s", config->name);
653 } else {
654 dev_set_name(&nvmem->dev, "%s%d",
655 config->name ? : "nvmem",
656 config->name ? config->id : nvmem->id);
657 }
658
659 nvmem->read_only = device_property_present(config->dev, "read-only") ||
660 config->read_only || !nvmem->reg_write;
661
> 662 nvmem->no_read_write = of_property_read_bool(np, "no-read-write") |
663 config->read_only;
664 if (config->root_only)
665 nvmem->dev.groups = nvmem->read_only ?
666 nvmem_ro_root_dev_groups :
667 nvmem_rw_root_dev_groups;
668 else
669 nvmem->dev.groups = nvmem->read_only ?
670 nvmem_ro_dev_groups :
671 nvmem_rw_dev_groups;
672
673 device_initialize(&nvmem->dev);
674
675 dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
676
677 rval = device_add(&nvmem->dev);
678 if (rval)
679 goto err_put_device;
680
681 if (config->compat) {
682 rval = nvmem_setup_compat(nvmem, config);
683 if (rval)
684 goto err_device_del;
685 }
686
687 if (config->cells) {
688 rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
689 if (rval)
690 goto err_teardown_compat;
691 }
692
693 rval = nvmem_add_cells_from_table(nvmem);
694 if (rval)
695 goto err_remove_cells;
696
697 rval = nvmem_add_cells_from_of(nvmem);
698 if (rval)
699 goto err_remove_cells;
700
701 blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
702
703 return nvmem;
704
705 err_remove_cells:
706 nvmem_device_remove_all_cells(nvmem);
707 err_teardown_compat:
708 if (config->compat)
709 device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
710 err_device_del:
711 device_del(&nvmem->dev);
712 err_put_device:
713 put_device(&nvmem->dev);
714
715 return ERR_PTR(rval);
716 }
717 EXPORT_SYMBOL_GPL(nvmem_register);
718

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (5.05 kB)
.config.gz (33.14 kB)
Download all attachments

2019-03-17 06:01:07

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] nvmem: core: Set no-read-write provider to avoid userspace read/write

Hi Gaurav,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.0 next-20190306]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Gaurav-Kohli/nvmem-core-Set-no-read-write-provider-to-avoid-userspace-read-write/20190317-105219
config: i386-randconfig-s0-201910 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

drivers//nvmem/core.c: In function 'nvmem_register':
>> drivers//nvmem/core.c:662:47: error: 'np' undeclared (first use in this function)
nvmem->no_read_write = of_property_read_bool(np, "no-read-write") |
^~
drivers//nvmem/core.c:662:47: note: each undeclared identifier is reported only once for each function it appears in

vim +/np +662 drivers//nvmem/core.c

602
603 /**
604 * nvmem_register() - Register a nvmem device for given nvmem_config.
605 * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
606 *
607 * @config: nvmem device configuration with which nvmem device is created.
608 *
609 * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
610 * on success.
611 */
612
613 struct nvmem_device *nvmem_register(const struct nvmem_config *config)
614 {
615 struct nvmem_device *nvmem;
616 int rval;
617
618 if (!config->dev)
619 return ERR_PTR(-EINVAL);
620
621 nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
622 if (!nvmem)
623 return ERR_PTR(-ENOMEM);
624
625 rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
626 if (rval < 0) {
627 kfree(nvmem);
628 return ERR_PTR(rval);
629 }
630
631 kref_init(&nvmem->refcnt);
632 INIT_LIST_HEAD(&nvmem->cells);
633
634 nvmem->id = rval;
635 nvmem->owner = config->owner;
636 if (!nvmem->owner && config->dev->driver)
637 nvmem->owner = config->dev->driver->owner;
638 nvmem->stride = config->stride ?: 1;
639 nvmem->word_size = config->word_size ?: 1;
640 nvmem->size = config->size;
641 nvmem->dev.type = &nvmem_provider_type;
642 nvmem->dev.bus = &nvmem_bus_type;
643 nvmem->dev.parent = config->dev;
644 nvmem->priv = config->priv;
645 nvmem->type = config->type;
646 nvmem->reg_read = config->reg_read;
647 nvmem->reg_write = config->reg_write;
648 if (!config->no_of_node)
649 nvmem->dev.of_node = config->dev->of_node;
650
651 if (config->id == -1 && config->name) {
652 dev_set_name(&nvmem->dev, "%s", config->name);
653 } else {
654 dev_set_name(&nvmem->dev, "%s%d",
655 config->name ? : "nvmem",
656 config->name ? config->id : nvmem->id);
657 }
658
659 nvmem->read_only = device_property_present(config->dev, "read-only") ||
660 config->read_only || !nvmem->reg_write;
661
> 662 nvmem->no_read_write = of_property_read_bool(np, "no-read-write") |
663 config->read_only;
664 if (config->root_only)
665 nvmem->dev.groups = nvmem->read_only ?
666 nvmem_ro_root_dev_groups :
667 nvmem_rw_root_dev_groups;
668 else
669 nvmem->dev.groups = nvmem->read_only ?
670 nvmem_ro_dev_groups :
671 nvmem_rw_dev_groups;
672
673 device_initialize(&nvmem->dev);
674
675 dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
676
677 rval = device_add(&nvmem->dev);
678 if (rval)
679 goto err_put_device;
680
681 if (config->compat) {
682 rval = nvmem_setup_compat(nvmem, config);
683 if (rval)
684 goto err_device_del;
685 }
686
687 if (config->cells) {
688 rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
689 if (rval)
690 goto err_teardown_compat;
691 }
692
693 rval = nvmem_add_cells_from_table(nvmem);
694 if (rval)
695 goto err_remove_cells;
696
697 rval = nvmem_add_cells_from_of(nvmem);
698 if (rval)
699 goto err_remove_cells;
700
701 blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
702
703 return nvmem;
704
705 err_remove_cells:
706 nvmem_device_remove_all_cells(nvmem);
707 err_teardown_compat:
708 if (config->compat)
709 device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
710 err_device_del:
711 device_del(&nvmem->dev);
712 err_put_device:
713 put_device(&nvmem->dev);
714
715 return ERR_PTR(rval);
716 }
717 EXPORT_SYMBOL_GPL(nvmem_register);
718

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (4.99 kB)
.config.gz (36.71 kB)
Download all attachments

2019-03-17 14:10:27

by Gaurav Kohli

[permalink] [raw]
Subject: Re: [PATCH] nvmem: core: Set no-read-write provider to avoid userspace read/write

Oh i was in wrong version, will upload new patch v2, thanks for update.

Regards

Gaurav

On 3/17/2019 9:51 AM, kbuild test robot wrote:
> Hi Gaurav,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v5.0 next-20190306]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Gaurav-Kohli/nvmem-core-Set-no-read-write-provider-to-avoid-userspace-read-write/20190317-105219
> config: i386-randconfig-x010-201911 (attached as .config)
> compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=i386
>
> All errors (new ones prefixed by >>):
>
> drivers//nvmem/core.c: In function 'nvmem_register':
>>> drivers//nvmem/core.c:662:47: error: 'np' undeclared (first use in this function); did you mean 'up'?
> nvmem->no_read_write = of_property_read_bool(np, "no-read-write") |
> ^~
> up
> drivers//nvmem/core.c:662:47: note: each undeclared identifier is reported only once for each function it appears in
>
> vim +662 drivers//nvmem/core.c
>
> 602
> 603 /**
> 604 * nvmem_register() - Register a nvmem device for given nvmem_config.
> 605 * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
> 606 *
> 607 * @config: nvmem device configuration with which nvmem device is created.
> 608 *
> 609 * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
> 610 * on success.
> 611 */
> 612
> 613 struct nvmem_device *nvmem_register(const struct nvmem_config *config)
> 614 {
> 615 struct nvmem_device *nvmem;
> 616 int rval;
> 617
> 618 if (!config->dev)
> 619 return ERR_PTR(-EINVAL);
> 620
> 621 nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
> 622 if (!nvmem)
> 623 return ERR_PTR(-ENOMEM);
> 624
> 625 rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
> 626 if (rval < 0) {
> 627 kfree(nvmem);
> 628 return ERR_PTR(rval);
> 629 }
> 630
> 631 kref_init(&nvmem->refcnt);
> 632 INIT_LIST_HEAD(&nvmem->cells);
> 633
> 634 nvmem->id = rval;
> 635 nvmem->owner = config->owner;
> 636 if (!nvmem->owner && config->dev->driver)
> 637 nvmem->owner = config->dev->driver->owner;
> 638 nvmem->stride = config->stride ?: 1;
> 639 nvmem->word_size = config->word_size ?: 1;
> 640 nvmem->size = config->size;
> 641 nvmem->dev.type = &nvmem_provider_type;
> 642 nvmem->dev.bus = &nvmem_bus_type;
> 643 nvmem->dev.parent = config->dev;
> 644 nvmem->priv = config->priv;
> 645 nvmem->type = config->type;
> 646 nvmem->reg_read = config->reg_read;
> 647 nvmem->reg_write = config->reg_write;
> 648 if (!config->no_of_node)
> 649 nvmem->dev.of_node = config->dev->of_node;
> 650
> 651 if (config->id == -1 && config->name) {
> 652 dev_set_name(&nvmem->dev, "%s", config->name);
> 653 } else {
> 654 dev_set_name(&nvmem->dev, "%s%d",
> 655 config->name ? : "nvmem",
> 656 config->name ? config->id : nvmem->id);
> 657 }
> 658
> 659 nvmem->read_only = device_property_present(config->dev, "read-only") ||
> 660 config->read_only || !nvmem->reg_write;
> 661
> > 662 nvmem->no_read_write = of_property_read_bool(np, "no-read-write") |
> 663 config->read_only;
> 664 if (config->root_only)
> 665 nvmem->dev.groups = nvmem->read_only ?
> 666 nvmem_ro_root_dev_groups :
> 667 nvmem_rw_root_dev_groups;
> 668 else
> 669 nvmem->dev.groups = nvmem->read_only ?
> 670 nvmem_ro_dev_groups :
> 671 nvmem_rw_dev_groups;
> 672
> 673 device_initialize(&nvmem->dev);
> 674
> 675 dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
> 676
> 677 rval = device_add(&nvmem->dev);
> 678 if (rval)
> 679 goto err_put_device;
> 680
> 681 if (config->compat) {
> 682 rval = nvmem_setup_compat(nvmem, config);
> 683 if (rval)
> 684 goto err_device_del;
> 685 }
> 686
> 687 if (config->cells) {
> 688 rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
> 689 if (rval)
> 690 goto err_teardown_compat;
> 691 }
> 692
> 693 rval = nvmem_add_cells_from_table(nvmem);
> 694 if (rval)
> 695 goto err_remove_cells;
> 696
> 697 rval = nvmem_add_cells_from_of(nvmem);
> 698 if (rval)
> 699 goto err_remove_cells;
> 700
> 701 blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
> 702
> 703 return nvmem;
> 704
> 705 err_remove_cells:
> 706 nvmem_device_remove_all_cells(nvmem);
> 707 err_teardown_compat:
> 708 if (config->compat)
> 709 device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
> 710 err_device_del:
> 711 device_del(&nvmem->dev);
> 712 err_put_device:
> 713 put_device(&nvmem->dev);
> 714
> 715 return ERR_PTR(rval);
> 716 }
> 717 EXPORT_SYMBOL_GPL(nvmem_register);
> 718
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation

--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center,
Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.