mirror of https://gitee.com/openkylin/linux.git
netlink: Add new socket option to enable strict checking on dumps
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 <dsahern@gmail.com> Acked-by: Christian Brauner <christian@brauner.io> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6ba1e6e856
commit
89d35528d1
|
@ -179,6 +179,7 @@ struct netlink_callback {
|
||||||
struct netlink_ext_ack *extack;
|
struct netlink_ext_ack *extack;
|
||||||
u16 family;
|
u16 family;
|
||||||
u16 min_dump_alloc;
|
u16 min_dump_alloc;
|
||||||
|
bool strict_check;
|
||||||
unsigned int prev_seq, seq;
|
unsigned int prev_seq, seq;
|
||||||
long args[6];
|
long args[6];
|
||||||
};
|
};
|
||||||
|
|
|
@ -155,6 +155,7 @@ enum nlmsgerr_attrs {
|
||||||
#define NETLINK_LIST_MEMBERSHIPS 9
|
#define NETLINK_LIST_MEMBERSHIPS 9
|
||||||
#define NETLINK_CAP_ACK 10
|
#define NETLINK_CAP_ACK 10
|
||||||
#define NETLINK_EXT_ACK 11
|
#define NETLINK_EXT_ACK 11
|
||||||
|
#define NETLINK_DUMP_STRICT_CHK 12
|
||||||
|
|
||||||
struct nl_pktinfo {
|
struct nl_pktinfo {
|
||||||
__u32 group;
|
__u32 group;
|
||||||
|
|
|
@ -1706,6 +1706,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
|
||||||
nlk->flags &= ~NETLINK_F_EXT_ACK;
|
nlk->flags &= ~NETLINK_F_EXT_ACK;
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
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:
|
default:
|
||||||
err = -ENOPROTOOPT;
|
err = -ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
|
@ -1799,6 +1806,15 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
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:
|
default:
|
||||||
err = -ENOPROTOOPT;
|
err = -ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
|
@ -2282,9 +2298,9 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
|
||||||
const struct nlmsghdr *nlh,
|
const struct nlmsghdr *nlh,
|
||||||
struct netlink_dump_control *control)
|
struct netlink_dump_control *control)
|
||||||
{
|
{
|
||||||
|
struct netlink_sock *nlk, *nlk2;
|
||||||
struct netlink_callback *cb;
|
struct netlink_callback *cb;
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
struct netlink_sock *nlk;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
refcount_inc(&skb->users);
|
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->min_dump_alloc = control->min_dump_alloc;
|
||||||
cb->skb = skb;
|
cb->skb = skb;
|
||||||
|
|
||||||
|
nlk2 = nlk_sk(NETLINK_CB(skb).sk);
|
||||||
|
cb->strict_check = !!(nlk2->flags & NETLINK_F_STRICT_CHK);
|
||||||
|
|
||||||
if (control->start) {
|
if (control->start) {
|
||||||
ret = control->start(cb);
|
ret = control->start(cb);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#define NETLINK_F_LISTEN_ALL_NSID 0x10
|
#define NETLINK_F_LISTEN_ALL_NSID 0x10
|
||||||
#define NETLINK_F_CAP_ACK 0x20
|
#define NETLINK_F_CAP_ACK 0x20
|
||||||
#define NETLINK_F_EXT_ACK 0x40
|
#define NETLINK_F_EXT_ACK 0x40
|
||||||
|
#define NETLINK_F_STRICT_CHK 0x80
|
||||||
|
|
||||||
#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8)
|
#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8)
|
||||||
#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long))
|
#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long))
|
||||||
|
|
Loading…
Reference in New Issue