]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
devlink: heap-allocate param fill buffers in devlink_nl_param_fill
authorRatheesh Kannoth <rkannoth@marvell.com>
Tue, 9 Jun 2026 04:04:47 +0000 (09:34 +0530)
committerJakub Kicinski <kuba@kernel.org>
Sat, 13 Jun 2026 23:16:58 +0000 (16:16 -0700)
devlink_nl_param_fill() kept two per-configuration-mode copies of
union devlink_param_value plus a struct devlink_param_gset_ctx on the
stack while building the Netlink reply. Allocate those with kcalloc()
and kzalloc_obj() instead, and route failures through a single cleanup
path so temporary buffers are always freed.

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
Link: https://patch.msgid.link/20260609040453.711932-4-rkannoth@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/devlink/param.c

index 1a196d3a843dbf341ad585cbea86af4e0dc15e77..bd3881349c6049af97367722080928aae5686e0d 100644 (file)
@@ -304,56 +304,79 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
                                 u32 portid, u32 seq, int flags,
                                 struct netlink_ext_ack *extack)
 {
-       union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1];
-       union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
        bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
        bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
        const struct devlink_param *param = param_item->param;
-       struct devlink_param_gset_ctx ctx;
+       union devlink_param_value *default_value;
+       union devlink_param_value *param_value;
+       struct devlink_param_gset_ctx *ctx;
        struct nlattr *param_values_list;
        struct nlattr *param_attr;
        void *hdr;
        int err;
        int i;
 
+       default_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+                               sizeof(*default_value), GFP_KERNEL);
+       if (!default_value)
+               return -ENOMEM;
+
+       param_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+                             sizeof(*param_value), GFP_KERNEL);
+       if (!param_value) {
+               kfree(default_value);
+               return -ENOMEM;
+       }
+
+       ctx = kzalloc_obj(*ctx);
+       if (!ctx) {
+               kfree(param_value);
+               kfree(default_value);
+               return -ENOMEM;
+       }
+
        /* Get value from driver part to driverinit configuration mode */
        for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
                if (!devlink_param_cmode_is_supported(param, i))
                        continue;
                if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
-                       if (param_item->driverinit_value_new_valid)
+                       if (param_item->driverinit_value_new_valid) {
                                param_value[i] = param_item->driverinit_value_new;
-                       else if (param_item->driverinit_value_valid)
+                       } else if (param_item->driverinit_value_valid) {
                                param_value[i] = param_item->driverinit_value;
-                       else
-                               return -EOPNOTSUPP;
+                       } else {
+                               err = -EOPNOTSUPP;
+                               goto get_put_fail;
+                       }
 
                        if (param_item->driverinit_value_valid) {
                                default_value[i] = param_item->driverinit_default;
                                default_value_set[i] = true;
                        }
                } else {
-                       ctx.cmode = i;
-                       err = devlink_param_get(devlink, param, &ctx, extack);
+                       ctx->cmode = i;
+                       err = devlink_param_get(devlink, param, ctx, extack);
                        if (err)
-                               return err;
-                       param_value[i] = ctx.val;
+                               goto get_put_fail;
 
-                       err = devlink_param_get_default(devlink, param, &ctx,
+                       param_value[i] = ctx->val;
+
+                       err = devlink_param_get_default(devlink, param, ctx,
                                                        extack);
                        if (!err) {
-                               default_value[i] = ctx.val;
+                               default_value[i] = ctx->val;
                                default_value_set[i] = true;
                        } else if (err != -EOPNOTSUPP) {
-                               return err;
+                               goto get_put_fail;
                        }
                }
                param_value_set[i] = true;
        }
 
+       err = -EMSGSIZE;
        hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
        if (!hdr)
-               return -EMSGSIZE;
+               goto get_put_fail;
 
        if (devlink_nl_put_handle(msg, devlink))
                goto genlmsg_cancel;
@@ -393,6 +416,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
        nla_nest_end(msg, param_values_list);
        nla_nest_end(msg, param_attr);
        genlmsg_end(msg, hdr);
+       kfree(default_value);
+       kfree(param_value);
+       kfree(ctx);
        return 0;
 
 values_list_nest_cancel:
@@ -401,7 +427,11 @@ param_nest_cancel:
        nla_nest_cancel(msg, param_attr);
 genlmsg_cancel:
        genlmsg_cancel(msg, hdr);
-       return -EMSGSIZE;
+get_put_fail:
+       kfree(default_value);
+       kfree(param_value);
+       kfree(ctx);
+       return err;
 }
 
 static void devlink_param_notify(struct devlink *devlink,