devlink: validate length of param values

DEVLINK_ATTR_PARAM_VALUE_DATA may have different types
so it's not checked by the normal netlink policy. Make
sure the attribute length is what we expect.

Fixes: e3b7ca18ad ("devlink: Add param set command")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jakub Kicinski 2020-03-02 21:05:11 -08:00 committed by David S. Miller
parent ab124d580a
commit 8750939b6a
1 changed files with 19 additions and 12 deletions

View File

@ -3352,34 +3352,41 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
struct genl_info *info, struct genl_info *info,
union devlink_param_value *value) union devlink_param_value *value)
{ {
struct nlattr *param_data;
int len; int len;
if (param->type != DEVLINK_PARAM_TYPE_BOOL && param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
!info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
return -EINVAL; return -EINVAL;
switch (param->type) { switch (param->type) {
case DEVLINK_PARAM_TYPE_U8: case DEVLINK_PARAM_TYPE_U8:
value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]); if (nla_len(param_data) != sizeof(u8))
return -EINVAL;
value->vu8 = nla_get_u8(param_data);
break; break;
case DEVLINK_PARAM_TYPE_U16: case DEVLINK_PARAM_TYPE_U16:
value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]); if (nla_len(param_data) != sizeof(u16))
return -EINVAL;
value->vu16 = nla_get_u16(param_data);
break; break;
case DEVLINK_PARAM_TYPE_U32: case DEVLINK_PARAM_TYPE_U32:
value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]); if (nla_len(param_data) != sizeof(u32))
return -EINVAL;
value->vu32 = nla_get_u32(param_data);
break; break;
case DEVLINK_PARAM_TYPE_STRING: case DEVLINK_PARAM_TYPE_STRING:
len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]), len = strnlen(nla_data(param_data), nla_len(param_data));
nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])); if (len == nla_len(param_data) ||
if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
len >= __DEVLINK_PARAM_MAX_STRING_VALUE) len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
return -EINVAL; return -EINVAL;
strcpy(value->vstr, strcpy(value->vstr, nla_data(param_data));
nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
break; break;
case DEVLINK_PARAM_TYPE_BOOL: case DEVLINK_PARAM_TYPE_BOOL:
value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ? if (param_data && nla_len(param_data))
true : false; return -EINVAL;
value->vbool = nla_get_flag(param_data);
break; break;
} }
return 0; return 0;