Message ID | 20240131174347.510961-1-jens.wiklander@linaro.org |
---|---|
Headers | show |
Series | Replay Protected Memory Block (RPMB) subsystem | expand |
Hi, On 1/31/24 09:43, Jens Wiklander wrote: > A number of storage technologies support a specialised hardware > partition designed to be resistant to replay attacks. The underlying > HW protocols differ but the operations are common. The RPMB partition > cannot be accessed via standard block layer, but by a set of specific > RPMB commands: WRITE, READ, GET_WRITE_COUNTER, and PROGRAM_KEY. Such a > partition provides authenticated and replay protected access, hence > suitable as a secure storage. > > The initial aim of this patch is to provide a simple RPMB Driver which > can be accessed by the optee driver to facilitate early RPMB access to > OP-TEE OS (secure OS) during the boot time. > > A TEE device driver can claim the RPMB interface, for example, via > class_interface_register() or rpmb_dev_find_device(). The RPMB driver > provides a callback to route RPMB frames to the RPMB device accessible > via rpmb_route_frames(). > > The detailed operation of implementing the access is left to the TEE > device driver itself. > > Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> > Signed-off-by: Alex Bennée <alex.bennee@linaro.org> > Signed-off-by: Shyam Saini <shyamsaini@linux.microsoft.com> > Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org> > --- > MAINTAINERS | 7 ++ > drivers/misc/Kconfig | 9 ++ > drivers/misc/Makefile | 1 + > drivers/misc/rpmb-core.c | 247 +++++++++++++++++++++++++++++++++++++++ > include/linux/rpmb.h | 184 +++++++++++++++++++++++++++++ > 5 files changed, 448 insertions(+) > create mode 100644 drivers/misc/rpmb-core.c > create mode 100644 include/linux/rpmb.h > > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig > index 4fb291f0bf7c..891aa5763666 100644 > --- a/drivers/misc/Kconfig > +++ b/drivers/misc/Kconfig > @@ -104,6 +104,15 @@ config PHANTOM > If you choose to build module, its name will be phantom. If unsure, > say N here. > > +config RPMB > + tristate "RPMB partition interface" > + help > + Unified RPMB unit interface for RPMB capable devices such as eMMC and > + UFS. Provides interface for in kernel security controllers to access in-kernel > + RPMB unit. > + > + If unsure, select N. > + > config TIFM_CORE > tristate "TI Flash Media interface support" > depends on PCI > diff --git a/drivers/misc/rpmb-core.c b/drivers/misc/rpmb-core.c > new file mode 100644 > index 000000000000..a3c289051687 > --- /dev/null > +++ b/drivers/misc/rpmb-core.c > @@ -0,0 +1,247 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright(c) 2015 - 2019 Intel Corporation. All rights reserved. > + * Copyright(c) 2021 - 2024 Linaro Ltd. > + */ > +#include <linux/device.h> > +#include <linux/init.h> > +#include <linux/kernel.h> > +#include <linux/list.h> > +#include <linux/module.h> > +#include <linux/mutex.h> > +#include <linux/rpmb.h> > +#include <linux/slab.h> > + > +/** > + * rpmb_route_frames() - route rpmb frames to rpmb device > + * @rdev: rpmb device > + * @req: rpmb request frames > + * @req_len: length of rpmb request frames in bytes > + * @rsp: rpmb response frames > + * @rsp_len: length of rpmb response frames in bytes > + * > + * @return < 0 on failure Above needs a colon ':' after @return, although using * Return: is preferable IMO. > + */ > +int rpmb_route_frames(struct rpmb_dev *rdev, u8 *req, > + unsigned int req_len, u8 *rsp, unsigned int rsp_len) > +{ > +/** > + * rpmb_dev_find_device() - return first matching rpmb device > + * @data: data for the match function > + * @match: the matching function > + * > + * @returns a matching rpmb device or NULL on failure * @returns: or * Returns: > + */ > +struct rpmb_dev *rpmb_dev_find_device(const void *data, > + const struct rpmb_dev *start, > + int (*match)(struct device *dev, > + const void *data)) > +{ > + struct device *dev; > + const struct device *start_dev = NULL; > + > + if (start) > + start_dev = &start->dev; > + dev = class_find_device(&rpmb_class, start_dev, data, match); > + > + return dev ? to_rpmb_dev(dev) : NULL; > +} > + > +/** > + * rpmb_dev_unregister() - unregister RPMB partition from the RPMB subsystem > + * @rdev: the rpmb device to unregister > + * > + * @returns < 0 on failure Ditto. > + */ > +int rpmb_dev_unregister(struct rpmb_dev *rdev) > +{ > + if (!rdev) > + return -EINVAL; > + > + device_del(&rdev->dev); > + > + rpmb_dev_put(rdev); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(rpmb_dev_unregister); > + > +/** > + * rpmb_dev_register - register RPMB partition with the RPMB subsystem > + * @dev: storage device of the rpmb device > + * @target: RPMB target/region within the physical device There is no @target function parameter. > + * @ops: device specific operations > + * > + * While registering the RPMB partition get references to needed resources > + * with the @ops->get_resources() callback and extracts needed devices > + * information while needed resources are available. > + * > + * @returns a pointer to a 'struct rpmb_dev' or an ERR_PTR on failure Ditto for Return syntax. > + */ > +struct rpmb_dev *rpmb_dev_register(struct device *dev, > + const struct rpmb_ops *ops) > +{ > + struct rpmb_dev *rdev; > + int id; > + int ret; > + > + if (!dev || !ops || !ops->get_resources || > + !ops->put_resources || !ops->route_frames || > + !ops->set_dev_info) > + return ERR_PTR(-EINVAL); > + > + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); > + if (!rdev) > + return ERR_PTR(-ENOMEM); > + > + mutex_lock(&rpmb_mutex); > + id = ida_simple_get(&rpmb_ida, 0, 0, GFP_KERNEL); > + mutex_unlock(&rpmb_mutex); > + if (id < 0) { > + ret = id; > + goto exit; > + } > + > + rdev->ops = ops; > + rdev->id = id; > + > + dev_set_name(&rdev->dev, "rpmb%d", id); > + rdev->dev.class = &rpmb_class; > + rdev->dev.parent = dev; > + > + ret = ops->set_dev_info(dev, rdev); > + if (ret) > + goto exit; > + > + ret = device_register(&rdev->dev); > + if (ret) > + goto exit; > + > + ops->get_resources(rdev->dev.parent); > + > + dev_dbg(&rdev->dev, "registered device\n"); > + > + return rdev; > + > +exit: > + if (id >= 0) { > + mutex_lock(&rpmb_mutex); > + ida_simple_remove(&rpmb_ida, id); > + mutex_unlock(&rpmb_mutex); > + } > + kfree(rdev); > + return ERR_PTR(ret); > +} > +EXPORT_SYMBOL_GPL(rpmb_dev_register); > diff --git a/include/linux/rpmb.h b/include/linux/rpmb.h > new file mode 100644 > index 000000000000..45073513264a > --- /dev/null > +++ b/include/linux/rpmb.h > @@ -0,0 +1,184 @@ > +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ > +/* > + * Copyright (C) 2015-2019 Intel Corp. All rights reserved > + * Copyright (C) 2021-2022 Linaro Ltd > + */ > +#ifndef __RPMB_H__ > +#define __RPMB_H__ > + > +#include <linux/types.h> > +#include <linux/device.h> > + > +/** > + * struct rpmb_frame - rpmb frame as defined by specs > + * > + * @stuff : stuff bytes > + * @key_mac : The authentication key or the message authentication > + * code (MAC) depending on the request/response type. > + * The MAC will be delivered in the last (or the only) > + * block of data. > + * @data : Data to be written or read by signed access. > + * @nonce : Random number generated by the host for the requests > + * and copied to the response by the RPMB engine. > + * @write_counter: Counter value for the total amount of the successful > + * authenticated data write requests made by the host. > + * @addr : Address of the data to be programmed to or read > + * from the RPMB. Address is the serial number of > + * the accessed block (half sector 256B). > + * @block_count : Number of blocks (half sectors, 256B) requested to be > + * read/programmed. > + * @result : Includes information about the status of the write counter > + * (valid, expired) and result of the access made to the RPMB. > + * @req_resp : Defines the type of request and response to/from the memory. > + */ > +struct rpmb_frame { > + u8 stuff[196]; > + u8 key_mac[32]; > + u8 data[256]; > + u8 nonce[16]; > + __be32 write_counter; > + __be16 addr; > + __be16 block_count; > + __be16 result; > + __be16 req_resp; > +} __packed; > + > +#define RPMB_PROGRAM_KEY 0x1 /* Program RPMB Authentication Key */ > +#define RPMB_GET_WRITE_COUNTER 0x2 /* Read RPMB write counter */ > +#define RPMB_WRITE_DATA 0x3 /* Write data to RPMB partition */ > +#define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */ > +#define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */ > + > +#define RPMB_REQ2RESP(_OP) ((_OP) << 8) > +#define RPMB_RESP2REQ(_OP) ((_OP) >> 8) > + > +/** > + * enum rpmb_op_result - rpmb operation results > + * > + * @RPMB_ERR_OK : operation successful > + * @RPMB_ERR_GENERAL : general failure > + * @RPMB_ERR_AUTH : mac doesn't match or ac calculation failure > + * @RPMB_ERR_COUNTER : counter doesn't match or counter increment failure > + * @RPMB_ERR_ADDRESS : address out of range or wrong address alignment > + * @RPMB_ERR_WRITE : data, counter, or result write failure > + * @RPMB_ERR_READ : data, counter, or result read failure > + * @RPMB_ERR_NO_KEY : authentication key not yet programmed > + * > + * @RPMB_ERR_COUNTER_EXPIRED: counter expired > + */ > +enum rpmb_op_result { > + RPMB_ERR_OK = 0x0000, > + RPMB_ERR_GENERAL = 0x0001, > + RPMB_ERR_AUTH = 0x0002, > + RPMB_ERR_COUNTER = 0x0003, > + RPMB_ERR_ADDRESS = 0x0004, > + RPMB_ERR_WRITE = 0x0005, > + RPMB_ERR_READ = 0x0006, > + RPMB_ERR_NO_KEY = 0x0007, > + > + RPMB_ERR_COUNTER_EXPIRED = 0x0080 > +}; > + > +/** > + * enum rpmb_type - type of underlaying storage technology underlying > + * > + * @RPMB_TYPE_EMMC : emmc (JESD84-B50.1) > + * @RPMB_TYPE_UFS : UFS (JESD220) > + * @RPMB_TYPE_NVME : NVM Express > + */ > +enum rpmb_type { > + RPMB_TYPE_EMMC, > + RPMB_TYPE_UFS, > + RPMB_TYPE_NVME, > +}; > + > +/** > + * struct rpmb_dev - device which can support RPMB partition > + * > + * @dev : device > + * @id : device id; > + * @ops : operation exported by rpmb > + * @dev_id : unique device identifier read from the hardware > + * @dev_id_len : length of unique device identifier > + * @reliable_wr_count: number of sectors that can be written in one access > + * @capacity : capacity of the device in units of 128K > + */ > +struct rpmb_dev { > + struct device dev; > + int id; > + const struct rpmb_ops *ops; > + u8 *dev_id; > + size_t dev_id_len; > + u16 reliable_wr_count; > + u16 capacity; > +}; > + > +#define to_rpmb_dev(x) container_of((x), struct rpmb_dev, dev) > + > +/** > + * struct rpmb_ops - RPMB ops to be implemented by underlying block device > + * > + * @type : block device type > + * @get_resources : gets references to needed resources in rpmb_dev_register() > + * @put_resources : puts references from resources in rpmb_dev_release() > + * @route_frames : routes frames to and from the RPMB device > + * @get_dev_info : extracts device info from the RPMB device set_dev_info ??? > + */ > +struct rpmb_ops { > + enum rpmb_type type; > + void (*get_resources)(struct device *dev); > + void (*put_resources)(struct device *dev); > + int (*set_dev_info)(struct device *dev, struct rpmb_dev *rdev); > + int (*route_frames)(struct device *dev, bool write, > + u8 *req, unsigned int req_len, > + u8 *resp, unsigned int resp_len); > +}; > + thanks.
On Wed, Jan 31, 2024 at 10:13 PM Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote: > > On Wed, Jan 31, 2024 at 06:43:45PM +0100, Jens Wiklander wrote: > > +struct class rpmb_class = { > > This structure should be marked as 'const', right? You're right, of course. > > > + .name = "rpmb", > > + .dev_release = rpmb_dev_release, > > +}; > > +EXPORT_SYMBOL(rpmb_class); > > EXPORT_SYMBOL_GPL() to match all the other exports in this file please. Sure, I'll fix it. Thanks, Jens > > thanks, > > greg k-h
On Thu, Feb 1, 2024 at 7:04 AM Randy Dunlap <rdunlap@infradead.org> wrote: > > Hi, > > On 1/31/24 09:43, Jens Wiklander wrote: > > A number of storage technologies support a specialised hardware > > partition designed to be resistant to replay attacks. The underlying > > HW protocols differ but the operations are common. The RPMB partition > > cannot be accessed via standard block layer, but by a set of specific > > RPMB commands: WRITE, READ, GET_WRITE_COUNTER, and PROGRAM_KEY. Such a > > partition provides authenticated and replay protected access, hence > > suitable as a secure storage. > > > > The initial aim of this patch is to provide a simple RPMB Driver which > > can be accessed by the optee driver to facilitate early RPMB access to > > OP-TEE OS (secure OS) during the boot time. > > > > A TEE device driver can claim the RPMB interface, for example, via > > class_interface_register() or rpmb_dev_find_device(). The RPMB driver > > provides a callback to route RPMB frames to the RPMB device accessible > > via rpmb_route_frames(). > > > > The detailed operation of implementing the access is left to the TEE > > device driver itself. > > > > Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> > > Signed-off-by: Alex Bennée <alex.bennee@linaro.org> > > Signed-off-by: Shyam Saini <shyamsaini@linux.microsoft.com> > > Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org> > > --- > > MAINTAINERS | 7 ++ > > drivers/misc/Kconfig | 9 ++ > > drivers/misc/Makefile | 1 + > > drivers/misc/rpmb-core.c | 247 +++++++++++++++++++++++++++++++++++++++ > > include/linux/rpmb.h | 184 +++++++++++++++++++++++++++++ > > 5 files changed, 448 insertions(+) > > create mode 100644 drivers/misc/rpmb-core.c > > create mode 100644 include/linux/rpmb.h > > > > > > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig > > index 4fb291f0bf7c..891aa5763666 100644 > > --- a/drivers/misc/Kconfig > > +++ b/drivers/misc/Kconfig > > @@ -104,6 +104,15 @@ config PHANTOM > > If you choose to build module, its name will be phantom. If unsure, > > say N here. > > > > +config RPMB > > + tristate "RPMB partition interface" > > + help > > + Unified RPMB unit interface for RPMB capable devices such as eMMC and > > + UFS. Provides interface for in kernel security controllers to access > > in-kernel > > > + RPMB unit. > > + > > + If unsure, select N. > > + > > config TIFM_CORE > > tristate "TI Flash Media interface support" > > depends on PCI > > > > diff --git a/drivers/misc/rpmb-core.c b/drivers/misc/rpmb-core.c > > new file mode 100644 > > index 000000000000..a3c289051687 > > --- /dev/null > > +++ b/drivers/misc/rpmb-core.c > > @@ -0,0 +1,247 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright(c) 2015 - 2019 Intel Corporation. All rights reserved. > > + * Copyright(c) 2021 - 2024 Linaro Ltd. > > + */ > > +#include <linux/device.h> > > +#include <linux/init.h> > > +#include <linux/kernel.h> > > +#include <linux/list.h> > > +#include <linux/module.h> > > +#include <linux/mutex.h> > > +#include <linux/rpmb.h> > > +#include <linux/slab.h> > > > + > > +/** > > + * rpmb_route_frames() - route rpmb frames to rpmb device > > + * @rdev: rpmb device > > + * @req: rpmb request frames > > + * @req_len: length of rpmb request frames in bytes > > + * @rsp: rpmb response frames > > + * @rsp_len: length of rpmb response frames in bytes > > + * > > + * @return < 0 on failure > > Above needs a colon ':' after @return, although using > * Return: > is preferable IMO. Thanks, I'll change to "* Return:" instead, everywhere in this patch. > > > + */ > > +int rpmb_route_frames(struct rpmb_dev *rdev, u8 *req, > > + unsigned int req_len, u8 *rsp, unsigned int rsp_len) > > +{ > > > > +/** > > + * rpmb_dev_find_device() - return first matching rpmb device > > + * @data: data for the match function > > + * @match: the matching function > > + * > > + * @returns a matching rpmb device or NULL on failure > > * @returns: > or > * Returns: > > > + */ > > +struct rpmb_dev *rpmb_dev_find_device(const void *data, > > + const struct rpmb_dev *start, > > + int (*match)(struct device *dev, > > + const void *data)) > > +{ > > + struct device *dev; > > + const struct device *start_dev = NULL; > > + > > + if (start) > > + start_dev = &start->dev; > > + dev = class_find_device(&rpmb_class, start_dev, data, match); > > + > > + return dev ? to_rpmb_dev(dev) : NULL; > > +} > > + > > +/** > > + * rpmb_dev_unregister() - unregister RPMB partition from the RPMB subsystem > > + * @rdev: the rpmb device to unregister > > + * > > + * @returns < 0 on failure > > Ditto. > > > + */ > > +int rpmb_dev_unregister(struct rpmb_dev *rdev) > > +{ > > + if (!rdev) > > + return -EINVAL; > > + > > + device_del(&rdev->dev); > > + > > + rpmb_dev_put(rdev); > > + > > + return 0; > > +} > > +EXPORT_SYMBOL_GPL(rpmb_dev_unregister); > > + > > +/** > > + * rpmb_dev_register - register RPMB partition with the RPMB subsystem > > + * @dev: storage device of the rpmb device > > + * @target: RPMB target/region within the physical device > > There is no @target function parameter. You're right, I'll remove it. > > > + * @ops: device specific operations > > + * > > + * While registering the RPMB partition get references to needed resources > > + * with the @ops->get_resources() callback and extracts needed devices > > + * information while needed resources are available. > > + * > > + * @returns a pointer to a 'struct rpmb_dev' or an ERR_PTR on failure > > Ditto for Return syntax. > > > + */ > > +struct rpmb_dev *rpmb_dev_register(struct device *dev, > > + const struct rpmb_ops *ops) > > +{ > > + struct rpmb_dev *rdev; > > + int id; > > + int ret; > > + > > + if (!dev || !ops || !ops->get_resources || > > + !ops->put_resources || !ops->route_frames || > > + !ops->set_dev_info) > > + return ERR_PTR(-EINVAL); > > + > > + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); > > + if (!rdev) > > + return ERR_PTR(-ENOMEM); > > + > > + mutex_lock(&rpmb_mutex); > > + id = ida_simple_get(&rpmb_ida, 0, 0, GFP_KERNEL); > > + mutex_unlock(&rpmb_mutex); > > + if (id < 0) { > > + ret = id; > > + goto exit; > > + } > > + > > + rdev->ops = ops; > > + rdev->id = id; > > + > > + dev_set_name(&rdev->dev, "rpmb%d", id); > > + rdev->dev.class = &rpmb_class; > > + rdev->dev.parent = dev; > > + > > + ret = ops->set_dev_info(dev, rdev); > > + if (ret) > > + goto exit; > > + > > + ret = device_register(&rdev->dev); > > + if (ret) > > + goto exit; > > + > > + ops->get_resources(rdev->dev.parent); > > + > > + dev_dbg(&rdev->dev, "registered device\n"); > > + > > + return rdev; > > + > > +exit: > > + if (id >= 0) { > > + mutex_lock(&rpmb_mutex); > > + ida_simple_remove(&rpmb_ida, id); > > + mutex_unlock(&rpmb_mutex); > > + } > > + kfree(rdev); > > + return ERR_PTR(ret); > > +} > > +EXPORT_SYMBOL_GPL(rpmb_dev_register); > > > > diff --git a/include/linux/rpmb.h b/include/linux/rpmb.h > > new file mode 100644 > > index 000000000000..45073513264a > > --- /dev/null > > +++ b/include/linux/rpmb.h > > @@ -0,0 +1,184 @@ > > +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ > > +/* > > + * Copyright (C) 2015-2019 Intel Corp. All rights reserved > > + * Copyright (C) 2021-2022 Linaro Ltd > > + */ > > +#ifndef __RPMB_H__ > > +#define __RPMB_H__ > > + > > +#include <linux/types.h> > > +#include <linux/device.h> > > + > > +/** > > + * struct rpmb_frame - rpmb frame as defined by specs > > + * > > + * @stuff : stuff bytes > > + * @key_mac : The authentication key or the message authentication > > + * code (MAC) depending on the request/response type. > > + * The MAC will be delivered in the last (or the only) > > + * block of data. > > + * @data : Data to be written or read by signed access. > > + * @nonce : Random number generated by the host for the requests > > + * and copied to the response by the RPMB engine. > > + * @write_counter: Counter value for the total amount of the successful > > + * authenticated data write requests made by the host. > > + * @addr : Address of the data to be programmed to or read > > + * from the RPMB. Address is the serial number of > > + * the accessed block (half sector 256B). > > + * @block_count : Number of blocks (half sectors, 256B) requested to be > > + * read/programmed. > > + * @result : Includes information about the status of the write counter > > + * (valid, expired) and result of the access made to the RPMB. > > + * @req_resp : Defines the type of request and response to/from the memory. > > + */ > > +struct rpmb_frame { > > + u8 stuff[196]; > > + u8 key_mac[32]; > > + u8 data[256]; > > + u8 nonce[16]; > > + __be32 write_counter; > > + __be16 addr; > > + __be16 block_count; > > + __be16 result; > > + __be16 req_resp; > > +} __packed; > > + > > +#define RPMB_PROGRAM_KEY 0x1 /* Program RPMB Authentication Key */ > > +#define RPMB_GET_WRITE_COUNTER 0x2 /* Read RPMB write counter */ > > +#define RPMB_WRITE_DATA 0x3 /* Write data to RPMB partition */ > > +#define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */ > > +#define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */ > > + > > +#define RPMB_REQ2RESP(_OP) ((_OP) << 8) > > +#define RPMB_RESP2REQ(_OP) ((_OP) >> 8) > > + > > +/** > > + * enum rpmb_op_result - rpmb operation results > > + * > > + * @RPMB_ERR_OK : operation successful > > + * @RPMB_ERR_GENERAL : general failure > > + * @RPMB_ERR_AUTH : mac doesn't match or ac calculation failure > > + * @RPMB_ERR_COUNTER : counter doesn't match or counter increment failure > > + * @RPMB_ERR_ADDRESS : address out of range or wrong address alignment > > + * @RPMB_ERR_WRITE : data, counter, or result write failure > > + * @RPMB_ERR_READ : data, counter, or result read failure > > + * @RPMB_ERR_NO_KEY : authentication key not yet programmed > > + * > > + * @RPMB_ERR_COUNTER_EXPIRED: counter expired > > + */ > > +enum rpmb_op_result { > > + RPMB_ERR_OK = 0x0000, > > + RPMB_ERR_GENERAL = 0x0001, > > + RPMB_ERR_AUTH = 0x0002, > > + RPMB_ERR_COUNTER = 0x0003, > > + RPMB_ERR_ADDRESS = 0x0004, > > + RPMB_ERR_WRITE = 0x0005, > > + RPMB_ERR_READ = 0x0006, > > + RPMB_ERR_NO_KEY = 0x0007, > > + > > + RPMB_ERR_COUNTER_EXPIRED = 0x0080 > > +}; > > + > > +/** > > + * enum rpmb_type - type of underlaying storage technology > > underlying Thanks > > > + * > > + * @RPMB_TYPE_EMMC : emmc (JESD84-B50.1) > > + * @RPMB_TYPE_UFS : UFS (JESD220) > > + * @RPMB_TYPE_NVME : NVM Express > > + */ > > +enum rpmb_type { > > + RPMB_TYPE_EMMC, > > + RPMB_TYPE_UFS, > > + RPMB_TYPE_NVME, > > +}; > > + > > +/** > > + * struct rpmb_dev - device which can support RPMB partition > > + * > > + * @dev : device > > + * @id : device id; > > + * @ops : operation exported by rpmb > > + * @dev_id : unique device identifier read from the hardware > > + * @dev_id_len : length of unique device identifier > > + * @reliable_wr_count: number of sectors that can be written in one access > > + * @capacity : capacity of the device in units of 128K > > + */ > > +struct rpmb_dev { > > + struct device dev; > > + int id; > > + const struct rpmb_ops *ops; > > + u8 *dev_id; > > + size_t dev_id_len; > > + u16 reliable_wr_count; > > + u16 capacity; > > +}; > > + > > +#define to_rpmb_dev(x) container_of((x), struct rpmb_dev, dev) > > + > > +/** > > + * struct rpmb_ops - RPMB ops to be implemented by underlying block device > > + * > > + * @type : block device type > > + * @get_resources : gets references to needed resources in rpmb_dev_register() > > + * @put_resources : puts references from resources in rpmb_dev_release() > > + * @route_frames : routes frames to and from the RPMB device > > + * @get_dev_info : extracts device info from the RPMB device > > set_dev_info ??? Yes. Thanks, Jens > > > + */ > > +struct rpmb_ops { > > + enum rpmb_type type; > > + void (*get_resources)(struct device *dev); > > + void (*put_resources)(struct device *dev); > > + int (*set_dev_info)(struct device *dev, struct rpmb_dev *rdev); > > + int (*route_frames)(struct device *dev, bool write, > > + u8 *req, unsigned int req_len, > > + u8 *resp, unsigned int resp_len); > > +}; > > + > > thanks. > -- > #Randy
Hi Jens, On Wed, 31 Jan 2024 at 23:14, Jens Wiklander <jens.wiklander@linaro.org> wrote: > > Hi, > > It's been a while since Shyam posted the last version [1] of this patch > set. I've pinged Shyam, but so far I've had no reply so I'm trying to make > another attempt with the RPMB subsystem. If Shyam has other changes in mind > than what I'm adding here I hope we'll find a way to cover that too. I'm > calling it version two of the patchset since I'm trying to address all > feedback on the previous version even if I'm starting a new thread. > > This patch set introduces a new RPMB subsystem, based on patches from [1], > [2], and [3]. The RPMB subsystem aims at providing access to RPMB > partitions to other kernel drivers, in particular the OP-TEE driver. A new > user space ABI isn't needed, we can instead continue using the already > present ABI when writing the RPMB key during production. > > I've added and removed things to keep only what is needed by the OP-TEE > driver. Since the posting of [3], there has been major changes in the MMC > subsystem so "mmc: block: register RPMB partition with the RPMB subsystem" > is in practice completely rewritten. > > With this OP-TEE can access RPMB during early boot instead of having to > wait for user space to become available as in the current design [4]. > This will benefit the efi variables [5] since we wont rely on userspace as > well as some TPM issues [6] that were solved. > > The OP-TEE driver finds the correct RPMB device to interact with by > iterating over available devices until one is found with a programmed > authentication matching the one OP-TEE is using. This enables coexisting > users of other RPMBs since the owner can be determined by who knows the > authentication key. > > I've put myself as a maintainer for the RPMB subsystem as I have an > interest in the OP-TEE driver to keep this in good shape. However, if you'd > rather see someone else taking the maintainership that's fine too. I'll > help keep the subsystem updated regardless. > > [1] https://lore.kernel.org/lkml/20230722014037.42647-1-shyamsaini@linux.microsoft.com/ > [2] https://lore.kernel.org/lkml/20220405093759.1126835-2-alex.bennee@linaro.org/ > [3] https://lore.kernel.org/linux-mmc/1478548394-8184-2-git-send-email-tomas.winkler@intel.com/ > [4] https://optee.readthedocs.io/en/latest/architecture/secure_storage.html#rpmb-secure-storage > [5] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c44b6be62e8dd4ee0a308c36a70620613e6fc55f > [6] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7269cba53d906cf257c139d3b3a53ad272176bca > > Thanks, > Jens > > Changes since Shyam's RFC: > * Removed the remaining leftover rpmb_cdev_*() function calls > * Refactored the struct rpmb_ops with all the previous ops replaced, in > some sense closer to [3] with the route_frames() op > * Added rpmb_route_frames() > * Added struct rpmb_frame, enum rpmb_op_result, and enum rpmb_type from [3] > * Removed all functions not needed in the OP-TEE use case > * Added "mmc: block: register RPMB partition with the RPMB subsystem", based > on the commit with the same name in [3] > * Added "optee: probe RPMB device using RPMB subsystem" for integration > with OP-TEE > * Moved the RPMB driver into drivers/misc/rpmb-core.c > * Added my name to MODULE_AUTHOR() in rpmb-core.c > * Added an rpmb_mutex to serialize access to the IDA > * Removed the target parameter from all rpmb_*() functions since it's > currently unused > Thanks for working on this. This is a huge step towards supporting TEE kernel client drivers. IIRC you mentioned offline to test it with virtio RPMB on Qemu. If it works then I would be happy to try it out as well. Along with that can you point me to the corresponding OP-TEE OS changes? I suppose as you are just adding 3 new RPC calls in patch#3, so we should be fine ABI wise although people have to uprev both OP-TEE and Linux kernel to get this feature enabled. However, OP-TEE should gate those RPCs behind a config flag or can just fallback to user-space supplicant if those aren't supported? -Sumit > > > Jens Wiklander (3): > rpmb: add Replay Protected Memory Block (RPMB) subsystem > mmc: block: register RPMB partition with the RPMB subsystem > optee: probe RPMB device using RPMB subsystem > > MAINTAINERS | 7 + > drivers/misc/Kconfig | 9 ++ > drivers/misc/Makefile | 1 + > drivers/misc/rpmb-core.c | 247 ++++++++++++++++++++++++++++++ > drivers/mmc/core/block.c | 177 +++++++++++++++++++++ > drivers/tee/optee/core.c | 1 + > drivers/tee/optee/ffa_abi.c | 2 + > drivers/tee/optee/optee_private.h | 6 + > drivers/tee/optee/optee_rpc_cmd.h | 33 ++++ > drivers/tee/optee/rpc.c | 221 ++++++++++++++++++++++++++ > drivers/tee/optee/smc_abi.c | 2 + > include/linux/rpmb.h | 184 ++++++++++++++++++++++ > 12 files changed, 890 insertions(+) > create mode 100644 drivers/misc/rpmb-core.c > create mode 100644 include/linux/rpmb.h > > > base-commit: 41bccc98fb7931d63d03f326a746ac4d429c1dd3 > -- > 2.34.1 >
Hi Sumit, On Fri, Feb 2, 2024 at 10:59 AM Sumit Garg <sumit.garg@linaro.org> wrote: > > Hi Jens, > > On Wed, 31 Jan 2024 at 23:14, Jens Wiklander <jens.wiklander@linaro.org> wrote: > > > > Hi, > > > > It's been a while since Shyam posted the last version [1] of this patch > > set. I've pinged Shyam, but so far I've had no reply so I'm trying to make > > another attempt with the RPMB subsystem. If Shyam has other changes in mind > > than what I'm adding here I hope we'll find a way to cover that too. I'm > > calling it version two of the patchset since I'm trying to address all > > feedback on the previous version even if I'm starting a new thread. > > > > This patch set introduces a new RPMB subsystem, based on patches from [1], > > [2], and [3]. The RPMB subsystem aims at providing access to RPMB > > partitions to other kernel drivers, in particular the OP-TEE driver. A new > > user space ABI isn't needed, we can instead continue using the already > > present ABI when writing the RPMB key during production. > > > > I've added and removed things to keep only what is needed by the OP-TEE > > driver. Since the posting of [3], there has been major changes in the MMC > > subsystem so "mmc: block: register RPMB partition with the RPMB subsystem" > > is in practice completely rewritten. > > > > With this OP-TEE can access RPMB during early boot instead of having to > > wait for user space to become available as in the current design [4]. > > This will benefit the efi variables [5] since we wont rely on userspace as > > well as some TPM issues [6] that were solved. > > > > The OP-TEE driver finds the correct RPMB device to interact with by > > iterating over available devices until one is found with a programmed > > authentication matching the one OP-TEE is using. This enables coexisting > > users of other RPMBs since the owner can be determined by who knows the > > authentication key. > > > > I've put myself as a maintainer for the RPMB subsystem as I have an > > interest in the OP-TEE driver to keep this in good shape. However, if you'd > > rather see someone else taking the maintainership that's fine too. I'll > > help keep the subsystem updated regardless. > > > > [1] https://lore.kernel.org/lkml/20230722014037.42647-1-shyamsaini@linux.microsoft.com/ > > [2] https://lore.kernel.org/lkml/20220405093759.1126835-2-alex.bennee@linaro.org/ > > [3] https://lore.kernel.org/linux-mmc/1478548394-8184-2-git-send-email-tomas.winkler@intel.com/ > > [4] https://optee.readthedocs.io/en/latest/architecture/secure_storage.html#rpmb-secure-storage > > [5] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c44b6be62e8dd4ee0a308c36a70620613e6fc55f > > [6] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7269cba53d906cf257c139d3b3a53ad272176bca > > > > Thanks, > > Jens > > > > Changes since Shyam's RFC: > > * Removed the remaining leftover rpmb_cdev_*() function calls > > * Refactored the struct rpmb_ops with all the previous ops replaced, in > > some sense closer to [3] with the route_frames() op > > * Added rpmb_route_frames() > > * Added struct rpmb_frame, enum rpmb_op_result, and enum rpmb_type from [3] > > * Removed all functions not needed in the OP-TEE use case > > * Added "mmc: block: register RPMB partition with the RPMB subsystem", based > > on the commit with the same name in [3] > > * Added "optee: probe RPMB device using RPMB subsystem" for integration > > with OP-TEE > > * Moved the RPMB driver into drivers/misc/rpmb-core.c > > * Added my name to MODULE_AUTHOR() in rpmb-core.c > > * Added an rpmb_mutex to serialize access to the IDA > > * Removed the target parameter from all rpmb_*() functions since it's > > currently unused > > > > Thanks for working on this. This is a huge step towards supporting TEE > kernel client drivers. IIRC you mentioned offline to test it with > virtio RPMB on Qemu. If it works then I would be happy to try it out > as well. I'm sorry, I didn't get far enough with that. I've been testing on a HiKey 620 with a removable HardKernel eMMC. So I have two RPMBs to test with. > > Along with that can you point me to the corresponding OP-TEE OS > changes? I suppose as you are just adding 3 new RPC calls in patch#3, > so we should be fine ABI wise although people have to uprev both > OP-TEE and Linux kernel to get this feature enabled. However, OP-TEE > should gate those RPCs behind a config flag or can just fallback to > user-space supplicant if those aren't supported? Here are the OP-TEE OS patches https://github.com/jenswi-linaro/optee_os/tree/rpmb_probe . Yes, there's automatic fallback to the user-space supplicant if the kernel reports that the new RPCs aren't supported and the kernel will not use the in-kernel driver unless the new RPCs have been used. Cheers, Jens > > -Sumit > > > > > > > Jens Wiklander (3): > > rpmb: add Replay Protected Memory Block (RPMB) subsystem > > mmc: block: register RPMB partition with the RPMB subsystem > > optee: probe RPMB device using RPMB subsystem > > > > MAINTAINERS | 7 + > > drivers/misc/Kconfig | 9 ++ > > drivers/misc/Makefile | 1 + > > drivers/misc/rpmb-core.c | 247 ++++++++++++++++++++++++++++++ > > drivers/mmc/core/block.c | 177 +++++++++++++++++++++ > > drivers/tee/optee/core.c | 1 + > > drivers/tee/optee/ffa_abi.c | 2 + > > drivers/tee/optee/optee_private.h | 6 + > > drivers/tee/optee/optee_rpc_cmd.h | 33 ++++ > > drivers/tee/optee/rpc.c | 221 ++++++++++++++++++++++++++ > > drivers/tee/optee/smc_abi.c | 2 + > > include/linux/rpmb.h | 184 ++++++++++++++++++++++ > > 12 files changed, 890 insertions(+) > > create mode 100644 drivers/misc/rpmb-core.c > > create mode 100644 include/linux/rpmb.h > > > > > > base-commit: 41bccc98fb7931d63d03f326a746ac4d429c1dd3 > > -- > > 2.34.1 > >