devlink: heap-allocate param fill buffers in devlink_nl_param_fill

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>
This commit is contained in:
Ratheesh Kannoth
2026-06-09 09:34:47 +05:30
committed by Jakub Kicinski
parent 4655902dee
commit c0e67fd123

View 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 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
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,