Skip to content

Commit

Permalink
device: fix potential truncation of DT-derived device names
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
pabigot committed Jan 24, 2021
1 parent 7786103 commit ba3d6f4
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 9 deletions.
25 changes: 19 additions & 6 deletions include/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)))) = { \
Expand All @@ -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) \
Expand Down
3 changes: 2 additions & 1 deletion include/net/ethernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 2 additions & 1 deletion include/net/net_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 2 additions & 1 deletion scripts/dts/gen_defines.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit ba3d6f4

Please sign in to comment.