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

Reply via email to