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 >