mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
ethtool: netlink: always pass genl_info to .prepare_data
We had a number of bugs in the past because developers forgot to fully test dumps, which pass NULL as info to .prepare_data. .prepare_data implementations would try to access info->extack leading to a null-deref. Now that dumps and notifications can access struct genl_info we can pass it in, and remove the info null checks. Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # pause Reviewed-by: Jiri Pirko <jiri@nvidia.com> Link: https://lore.kernel.org/r/20230814214723.2924989-11-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
ec0e5b09b8
commit
f946270d05
@ -24,7 +24,7 @@ const struct nla_policy ethnl_channels_get_policy[] = {
|
||||
|
||||
static int channels_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct channels_reply_data *data = CHANNELS_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -59,10 +59,9 @@ const struct nla_policy ethnl_coalesce_get_policy[] = {
|
||||
|
||||
static int coalesce_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct coalesce_reply_data *data = COALESCE_REPDATA(reply_base);
|
||||
struct netlink_ext_ack *extack = info ? info->extack : NULL;
|
||||
struct net_device *dev = reply_base->dev;
|
||||
int ret;
|
||||
|
||||
@ -73,7 +72,8 @@ static int coalesce_prepare_data(const struct ethnl_req_info *req_base,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = dev->ethtool_ops->get_coalesce(dev, &data->coalesce,
|
||||
&data->kernel_coalesce, extack);
|
||||
&data->kernel_coalesce,
|
||||
info->extack);
|
||||
ethnl_ops_complete(dev);
|
||||
|
||||
return ret;
|
||||
|
@ -23,7 +23,7 @@ const struct nla_policy ethnl_debug_get_policy[] = {
|
||||
|
||||
static int debug_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct debug_reply_data *data = DEBUG_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -26,7 +26,7 @@ const struct nla_policy ethnl_eee_get_policy[] = {
|
||||
|
||||
static int eee_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct eee_reply_data *data = EEE_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -51,8 +51,7 @@ static int fallback_set_params(struct eeprom_req_info *request,
|
||||
}
|
||||
|
||||
static int eeprom_fallback(struct eeprom_req_info *request,
|
||||
struct eeprom_reply_data *reply,
|
||||
struct genl_info *info)
|
||||
struct eeprom_reply_data *reply)
|
||||
{
|
||||
struct net_device *dev = reply->base.dev;
|
||||
struct ethtool_modinfo modinfo = {0};
|
||||
@ -103,7 +102,7 @@ static int get_module_eeprom_by_page(struct net_device *dev,
|
||||
|
||||
static int eeprom_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct eeprom_reply_data *reply = MODULE_EEPROM_REPDATA(reply_base);
|
||||
struct eeprom_req_info *request = MODULE_EEPROM_REQINFO(req_base);
|
||||
@ -124,7 +123,7 @@ static int eeprom_prepare_data(const struct ethnl_req_info *req_base,
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
ret = get_module_eeprom_by_page(dev, &page_data, info ? info->extack : NULL);
|
||||
ret = get_module_eeprom_by_page(dev, &page_data, info->extack);
|
||||
if (ret < 0)
|
||||
goto err_ops;
|
||||
|
||||
@ -140,7 +139,7 @@ static int eeprom_prepare_data(const struct ethnl_req_info *req_base,
|
||||
kfree(page_data.data);
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
return eeprom_fallback(request, reply, info);
|
||||
return eeprom_fallback(request, reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t src)
|
||||
|
||||
static int features_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct features_reply_data *data = FEATURES_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -92,7 +92,7 @@ fec_stats_recalc(struct fec_stat_grp *grp, struct ethtool_fec_stat *stats)
|
||||
|
||||
static int fec_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(active_fec_modes) = {};
|
||||
struct fec_reply_data *data = FEC_REPDATA(reply_base);
|
||||
|
@ -23,7 +23,7 @@ const struct nla_policy ethnl_linkinfo_get_policy[] = {
|
||||
|
||||
static int linkinfo_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct linkinfo_reply_data *data = LINKINFO_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -27,7 +27,7 @@ const struct nla_policy ethnl_linkmodes_get_policy[] = {
|
||||
|
||||
static int linkmodes_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct linkmodes_reply_data *data = LINKMODES_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -81,7 +81,7 @@ static int linkstate_get_link_ext_state(struct net_device *dev,
|
||||
|
||||
static int linkstate_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct linkstate_reply_data *data = LINKSTATE_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -27,7 +27,7 @@ const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1] = {
|
||||
|
||||
static int mm_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct mm_reply_data *data = MM_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -38,10 +38,9 @@ static int module_get_power_mode(struct net_device *dev,
|
||||
|
||||
static int module_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct module_reply_data *data = MODULE_REPDATA(reply_base);
|
||||
struct netlink_ext_ack *extack = info ? info->extack : NULL;
|
||||
struct net_device *dev = reply_base->dev;
|
||||
int ret;
|
||||
|
||||
@ -49,7 +48,7 @@ static int module_prepare_data(const struct ethnl_req_info *req_base,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = module_get_power_mode(dev, data, extack);
|
||||
ret = module_get_power_mode(dev, data, info->extack);
|
||||
if (ret < 0)
|
||||
goto out_complete;
|
||||
|
||||
|
@ -444,12 +444,12 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
|
||||
const struct ethnl_dump_ctx *ctx,
|
||||
struct netlink_callback *cb)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
void *ehdr;
|
||||
int ret;
|
||||
|
||||
ehdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
||||
ehdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
|
||||
ðtool_genl_family, NLM_F_MULTI,
|
||||
ctx->ops->reply_cmd);
|
||||
if (!ehdr)
|
||||
@ -457,7 +457,7 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
|
||||
|
||||
ethnl_init_reply_data(ctx->reply_data, ctx->ops, dev);
|
||||
rtnl_lock();
|
||||
ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, NULL);
|
||||
ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, info);
|
||||
rtnl_unlock();
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@ -495,7 +495,7 @@ static int ethnl_default_dumpit(struct sk_buff *skb,
|
||||
dev_hold(dev);
|
||||
rtnl_unlock();
|
||||
|
||||
ret = ethnl_default_dump_one(skb, dev, ctx, cb);
|
||||
ret = ethnl_default_dump_one(skb, dev, ctx, genl_info_dump(cb));
|
||||
|
||||
rtnl_lock();
|
||||
dev_put(dev);
|
||||
@ -647,11 +647,14 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
|
||||
struct ethnl_reply_data *reply_data;
|
||||
const struct ethnl_request_ops *ops;
|
||||
struct ethnl_req_info *req_info;
|
||||
struct genl_info info;
|
||||
struct sk_buff *skb;
|
||||
void *reply_payload;
|
||||
int reply_len;
|
||||
int ret;
|
||||
|
||||
genl_info_init_ntf(&info, ðtool_genl_family, cmd);
|
||||
|
||||
if (WARN_ONCE(cmd > ETHTOOL_MSG_KERNEL_MAX ||
|
||||
!ethnl_default_notify_ops[cmd],
|
||||
"unexpected notification type %u\n", cmd))
|
||||
@ -670,7 +673,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
|
||||
req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||
|
||||
ethnl_init_reply_data(reply_data, ops, dev);
|
||||
ret = ops->prepare_data(req_info, reply_data, NULL);
|
||||
ret = ops->prepare_data(req_info, reply_data, &info);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
ret = ops->reply_size(req_info, reply_data);
|
||||
|
@ -355,7 +355,7 @@ struct ethnl_request_ops {
|
||||
struct netlink_ext_ack *extack);
|
||||
int (*prepare_data)(const struct ethnl_req_info *req_info,
|
||||
struct ethnl_reply_data *reply_data,
|
||||
struct genl_info *info);
|
||||
const struct genl_info *info);
|
||||
int (*reply_size)(const struct ethnl_req_info *req_info,
|
||||
const struct ethnl_reply_data *reply_data);
|
||||
int (*fill_reply)(struct sk_buff *skb,
|
||||
|
@ -51,10 +51,9 @@ static int pause_parse_request(struct ethnl_req_info *req_base,
|
||||
|
||||
static int pause_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
const struct pause_req_info *req_info = PAUSE_REQINFO(req_base);
|
||||
struct netlink_ext_ack *extack = info ? info->extack : NULL;
|
||||
struct pause_reply_data *data = PAUSE_REPDATA(reply_base);
|
||||
enum ethtool_mac_stats_src src = req_info->src;
|
||||
struct net_device *dev = reply_base->dev;
|
||||
@ -74,7 +73,7 @@ static int pause_prepare_data(const struct ethnl_req_info *req_base,
|
||||
if ((src == ETHTOOL_MAC_STATS_SRC_EMAC ||
|
||||
src == ETHTOOL_MAC_STATS_SRC_PMAC) &&
|
||||
!__ethtool_dev_mm_supported(dev)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
NL_SET_ERR_MSG_MOD(info->extack,
|
||||
"Device does not support MAC merge layer");
|
||||
ethnl_ops_complete(dev);
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -24,7 +24,7 @@ const struct nla_policy ethnl_phc_vclocks_get_policy[] = {
|
||||
|
||||
static int phc_vclocks_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct phc_vclocks_reply_data *data = PHC_VCLOCKS_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -40,7 +40,7 @@ const struct nla_policy ethnl_plca_get_cfg_policy[] = {
|
||||
|
||||
static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct plca_reply_data *data = PLCA_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
@ -183,7 +183,7 @@ const struct nla_policy ethnl_plca_get_status_policy[] = {
|
||||
|
||||
static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct plca_reply_data *data = PLCA_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -57,7 +57,7 @@ static int ethnl_get_priv_flags_info(struct net_device *dev,
|
||||
|
||||
static int privflags_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -53,8 +53,8 @@ static int pse_get_pse_attributes(struct net_device *dev,
|
||||
}
|
||||
|
||||
static int pse_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
struct ethnl_reply_data *reply_base,
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct pse_reply_data *data = PSE_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
@ -64,7 +64,7 @@ static int pse_prepare_data(const struct ethnl_req_info *req_base,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pse_get_pse_attributes(dev, info ? info->extack : NULL, data);
|
||||
ret = pse_get_pse_attributes(dev, info->extack, data);
|
||||
|
||||
ethnl_ops_complete(dev);
|
||||
|
||||
|
@ -24,10 +24,9 @@ const struct nla_policy ethnl_rings_get_policy[] = {
|
||||
|
||||
static int rings_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct rings_reply_data *data = RINGS_REPDATA(reply_base);
|
||||
struct netlink_ext_ack *extack = info ? info->extack : NULL;
|
||||
struct net_device *dev = reply_base->dev;
|
||||
int ret;
|
||||
|
||||
@ -39,7 +38,7 @@ static int rings_prepare_data(const struct ethnl_req_info *req_base,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
dev->ethtool_ops->get_ringparam(dev, &data->ringparam,
|
||||
&data->kernel_ringparam, extack);
|
||||
&data->kernel_ringparam, info->extack);
|
||||
ethnl_ops_complete(dev);
|
||||
|
||||
return 0;
|
||||
|
@ -42,7 +42,8 @@ rss_parse_request(struct ethnl_req_info *req_info, struct nlattr **tb,
|
||||
|
||||
static int
|
||||
rss_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base, struct genl_info *info)
|
||||
struct ethnl_reply_data *reply_base,
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct rss_reply_data *data = RSS_REPDATA(reply_base);
|
||||
struct rss_req_info *request = RSS_REQINFO(req_base);
|
||||
|
@ -114,10 +114,9 @@ static int stats_parse_request(struct ethnl_req_info *req_base,
|
||||
|
||||
static int stats_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
const struct stats_req_info *req_info = STATS_REQINFO(req_base);
|
||||
struct netlink_ext_ack *extack = info ? info->extack : NULL;
|
||||
struct stats_reply_data *data = STATS_REPDATA(reply_base);
|
||||
enum ethtool_mac_stats_src src = req_info->src;
|
||||
struct net_device *dev = reply_base->dev;
|
||||
@ -130,7 +129,7 @@ static int stats_prepare_data(const struct ethnl_req_info *req_base,
|
||||
if ((src == ETHTOOL_MAC_STATS_SRC_EMAC ||
|
||||
src == ETHTOOL_MAC_STATS_SRC_PMAC) &&
|
||||
!__ethtool_dev_mm_supported(dev)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
NL_SET_ERR_MSG_MOD(info->extack,
|
||||
"Device does not support MAC merge layer");
|
||||
ethnl_ops_complete(dev);
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -274,7 +274,7 @@ static int strset_prepare_set(struct strset_info *info, struct net_device *dev,
|
||||
|
||||
static int strset_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
const struct strset_req_info *req_info = STRSET_REQINFO(req_base);
|
||||
struct strset_reply_data *data = STRSET_REPDATA(reply_base);
|
||||
|
@ -25,7 +25,7 @@ const struct nla_policy ethnl_tsinfo_get_policy[] = {
|
||||
|
||||
static int tsinfo_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
|
@ -24,7 +24,7 @@ const struct nla_policy ethnl_wol_get_policy[] = {
|
||||
|
||||
static int wol_prepare_data(const struct ethnl_req_info *req_base,
|
||||
struct ethnl_reply_data *reply_base,
|
||||
struct genl_info *info)
|
||||
const struct genl_info *info)
|
||||
{
|
||||
struct wol_reply_data *data = WOL_REPDATA(reply_base);
|
||||
struct net_device *dev = reply_base->dev;
|
||||
@ -39,7 +39,8 @@ static int wol_prepare_data(const struct ethnl_req_info *req_base,
|
||||
dev->ethtool_ops->get_wol(dev, &data->wol);
|
||||
ethnl_ops_complete(dev);
|
||||
/* do not include password in notifications */
|
||||
data->show_sopass = info && (data->wol.supported & WAKE_MAGICSECURE);
|
||||
data->show_sopass = !genl_info_is_ntf(info) &&
|
||||
(data->wol.supported & WAKE_MAGICSECURE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user