From f91e9fba51e5da46ee5c6822f8656713d74a6ecf Mon Sep 17 00:00:00 2001 From: Peter Bigot Date: Sat, 23 Jan 2021 07:56:09 -0600 Subject: [PATCH] device: fix potential truncation of DT-derived device names While using the encoded path to a device tree node guarantees a unique identifier for the corresponding device there is a limit on the number of characters of that name that can be captured when looking up a device by name from user mode, and the path can exceed that limit. Synthesize a unique name from the node dependency ordinal instead, and update the gen_defines script to record the name associated with the full path in the extern declaration. Add a build-time check that no device is created with a name that violates the user mode requirement. Also update the network device DTS helper functions to use the same inference for dev_name and label that the real one does, since they bypass the real one. Signed-off-by: Peter Bigot --- include/device.h | 25 +++++++++++++++++++------ include/net/ethernet.h | 3 ++- include/net/net_if.h | 3 ++- scripts/dts/gen_defines.py | 3 ++- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/device.h b/include/device.h index 9d0dfe6d3d8..d90f4c8b6cd 100644 --- a/include/device.h +++ b/include/device.h @@ -99,7 +99,8 @@ extern "C" { * since the API is not specified; * * @param dev_name Device name. This must be less than Z_DEVICE_MAX_NAME_LEN - * characters in order to be looked up from user mode with device_get_binding(). + * characters (including terminating NUL) in order to be looked up from user + * mode with device_get_binding(). * * @param drv_name The name this instance of the driver exposes to * the system. @@ -168,7 +169,7 @@ extern "C" { */ #define DEVICE_DT_DEFINE(node_id, init_fn, pm_control_fn, \ data_ptr, cfg_ptr, level, prio, api_ptr) \ - Z_DEVICE_DEFINE(node_id, node_id, \ + Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_NAME(node_id), \ DT_PROP_OR(node_id, label, NULL), init_fn, \ pm_control_fn, \ data_ptr, cfg_ptr, level, prio, api_ptr) @@ -202,7 +203,7 @@ extern "C" { * @return The expanded name of the device object created by * DEVICE_DT_DEFINE() */ -#define DEVICE_DT_NAME_GET(node_id) DEVICE_NAME_GET(node_id) +#define DEVICE_DT_NAME_GET(node_id) DEVICE_NAME_GET(Z_DEVICE_DT_DEV_NAME(node_id)) /** * @def DEVICE_DT_GET @@ -688,10 +689,20 @@ static inline int device_pm_put_sync(const struct device *dev) { return -ENOTSUP * @} */ +/* Node paths can exceed the maximum size supported by device_get_binding() in user mode, + * so synthesize a unique dev_name from the devicetree node. + * + * The ordinal used in this name can be mapped to the path by + * examining zephyr/include/generated/device_extern.h header. If the + * format of this conversion changes, gen_defines should be updated to + * match it. + */ +#define Z_DEVICE_DT_DEV_NAME(node_id) _CONCAT(dts_ord_, DT_DEP_ORD(node_id)) + #define Z_DEVICE_DEFINE(node_id, dev_name, drv_name, init_fn, pm_control_fn, \ data_ptr, cfg_ptr, level, prio, api_ptr) \ Z_DEVICE_DEFINE_PM(dev_name) \ - COND_CODE_1(DT_NODE_EXISTS(dev_name), (), (static)) \ + COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static)) \ const Z_DECL_ALIGN(struct device) \ DEVICE_NAME_GET(dev_name) __used \ __attribute__((__section__(".device_" #level STRINGIFY(prio)))) = { \ @@ -701,8 +712,10 @@ static inline int device_pm_put_sync(const struct device *dev) { return -ENOTSUP .data = (data_ptr), \ Z_DEVICE_DEFINE_PM_INIT(dev_name, pm_control_fn) \ }; \ - Z_INIT_ENTRY_DEFINE(_CONCAT(__device_, dev_name), init_fn, \ - (&_CONCAT(__device_, dev_name)), level, prio) + BUILD_ASSERT(sizeof(Z_STRINGIFY(drv_name)) <= Z_DEVICE_MAX_NAME_LEN, \ + Z_STRINGIFY(DEVICE_GET_NAME(drv_name)) " too long"); \ + Z_INIT_ENTRY_DEFINE(DEVICE_NAME_GET(dev_name), init_fn, \ + (&DEVICE_NAME_GET(dev_name)), level, prio) #ifdef CONFIG_PM_DEVICE #define Z_DEVICE_DEFINE_PM(dev_name) \ diff --git a/include/net/ethernet.h b/include/net/ethernet.h index a3209795e93..f17d8efffff 100644 --- a/include/net/ethernet.h +++ b/include/net/ethernet.h @@ -711,7 +711,8 @@ static inline bool net_eth_get_vlan_status(struct net_if *iface) */ #define ETH_NET_DEVICE_DT_DEFINE(node_id, init_fn, pm_control_fn, data, \ cfg, prio, api, mtu) \ - Z_ETH_NET_DEVICE_INIT(node_id, node_id, DT_LABEL(node_id), \ + Z_ETH_NET_DEVICE_INIT(node_id, Z_DEVICE_DT_DEV_NAME(node_id), \ + DT_PROP_OR(node_id, label, NULL), \ init_fn, pm_control_fn, data, cfg, prio, \ api, mtu) diff --git a/include/net/net_if.h b/include/net/net_if.h index b52b2b67a7c..9581c3ff200 100644 --- a/include/net/net_if.h +++ b/include/net/net_if.h @@ -2268,7 +2268,8 @@ struct net_if_api { */ #define NET_DEVICE_DT_DEFINE(node_id, init_fn, pm_control_fn, data, cfg, \ prio, api, l2, l2_ctx_type, mtu) \ - Z_NET_DEVICE_INIT(node_id, node_id, DT_LABEL(node_id), init_fn, \ + Z_NET_DEVICE_INIT(node_id, Z_DEVICE_DT_DEV_NAME(node_id), \ + DT_PROP_OR(node_id, label, NULL), init_fn, \ pm_control_fn, data, cfg, prio, api, l2, \ l2_ctx_type, mtu) diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index 0ce11649499..5185acb6832 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -132,7 +132,8 @@ def write_device_extern_header(device_header_out, edt): print("", file=dev_header_file) for node in sorted(edt.nodes, key=lambda node: node.dep_ordinal): - print(f"extern const struct device DEVICE_DT_NAME_GET(DT_{node.z_path_id});", file=dev_header_file) + print(f"extern const struct device DEVICE_DT_NAME_GET(DT_{node.z_path_id}); /* dts_ord_{node.dep_ordinal} */", + file=dev_header_file) print("", file=dev_header_file) print("#ifdef __cplusplus", file=dev_header_file)