Patchwork nvmem: core: Set no-read-write provider to avoid userspace read/write

login
register
mail settings
Submitter Gaurav Kohli
Date March 15, 2019, 9:25 a.m.
Message ID <1552641937-19444-1-git-send-email-gkohli@codeaurora.org>
Download mbox | patch
Permalink /patch/749423/
State New
Headers show

Comments

Gaurav Kohli - March 15, 2019, 9:25 a.m.
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 <gkohli@codeaurora.org>
kbuild test robot - March 17, 2019, 4:21 a.m.
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
kbuild test robot - March 17, 2019, 5:39 a.m.
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
Gaurav Kohli - March 17, 2019, 2:09 p.m.
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

Patch

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 :