Introduce a new lock-firmware command to the devlink API, providing a mechanism to enforce secure firmware versions at the user's request. The lock-firmware command invokes a driver-implemented callback, allowing hardware vendors to implement a mechanism for the specific hardware to block undesirable firmware downgrades possibilities. This ensures that firmware downgrades, which could expose devices to known vulnerabilities, are prevented in security-sensitive deployments.
Signed-off-by: Martyna Szapar-Mudlaw <[email protected]> --- Note: This is only RFC draft. As expected, the code that should be automatically generated will eventually not be manually entered here. Documentation will be added. --- include/net/devlink.h | 2 ++ include/uapi/linux/devlink.h | 2 ++ net/devlink/dev.c | 13 +++++++++++++ net/devlink/netlink_gen.c | 18 +++++++++++++++++- net/devlink/netlink_gen.h | 4 +++- 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/net/devlink.h b/include/net/devlink.h index d5da362ea321..1b19f7c4550b 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1354,6 +1354,8 @@ struct devlink_ops { int (*flash_update)(struct devlink *devlink, struct devlink_flash_update_params *params, struct netlink_ext_ack *extack); + int (*lock_firmware)(struct devlink *devlink, + struct netlink_ext_ack *extack); /** * @trap_init: Trap initialization function. * diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index 9401aa343673..8f37cef858e2 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -141,6 +141,8 @@ enum devlink_command { DEVLINK_CMD_NOTIFY_FILTER_SET, + DEVLINK_CMD_LOCK_FIRMWARE, + /* add new commands above here */ __DEVLINK_CMD_MAX, DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 diff --git a/net/devlink/dev.c b/net/devlink/dev.c index d6e3db300acb..7bb7617a8080 100644 --- a/net/devlink/dev.c +++ b/net/devlink/dev.c @@ -1440,3 +1440,16 @@ int devlink_nl_selftests_run_doit(struct sk_buff *skb, struct genl_info *info) nlmsg_free(msg); return err; } + +int devlink_nl_lock_firmware_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct devlink *devlink = info->user_ptr[0]; + int ret; + + if (!devlink->ops->lock_firmware) + return -EOPNOTSUPP; + + ret = devlink->ops->lock_firmware(devlink, info->extack); + + return ret; +} diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c index f9786d51f68f..2d12fb09ad48 100644 --- a/net/devlink/netlink_gen.c +++ b/net/devlink/netlink_gen.c @@ -567,8 +567,14 @@ static const struct nla_policy devlink_notify_filter_set_nl_policy[DEVLINK_ATTR_ [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, }; +/* DEVLINK_CMD_LOCK_FIRMWARE - do */ +static const struct nla_policy devlink_lock_firmware_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, +}; + /* Ops table for devlink */ -const struct genl_split_ops devlink_nl_ops[74] = { +const struct genl_split_ops devlink_nl_ops[75] = { { .cmd = DEVLINK_CMD_GET, .validate = GENL_DONT_VALIDATE_STRICT, @@ -1247,4 +1253,14 @@ const struct genl_split_ops devlink_nl_ops[74] = { .maxattr = DEVLINK_ATTR_PORT_INDEX, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = DEVLINK_CMD_LOCK_FIRMWARE, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit, + .doit = devlink_nl_lock_firmware_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_lock_firmware_nl_policy, + .maxattr = DEVLINK_ATTR_DEV_NAME, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, }; diff --git a/net/devlink/netlink_gen.h b/net/devlink/netlink_gen.h index 8f2bd50ddf5e..f0129da6a81b 100644 --- a/net/devlink/netlink_gen.h +++ b/net/devlink/netlink_gen.h @@ -16,7 +16,7 @@ extern const struct nla_policy devlink_dl_port_function_nl_policy[DEVLINK_PORT_F extern const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1]; /* Ops table for devlink */ -extern const struct genl_split_ops devlink_nl_ops[74]; +extern const struct genl_split_ops devlink_nl_ops[75]; int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info); @@ -144,5 +144,7 @@ int devlink_nl_selftests_get_dumpit(struct sk_buff *skb, int devlink_nl_selftests_run_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_notify_filter_set_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_lock_firmware_doit(struct sk_buff *skb, + struct genl_info *info); #endif /* _LINUX_DEVLINK_GEN_H */ -- 2.47.0
