The Kconfig option already warns that the current behavior of machine_id_set_hashable() overriding previous calls can lead to the machine-id changing over updates. We don't yet have this problem in practice, because the only two upstream users are for bsec and ocotp, which are efuse drivers for different SoCs. On the other hand, users may want to get the unique ID from an EEPROM and with deep probe support, the initcall ordering will be independent of the actual probe order. Work around this issue by introducing a way for each board to explicitly reference a nvmem cell that should be hashed to produce the machine-id. If no such device tree property is supplied, the last call to machine_id_set_hashable() will be used as before. Cc: Bastian Krause <bst@xxxxxxxxxxxxxx> Cc: Uwe Kleine-König <ukl@xxxxxxxxxxxxxx> Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- common/Kconfig | 13 ++++++---- common/machine_id.c | 41 ++++++++++++++++++++++++++++--- drivers/nvmem/core.c | 44 ++++++++++++++++++++++++---------- drivers/of/base.c | 11 +++++++++ include/linux/nvmem-consumer.h | 5 ++++ include/of.h | 6 +++++ 6 files changed, 99 insertions(+), 21 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index 54f1eb633a32..a4a109f04f08 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1066,13 +1066,16 @@ config MACHINE_ID bool "compute unique machine-id" depends on FLEXIBLE_BOOTARGS depends on SHA1 + select NVMEM help Compute a persistent machine-specific id and store it to $global.machine_id. - The id is a hash of device-specific information added via - machine_id_set_hashable(). If multiple sources are available, the - information provided by the last call prior to the late initcall - set_machine_id() is used to generate the machine id from. Thus when - updating barebox the machine id might change. + The id is a hash of device-specific information added either via + machine_id_set_hashable() or by hashing the nvmem cell referenced by the + /chosen/barebox,machine-id device tree property. + + With machine_id_set_hashable(), the last call prior to the late initcall + set_machine_id() willl be used to generate the machine id. This means + updating barebox may change the machine id! global.bootm.provide_machine_id may be used to automatically set the linux.bootargs.machine_id global variable with a value of diff --git a/common/machine_id.c b/common/machine_id.c index 6480806cd287..fd2f0888a6cd 100644 --- a/common/machine_id.c +++ b/common/machine_id.c @@ -10,6 +10,9 @@ #include <magicvar.h> #include <crypto/sha.h> #include <machine_id.h> +#include <linux/err.h> +#include <linux/nvmem-consumer.h> +#include <of.h> #define MACHINE_ID_LENGTH 32 @@ -24,16 +27,49 @@ void machine_id_set_hashable(const void *hashable, size_t len) __machine_id_hashable_length = len; } +static const void *machine_id_get_hashable(size_t *len) +{ + struct device_node *np = of_get_machineidpath(); + struct nvmem_cell *cell; + void *ret; + + if (!np) + goto no_cell; + + cell = of_nvmem_cell_get_from_node(np); + if (IS_ERR(cell)) { + pr_err("Invalid barebox,machine-id-path: %pe\n", cell); + goto no_cell; + } + + ret = nvmem_cell_read(cell, len); + nvmem_cell_put(cell); + if (IS_ERR(ret)) { + pr_err("Couldn't read from barebox,machine-id-path: %pe\n", ret); + goto no_cell; + } + + return ret; + +no_cell: + *len = __machine_id_hashable_length; + return __machine_id_hashable; +} + static int machine_id_set_globalvar(void) { struct digest *digest = NULL; unsigned char machine_id[SHA1_DIGEST_SIZE]; char hex_machine_id[MACHINE_ID_LENGTH]; char *env_machine_id; + const void *hashable; + size_t length; int ret = 0; + hashable = machine_id_get_hashable(&length); + /* nothing to do if no hashable information provided */ - if (!__machine_id_hashable) + if (!hashable) goto out; digest = digest_alloc_by_algo(HASH_ALGO_SHA1); @@ -41,8 +77,7 @@ static int machine_id_set_globalvar(void) if (ret) goto out; - ret = digest_update(digest, __machine_id_hashable, - __machine_id_hashable_length); + ret = digest_update(digest, hashable, length); if (ret) goto out; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 4e558e165063..980304a8078b 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -361,29 +361,21 @@ static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id) #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OFTREE) /** - * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id + * of_nvmem_cell_get_from_node() - Get a nvmem cell from cell device node * - * @dev node: Device tree node that uses the nvmem cell - * @id: nvmem cell name from nvmem-cell-names property. + * @cell_np: Device tree node of the nvmem cell * * Return: Will be an ERR_PTR() on error or a valid pointer * to a struct nvmem_cell. The nvmem_cell will be freed by the * nvmem_cell_put(). */ -struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, - const char *name) +struct nvmem_cell *of_nvmem_cell_get_from_node(struct device_node *cell_np) { - struct device_node *cell_np, *nvmem_np; + struct device_node *nvmem_np; struct nvmem_cell *cell; struct nvmem_device *nvmem; const __be32 *addr; - int rval, len, index; - - index = of_property_match_string(np, "nvmem-cell-names", name); - - cell_np = of_parse_phandle(np, "nvmem-cells", index); - if (!cell_np) - return ERR_PTR(-EINVAL); + int rval, len; nvmem_np = of_get_parent(cell_np); if (!nvmem_np) @@ -445,6 +437,32 @@ err_mem: return ERR_PTR(rval); } +EXPORT_SYMBOL_GPL(of_nvmem_cell_get_from_node); + +/** + * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id + * + * @dev node: Device tree node that uses the nvmem cell + * @id: nvmem cell name from nvmem-cell-names property. + * + * Return: Will be an ERR_PTR() on error or a valid pointer + * to a struct nvmem_cell. The nvmem_cell will be freed by the + * nvmem_cell_put(). + */ +struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, + const char *name) +{ + struct device_node *cell_np; + int index; + + index = of_property_match_string(np, "nvmem-cell-names", name); + + cell_np = of_parse_phandle(np, "nvmem-cells", index); + if (!cell_np) + return ERR_PTR(-EINVAL); + + return of_nvmem_cell_get_from_node(cell_np); +} EXPORT_SYMBOL_GPL(of_nvmem_cell_get); #endif diff --git a/drivers/of/base.c b/drivers/of/base.c index 4104d7589305..a5b74707fc4f 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2525,6 +2525,17 @@ int of_device_is_stdout_path(struct device_d *dev, unsigned int *baudrate) return true; } +struct device_node *of_get_machineidpath(void) +{ + const char *name; + + name = of_get_property(of_chosen, "barebox,machine-id-path", NULL); + if (!name) + return NULL; + + return of_find_node_by_path_or_alias(NULL, name); +} + /** * of_add_initrd - add initrd properties to the devicetree * @root - the root node of the tree diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index b979f23372a6..639a7ebbabae 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -122,11 +122,16 @@ static inline int nvmem_device_write(struct nvmem_device *nvmem, #endif /* CONFIG_NVMEM */ #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OFTREE) +struct nvmem_cell *of_nvmem_cell_get_from_node(struct device_node *cell_np); struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *name); struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *name); #else +static inline struct nvmem_cell *of_nvmem_cell_get_from_node(struct device_node *cell_np) +{ + return ERR_PTR(-ENOSYS); +} static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *name) { diff --git a/include/of.h b/include/of.h index d82790c0523e..677f48d0aba1 100644 --- a/include/of.h +++ b/include/of.h @@ -290,6 +290,7 @@ int of_fixup_partitions(struct device_node *np, struct cdev *cdev); int of_partitions_register_fixup(struct cdev *cdev); struct device_node *of_get_stdoutpath(unsigned int *); int of_device_is_stdout_path(struct device_d *dev, unsigned int *baudrate); +struct device_node *of_get_machineidpath(void); const char *of_get_model(void); void *of_flatten_dtb(struct device_node *node); int of_add_memory(struct device_node *node, bool dump); @@ -336,6 +337,11 @@ static inline int of_device_is_stdout_path(struct device_d *dev, unsigned int *b return 0; } +static inline struct device_node *of_get_machineidpath(void) +{ + return NULL; +} + static inline const char *of_get_model(void) { return NULL; -- 2.30.2 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox