On Sun, Oct 07, 2018 at 08:16:27PM -0700, David Ahern wrote:
> From: David Ahern <dsah...@gmail.com>
> 
> Add a new socket option, NETLINK_DUMP_STRICT_CHK, that userspace
> can use via setsockopt to request strict checking of headers and
> attributes on dump requests.
> 
> To get dump features such as kernel side filtering based on data in
> the header or attributes appended to the dump request, userspace
> must call setsockopt() for NETLINK_DUMP_STRICT_CHK and a non-zero
> value. Since the netlink sock and its flags are private to the
> af_netlink code, the strict checking flag is passed to dump handlers
> via a flag in the netlink_callback struct.
> 
> For old userspace on new kernel there is no impact as all of the data
> checks in later patches are wrapped in a check on the new strict flag.
> 
> For new userspace on old kernel, the setsockopt will fail and even if
> new userspace sets data in the headers and appended attributes the
> kernel will silently ignore it. Moving forward when the setsockopt
> succeeds, the new userspace on old kernel means the dump request can
> pass an attribute the kernel does not understand. The dump will then
> fail as the older kernel does not understand it.
> 
> New userspace on new kernel setting the socket option gets the benefit
> of the improved data dump.
> 
> Kernel side the NETLINK_DUMP_STRICT_CHK uapi is converted to a generic
> NETLINK_F_STRICT_CHK flag which can potentially be leveraged for tighter
> checking on the NEW, DEL, and SET commands.
> 
> Signed-off-by: David Ahern <dsah...@gmail.com>

Thanks for the bool. :)

Acked-by: Christian Brauner <christ...@brauner.io>

> ---
>  include/linux/netlink.h      |  1 +
>  include/uapi/linux/netlink.h |  1 +
>  net/netlink/af_netlink.c     | 21 ++++++++++++++++++++-
>  net/netlink/af_netlink.h     |  1 +
>  4 files changed, 23 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/netlink.h b/include/linux/netlink.h
> index 88c8a2d83eb3..72580f1a72a2 100644
> --- a/include/linux/netlink.h
> +++ b/include/linux/netlink.h
> @@ -179,6 +179,7 @@ struct netlink_callback {
>       struct netlink_ext_ack  *extack;
>       u16                     family;
>       u16                     min_dump_alloc;
> +     bool                    strict_check;
>       unsigned int            prev_seq, seq;
>       long                    args[6];
>  };
> diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
> index 776bc92e9118..486ed1f0c0bc 100644
> --- a/include/uapi/linux/netlink.h
> +++ b/include/uapi/linux/netlink.h
> @@ -155,6 +155,7 @@ enum nlmsgerr_attrs {
>  #define NETLINK_LIST_MEMBERSHIPS     9
>  #define NETLINK_CAP_ACK                      10
>  #define NETLINK_EXT_ACK                      11
> +#define NETLINK_DUMP_STRICT_CHK              12
>  
>  struct nl_pktinfo {
>       __u32   group;
> diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
> index 7ac585f33a9e..e613a9f89600 100644
> --- a/net/netlink/af_netlink.c
> +++ b/net/netlink/af_netlink.c
> @@ -1706,6 +1706,13 @@ static int netlink_setsockopt(struct socket *sock, int 
> level, int optname,
>                       nlk->flags &= ~NETLINK_F_EXT_ACK;
>               err = 0;
>               break;
> +     case NETLINK_DUMP_STRICT_CHK:
> +             if (val)
> +                     nlk->flags |= NETLINK_F_STRICT_CHK;
> +             else
> +                     nlk->flags &= ~NETLINK_F_STRICT_CHK;
> +             err = 0;
> +             break;
>       default:
>               err = -ENOPROTOOPT;
>       }
> @@ -1799,6 +1806,15 @@ static int netlink_getsockopt(struct socket *sock, int 
> level, int optname,
>                       return -EFAULT;
>               err = 0;
>               break;
> +     case NETLINK_DUMP_STRICT_CHK:
> +             if (len < sizeof(int))
> +                     return -EINVAL;
> +             len = sizeof(int);
> +             val = nlk->flags & NETLINK_F_STRICT_CHK ? 1 : 0;
> +             if (put_user(len, optlen) || put_user(val, optval))
> +                     return -EFAULT;
> +             err = 0;
> +             break;
>       default:
>               err = -ENOPROTOOPT;
>       }
> @@ -2282,9 +2298,9 @@ int __netlink_dump_start(struct sock *ssk, struct 
> sk_buff *skb,
>                        const struct nlmsghdr *nlh,
>                        struct netlink_dump_control *control)
>  {
> +     struct netlink_sock *nlk, *nlk2;
>       struct netlink_callback *cb;
>       struct sock *sk;
> -     struct netlink_sock *nlk;
>       int ret;
>  
>       refcount_inc(&skb->users);
> @@ -2318,6 +2334,9 @@ int __netlink_dump_start(struct sock *ssk, struct 
> sk_buff *skb,
>       cb->min_dump_alloc = control->min_dump_alloc;
>       cb->skb = skb;
>  
> +     nlk2 = nlk_sk(NETLINK_CB(skb).sk);
> +     cb->strict_check = !!(nlk2->flags & NETLINK_F_STRICT_CHK);
> +
>       if (control->start) {
>               ret = control->start(cb);
>               if (ret)
> diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
> index 962de7b3c023..5f454c8de6a4 100644
> --- a/net/netlink/af_netlink.h
> +++ b/net/netlink/af_netlink.h
> @@ -15,6 +15,7 @@
>  #define NETLINK_F_LISTEN_ALL_NSID    0x10
>  #define NETLINK_F_CAP_ACK            0x20
>  #define NETLINK_F_EXT_ACK            0x40
> +#define NETLINK_F_STRICT_CHK         0x80
>  
>  #define NLGRPSZ(x)   (ALIGN(x, sizeof(unsigned long) * 8) / 8)
>  #define NLGRPLONGS(x)        (NLGRPSZ(x)/sizeof(unsigned long))
> -- 
> 2.11.0
> 

Reply via email to