netlink: strict attribute checking option
Subsystems (15)
cover netlink: strict attribute checking option
When sending a netlink request (NLM_F_REQUEST), any unknown attributes are ignored. This behavior is problematic in some situations. For example if the user asks for a particular config, the request finishes successfully, yet the configuraton applied does not work because some of the attributes are not supported by the kernel (e.g. because it's older than the user space tool).
We're hitting this when configuring metadata based lwtunnels from user space
applications: it would be surely nice if iproute2 warned about this, as the resulting tunnel silently won't work with encap routes. Worse, it's quite crucial for openvswitch and similar programs when deciding what kernel API (lwtunnel vs. legacy) to use.
This patchset tries to solve this. Everything should be compatible with old kernels that don't have this patchset.
Before using this new facility, the application should check whether it is supported by the kernel. This is done by sending a NLMSG_NOOP message with NLM_F_REQUEST | NLM_F_STRICT | NLM_F_ACK flags set. If the returned message has NLM_F_STRICT set, the kernel does support NLM_F_STRICT flag; otherwise, the flag should not be used.
When NLM_F_STRICT is set in a request, the request undergoes stricter checking for compatibility with the current kernel. Presence of any attribute unknown to the kernel will mean the message will be rejected and error returned. In case of success, the request has been performed in the same way as if NLM_F_STRICT was not set.
However, the sole fact that NLM_F_STRICT is supported by the kernel does not yet mean it is supported for the particular netlink family and/or message type. If EPROTO is returned in an error reply, it means that the particular netlink family/message does not support NLM_F_STRICT (yet). In such case, the application could fall back to operation without using NLM_F_STRICT (which is needed for older kernels anyway), possibly warning users that some options may have been ignored by the kernel, if appropriate.
Another option for using this facility is just set NLM_F_STRICT with NLM_F_ACK in a request. There are four results that could happen:
1. Request succeeds and NLM_F_STRICT is set in the reply. Everything is good and verified in this case.
2. Request succeeds but NLM_F_STRICT is not set in the reply. The request was processed but some attributes might (or might not) be ignored because the kernel does not understand NLM_F_STRICT. Warn user if appropriate.
3. Request fails with EPROTO. This means NLM_F_STRICT is not supported for this request. Depending on the needs of the application, either fail hard or try again without NLM_F_STRICT, warning user if appropriate.
4. Request fails with other error code. The request did not succeed.
Applications with hard depency on new kernel features that implement strict checking may choose to abort if NLM_F_STRICT is not set in the reply to NLMSG_NOOP, always use NLM_F_STRICT and treat EPROTO as any other error code.
Note that this RFC patchset is completely untested and may not compile on all configs. I'd like to get feedback on whether this makes sense. For example, I'm not thrilled about the EPROTO error code. Suggestions for a better one are welcome - it needs to be one that is never returned by any netlink operation, though.
Jiri Benc (9):
netlink: add NLM_F_STRICT for strict attribute checking
netlink: remove unnecesary goto's
netlink: strict attribute parsing
netlink: strict attribute validation
rtnetlink: support strict attribute checking
rtnetlink: add strict parameter to validate callbacks
rtnetlink: add strict parameter to validate_link_af
rtnetlink: support strict checking for newlink, setlink and dellink
veth: validate nested attributes
crypto/crypto_user.c | 2 +- drivers/infiniband/core/netlink.c | 2 +- drivers/net/bonding/bond_netlink.c | 3 +- drivers/net/dummy.c | 3 +- drivers/net/geneve.c | 3 +- drivers/net/ifb.c | 3 +- drivers/net/ipvlan/ipvlan_main.c | 3 +- drivers/net/macvlan.c | 3 +- drivers/net/nlmon.c | 3 +- drivers/net/team/team.c | 3 +- drivers/net/tun.c | 3 +- drivers/net/veth.c | 13 +++- drivers/net/vrf.c | 3 +- drivers/net/vxlan.c | 3 +- include/net/netlink.h | 144 ++++++++++++++++++++++++++++++++----- include/net/rtnetlink.h | 37 ++++++++-- include/uapi/linux/netlink.h | 1 + lib/nlattr.c | 56 +++++++++------ net/8021q/vlan_netlink.c | 12 ++-- net/bridge/br_netlink.c | 3 +- net/core/rtnetlink.c | 143 ++++++++++++++++++++++-------------- net/core/sock_diag.c | 2 +- net/ieee802154/6lowpan/core.c | 3 +- net/ipv4/devinet.c | 6 +- net/ipv4/ip_gre.c | 8 ++- net/ipv4/ip_vti.c | 3 +- net/ipv6/addrconf.c | 6 +- net/ipv6/ip6_gre.c | 8 ++- net/ipv6/ip6_tunnel.c | 3 +- net/ipv6/ip6_vti.c | 3 +- net/ipv6/sit.c | 3 +- net/netfilter/nfnetlink.c | 6 +- net/netlink/af_netlink.c | 14 +++- net/netlink/genetlink.c | 2 +- net/xfrm/xfrm_user.c | 2 +- 35 files changed, 371 insertions(+), 144 deletions(-)
Signature · 1 line
1.8.3.1
RFC PATCH 1/9 netlink: add NLM_F_STRICT for strict attribute checking
When NLM_F_STRICT flag is set in a request, the message should undergo stricter check for compatibility with the current kernel, or EPROTO should be returned if such check could not be performed. In addition, NLM_F_STRICT is set in error/ack reply to a request with this flag set.
For now, always return EPROTO.
--- crypto/crypto_user.c | 2 +- drivers/infiniband/core/netlink.c | 2 +- include/net/netlink.h | 2 +- include/uapi/linux/netlink.h | 1 + net/core/rtnetlink.c | 2 +- net/core/sock_diag.c | 2 +- net/netfilter/nfnetlink.c | 6 +++++- net/netlink/af_netlink.c | 14 +++++++++++--- net/netlink/genetlink.c | 2 +- net/xfrm/xfrm_user.c | 2 +- 10 files changed, 24 insertions(+), 11 deletions(-)
crypto/crypto_user.c +1 -1
@@ -526,7 +526,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)static void crypto_netlink_rcv (struct sk_buff *skb) {mutex_lock (&crypto_cfg_mutex); -netlink_rcv_skb (skb, &crypto_user_rcv_msg); +netlink_rcv_skb (skb, false, &crypto_user_rcv_msg);mutex_unlock (&crypto_cfg_mutex); }
drivers/infiniband/core/netlink.c +1 -1
@@ -223,7 +223,7 @@ static void ibnl_rcv(struct sk_buff *skb) {mutex_lock (&ibnl_mutex);ibnl_rcv_reply_skb (skb); -netlink_rcv_skb (skb, &ibnl_rcv_msg); +netlink_rcv_skb (skb, false, &ibnl_rcv_msg);mutex_unlock (&ibnl_mutex); }
include/net/netlink.h +1 -1
@@ -228,7 +228,7 @@ struct nl_info {u32 portid; }; -int netlink_rcv_skb (struct sk_buff *skb, +int netlink_rcv_skb (struct sk_buff *skb,bool strict_supported,int (*cb)(struct sk_buff *,struct nlmsghdr *));int nlmsg_notify (struct sock *sk,struct sk_buff *skb,u32 portid,unsigned int group,int report,gfp_t flags);
include/uapi/linux/netlink.h +1 -0
@@ -55,6 +55,7 @@ struct nlmsghdr {#define NLM_F_ECHO 8/* Echo this request */ #define NLM_F_DUMP_INTR 16/* Dump was inconsistent due to sequence change */ #define NLM_F_DUMP_FILTERED 32/* Dump was filtered as requested */ +#define NLM_F_STRICT 64/* Fail if an attr is unsupported */ /* Modifiers to GET request */ #define NLM_F_ROOT 0x100/* specify tree root */
net/core/rtnetlink.c +1 -1
@@ -3356,7 +3356,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)static void rtnetlink_rcv (struct sk_buff *skb) {rtnl_lock (); -netlink_rcv_skb (skb, &rtnetlink_rcv_msg); +netlink_rcv_skb (skb, false, &rtnetlink_rcv_msg);rtnl_unlock (); }
net/core/sock_diag.c +1 -1
@@ -272,7 +272,7 @@ static DEFINE_MUTEX(sock_diag_mutex);static void sock_diag_rcv (struct sk_buff *skb) {mutex_lock (&sock_diag_mutex); -netlink_rcv_skb (skb, &sock_diag_rcv_msg); +netlink_rcv_skb (skb, false, &sock_diag_rcv_msg);mutex_unlock (&sock_diag_mutex); }
net/netfilter/nfnetlink.c +5 -1
@@ -339,6 +339,10 @@ replay: err = -EINVAL ; goto ack; } +if (nlh->nlmsg_flags &NLM_F_STRICT ) { + err = -EPROTO ; + goto ack; + } type = nlh->nlmsg_type;if (type ==NFNL_MSG_BATCH_BEGIN ) {
@@ -476,7 +480,7 @@ static void nfnetlink_rcv(struct sk_buff *skb) res_id =ntohs (nfgenmsg->res_id);nfnetlink_rcv_batch (skb, nlh, res_id); }else { -netlink_rcv_skb (skb, &nfnetlink_rcv_msg); +netlink_rcv_skb (skb, false, &nfnetlink_rcv_msg); } }
net/netlink/af_netlink.c +11 -3
@@ -2944,6 +2944,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)struct nlmsgerr *errmsg;size_t payload =sizeof (*errmsg);struct netlink_sock *nlk =nlk_sk (NETLINK_CB (in_skb).sk); +unsigned int flags =0 ;/* Error messages get the original request appened, unless the user * requests to cap the error message.
@@ -2967,8 +2968,10 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)return ; } +if (nlh->nlmsg_flags &NLM_F_STRICT ) + flags |=NLM_F_STRICT ; rep =__nlmsg_put (skb,NETLINK_CB (in_skb).portid, nlh->nlmsg_seq, -NLMSG_ERROR , payload,0 ); +NLMSG_ERROR , payload, flags); errmsg =nlmsg_data (rep); errmsg->error = err;memcpy (&errmsg->msg, nlh, payload >sizeof (*errmsg) ? nlh->nlmsg_len :sizeof (*nlh));
@@ -2976,8 +2979,8 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) }EXPORT_SYMBOL (netlink_ack); -int netlink_rcv_skb (struct sk_buff *skb,int (*cb)(struct sk_buff *, -struct nlmsghdr *)) +int netlink_rcv_skb (struct sk_buff *skb,bool strict_supported, +int (*cb)(struct sk_buff *,struct nlmsghdr *)) {struct nlmsghdr *nlh;int err;
@@ -2995,6 +2998,11 @@ int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,if (!(nlh->nlmsg_flags &NLM_F_REQUEST )) goto ack; +if (!strict_supported && (nlh->nlmsg_flags &NLM_F_STRICT )) { + err = -EPROTO ; + goto ack; + } +/* Skip control messages */ if (nlh->nlmsg_type <NLMSG_MIN_TYPE ) goto ack;
net/netlink/genetlink.c +1 -1
@@ -667,7 +667,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)static void genl_rcv (struct sk_buff *skb) {down_read (&cb_lock); -netlink_rcv_skb (skb, &genl_rcv_msg); +netlink_rcv_skb (skb, false, &genl_rcv_msg);up_read (&cb_lock); }
net/xfrm/xfrm_user.c +1 -1
@@ -2491,7 +2491,7 @@ static void xfrm_netlink_rcv(struct sk_buff *skb)struct net *net =sock_net (skb->sk);mutex_lock (&net->xfrm.xfrm_cfg_mutex); -netlink_rcv_skb (skb, &xfrm_user_rcv_msg); +netlink_rcv_skb (skb, false, &xfrm_user_rcv_msg);mutex_unlock (&net->xfrm.xfrm_cfg_mutex); }
Signature · 1 line
1.8.3.1
RFC PATCH 2/9 netlink: remove unnecesary goto's
In reply to Jiri BencJumping to the return makes the code less readable. The compiler will optimize this just fine.
--- lib/nlattr.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
lib/nlattr.c +4 -8
@@ -128,12 +128,10 @@ int nla_validate(const struct nlattr *head, int len, int maxtype,nla_for_each_attr (nla, head, len, rem) { err =validate_nla (nla, maxtype, policy);if (err <0 ) - goto errout; +return err; } - err =0 ; -errout: -return err; +return 0 ; }EXPORT_SYMBOL (nla_validate);
@@ -194,7 +192,7 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,if (policy) { err =validate_nla (nla, maxtype, policy);if (err <0 ) - goto errout; +return err; } tb[type] = (struct nlattr *)nla;
@@ -205,9 +203,7 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,pr_warn_ratelimited ("netlink: %d bytes leftover after parsing attributes in process `%s'.\n" , rem, current->comm); - err =0 ; -errout: -return err; +return 0 ; }EXPORT_SYMBOL (nla_parse);
Signature · 1 line
1.8.3.1
RFC PATCH 3/9 netlink: strict attribute parsing
In reply to Jiri BencEnhance the attribute parsing functions to support strict attribute checking. Keep the semantics of the current nla_parse and nlmsg_parse functions, it's better then changing hundreds of call sites all around the kernel.
--- include/net/netlink.h | 75 ++++++++++++++++++++++++++++++++++++++++++++------- lib/nlattr.c | 20 +++++++++----- 2 files changed, 80 insertions(+), 15 deletions(-)
include/net/netlink.h +66 -9
@@ -235,8 +235,9 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid,int nla_validate (const struct nlattr *head,int len,int maxtype,const struct nla_policy *policy); -int nla_parse (struct nlattr **tb,int maxtype,const struct nlattr *head, -int len,const struct nla_policy *policy); +int nla_strict_parse (struct nlattr **tb,int maxtype,bool strict, +const struct nlattr *head,int len, +const struct nla_policy *policy);int nla_policy_len (const struct nla_policy *,int );struct nlattr *nla_find (const struct nlattr *head,int len,int attrtype);size_t nla_strlcpy (char *dst,const struct nlattr *nla,size_t dstsize);
@@ -356,6 +357,30 @@ nlmsg_next(const struct nlmsghdr *nlh, int *remaining) }/** +* nlmsg_strict_parse - parse attributes of a netlink message +* @nlh: netlink message header +* @hdrlen: length of family specific header +* @tb: destination array with maxtype+1 elements +* @maxtype: maximum attribute type to be expected +* @strict: whether to perform strict checking +* @policy: validation policy +* +* See nla_strict_parse(). +*/ +static inline int nlmsg_strict_parse (const struct nlmsghdr *nlh,int hdrlen, +struct nlattr *tb[],int maxtype, +bool strict, +const struct nla_policy *policy) +{ +if (nlh->nlmsg_len <nlmsg_msg_size (hdrlen)) +return -EINVAL ; + +return nla_strict_parse (tb, maxtype, strict, +nlmsg_attrdata (nlh, hdrlen), +nlmsg_attrlen (nlh, hdrlen), policy); +} + +/** * nlmsg_parse - parse attributes of a netlink message * @nlh: netlink message header * @hdrlen: length of family specific header
@@ -363,17 +388,13 @@ nlmsg_next(const struct nlmsghdr *nlh, int *remaining)* @maxtype: maximum attribute type to be expected * @policy: validation policy * -* See nla_parse() +* See nla_strict_parse(). Strict checking is not performed. */ static inline int nlmsg_parse (const struct nlmsghdr *nlh,int hdrlen,struct nlattr *tb[],int maxtype,const struct nla_policy *policy) { -if (nlh->nlmsg_len <nlmsg_msg_size (hdrlen)) -return -EINVAL ; - -return nla_parse (tb, maxtype,nlmsg_attrdata (nlh, hdrlen), -nlmsg_attrlen (nlh, hdrlen), policy); +return nlmsg_strict_parse (nlh, hdrlen, tb, maxtype, false, policy); }/**
@@ -722,13 +743,49 @@ nla_find_nested(const struct nlattr *nla, int attrtype) }/** +* nla_parse - Parse a stream of attributes into a tb buffer +* @tb: destination array with maxtype+1 elements +* @maxtype: maximum attribute type to be expected +* @head: head of attribute stream +* @len: length of attribute stream +* @policy: validation policy +* +* See nla_strict_parse(). Strict checking is not performed. +*/ +static inline int nla_parse (struct nlattr **tb,int maxtype, +const struct nlattr *head,int len, +const struct nla_policy *policy) +{ +return nla_strict_parse (tb, maxtype, false, head, len, policy); +} + +/** +* nla_strict_parse_nested - parse nested attributes +* @tb: destination array with maxtype+1 elements +* @maxtype: maximum attribute type to be expected +* @strict: whether to perform strict checking +* @nla: attribute containing the nested attributes +* @policy: validation policy +* +* See nla_strict_parse(). Strict checking is not performed. +*/ +static inline int nla_strict_parse_nested (struct nlattr *tb[],int maxtype, +bool strict, +const struct nlattr *nla, +const struct nla_policy *policy) +{ +return nla_strict_parse (tb, maxtype, strict,nla_data (nla), +nla_len (nla), policy); +} + +/** * nla_parse_nested - parse nested attributes * @tb: destination array with maxtype+1 elements * @maxtype: maximum attribute type to be expected * @nla: attribute containing the nested attributes * @policy: validation policy * -* See nla_parse() +* See nla_strict_parse() */ static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, const struct nlattr *nla,
lib/nlattr.c +14 -6
@@ -163,9 +163,10 @@ nla_policy_len(const struct nla_policy *p, int n)EXPORT_SYMBOL (nla_policy_len);/** -* nla_parse - Parse a stream of attributes into a tb buffer +* nla_strict_parse - Parse a stream of attributes into a tb buffer * @tb: destination array with maxtype+1 elements * @maxtype: maximum attribute type to be expected +* @strict: whether to perform strict checking * @head: head of attribute stream * @len: length of attribute stream * @policy: validation policy
@@ -173,12 +174,14 @@ EXPORT_SYMBOL(nla_policy_len);* Parses a stream of attributes and stores a pointer to each attribute in * the tb array accessible via the attribute type. Attributes with a type * exceeding maxtype will be silently ignored for backwards compatibility -* reasons. policy may be set to NULL if no validation is required. +* reasons, unless strict is set. policy may be set to NULL if no validation +* is required. * * Returns 0 on success or a negative error code. */ -int nla_parse (struct nlattr **tb,int maxtype,const struct nlattr *head, -int len,const struct nla_policy *policy) +int nla_strict_parse (struct nlattr **tb,int maxtype,bool strict, +const struct nlattr *head,int len, +const struct nla_policy *policy) {const struct nlattr *nla;int rem, err;
@@ -196,16 +199,21 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, } tb[type] = (struct nlattr *)nla; + }else if (strict) { +return -EINVAL ; } } -if (unlikely (rem >0 )) +if (unlikely (rem >0 )) {pr_warn_ratelimited ("netlink: %d bytes leftover after parsing attributes in process `%s'.\n" , rem, current->comm); +if (strict) +return -EINVAL ; + }return 0 ; } -EXPORT_SYMBOL (nla_parse); +EXPORT_SYMBOL (nla_strict_parse);/** * nla_find - Find a specific attribute in a stream of attributes
Signature · 1 line
1.8.3.1
RFC PATCH 4/9 netlink: strict attribute validation
In reply to Jiri BencEnhance the attribute validation functions to support strict attribute checking. Keep the semantics of the current nla_validate and nlmsg_validate functions.
--- include/net/netlink.h | 67 ++++++++++++++++++++++++++++++++++++++++++++------- lib/nlattr.c | 24 +++++++++++------- 2 files changed, 73 insertions(+), 18 deletions(-)
include/net/netlink.h +58 -9
@@ -233,8 +233,8 @@ int netlink_rcv_skb(struct sk_buff *skb, bool strict_supported,int nlmsg_notify (struct sock *sk,struct sk_buff *skb,u32 portid,unsigned int group,int report,gfp_t flags); -int nla_validate (const struct nlattr *head,int len,int maxtype, -const struct nla_policy *policy); +int nla_strict_validate (const struct nlattr *head,int len,int maxtype, +bool strict,const struct nla_policy *policy);int nla_strict_parse (struct nlattr **tb,int maxtype,bool strict,const struct nlattr *head,int len,const struct nla_policy *policy);
@@ -413,6 +413,26 @@ static inline struct nlattr *nlmsg_find_attr(const struct nlmsghdr *nlh, }/** +* nlmsg_strict_validate - validate a netlink message including attributes +* @nlh: netlinket message header +* @hdrlen: length of familiy specific header +* @maxtype: maximum attribute type to be expected +* @strict: whether to perform strict checking +* @policy: validation policy +*/ +static inline int nlmsg_strict_validate (const struct nlmsghdr *nlh, +int hdrlen,int maxtype,bool strict, +const struct nla_policy *policy) +{ +if (nlh->nlmsg_len <nlmsg_msg_size (hdrlen)) +return -EINVAL ; + +return nla_strict_validate (nlmsg_attrdata (nlh, hdrlen), +nlmsg_attrlen (nlh, hdrlen), maxtype, + strict, policy); +} + +/** * nlmsg_validate - validate a netlink message including attributes * @nlh: netlinket message header * @hdrlen: length of familiy specific header
@@ -423,11 +443,7 @@ static inline int nlmsg_validate(const struct nlmsghdr *nlh, int hdrlen, int maxtype, const struct nla_policy *policy) { - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) - return -EINVAL; - - return nla_validate(nlmsg_attrdata(nlh, hdrlen), -nlmsg_attrlen (nlh ,hdrlen ),maxtype ,policy ); + return nlmsg_strict_validate(nlh, hdrlen, maxtype, false, policy); }/**
@@ -1270,17 +1286,50 @@ static inline void nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) }/** -* nla_validate_nested - Validate a stream of nested attributes +* nla_validate - Validate a stream of attributes +* @head: head of attribute stream +* @len: length of attribute stream +* @maxtype: maximum attribute type to be expected +* @policy: validation policy +* +* See nla_strict_validate(). Strict checking is not performed. +*/ +static inline int nla_validate (const struct nlattr *head,int len, +int maxtype,const struct nla_policy *policy) +{ +return nla_strict_validate (head, len, maxtype, false, policy); +} + +/** +* nla_strict_validate_nested - Validate a stream of nested attributes * @start: container attribute * @maxtype: maximum attribute type to be expected +* @strict: whether to perform strict checking * @policy: validation policy * * Validates all attributes in the nested attribute stream against the * specified policy. Attributes with a type exceeding maxtype will be -* ignored. See documenation of struct nla_policy for more details. +* ignored, unless strict is set. See documenation of struct nla_policy for +* more details. * * Returns 0 on success or a negative error code. */ +static inline int nla_strict_validate_nested (const struct nlattr *start, +int maxtype,bool strict, +const struct nla_policy *policy) +{ +return nla_strict_validate (nla_data (start),nla_len (start), maxtype, + strict, policy); +} + +/** +* nla_validate_nested - Validate a stream of nested attributes +* @start: container attribute +* @maxtype: maximum attribute type to be expected +* @policy: validation policy +* +* See nla_strict_validate_nested(). Strict checking is not performed. +*/ static inline int nla_validate_nested (const struct nlattr *start,int maxtype,const struct nla_policy *policy) {
lib/nlattr.c +15 -9
@@ -27,14 +27,17 @@ static const u16 nla_attr_minlen[NLA_TYPE_MAX+1] = { [NLA_S64] = sizeof(s64), }; -static int validate_nla (const struct nlattr *nla,int maxtype, +static int validate_nla (const struct nlattr *nla,int maxtype,bool strict,const struct nla_policy *policy) {const struct nla_policy *pt;int minlen =0 , attrlen =nla_len (nla), type =nla_type (nla); -if (type <=0 || type > maxtype) +if (type <=0 || type > maxtype) { +if (strict) +return -EINVAL ;return 0 ; + } pt = &policy[type];
@@ -107,33 +110,35 @@ static int validate_nla(const struct nlattr *nla, int maxtype, }/** -* nla_validate - Validate a stream of attributes +* nla_strict_validate - Validate a stream of attributes * @head: head of attribute stream * @len: length of attribute stream * @maxtype: maximum attribute type to be expected +* @strict: whether to perform strict checking * @policy: validation policy * * Validates all attributes in the specified attribute stream against the * specified policy. Attributes with a type exceeding maxtype will be -* ignored. See documenation of struct nla_policy for more details. +* ignored, unless strict is set. See documenation of struct nla_policy for +* more details. * * Returns 0 on success or a negative error code. */ -int nla_validate (const struct nlattr *head,int len,int maxtype, -const struct nla_policy *policy) +int nla_strict_validate (const struct nlattr *head,int len,int maxtype, +bool strict,const struct nla_policy *policy) {const struct nlattr *nla;int rem, err;nla_for_each_attr (nla, head, len, rem) { - err =validate_nla (nla, maxtype, policy); + err =validate_nla (nla, maxtype, strict, policy);if (err <0 )return err; }return 0 ; } -EXPORT_SYMBOL (nla_validate); +EXPORT_SYMBOL (nla_strict_validate);/** * nla_policy_len - Determin the max. length of a policy
@@ -193,7 +198,8 @@ int nla_strict_parse(struct nlattr **tb, int maxtype, bool strict,if (type >0 && type <= maxtype) {if (policy) { - err =validate_nla (nla, maxtype, policy); + err =validate_nla (nla, maxtype, strict, + policy);if (err <0 )return err; }
Signature · 1 line
1.8.3.1
RFC PATCH 5/9 rtnetlink: support strict attribute checking
In reply to Jiri BencAllow rtnl callbacks to support strict attribute checking. They can do so by passing new RTNL_F_STRICT flag to rtnl_register_flags. The semantics of the current rtnl_register and __rtnl_register functions were preserved in order not to change almost hundred of the call sites.
--- include/net/rtnetlink.h | 27 ++++++++++++++++++++++---- net/core/rtnetlink.c | 51 +++++++++++++++++++++++++++++++------------------ 2 files changed, 55 insertions(+), 23 deletions(-)
include/net/rtnetlink.h +23 -4
@@ -8,13 +8,32 @@ typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *);typedef int (*rtnl_dumpit_func )(struct sk_buff *,struct netlink_callback *);typedef u16 (*rtnl_calcit_func )(struct sk_buff *,struct nlmsghdr *); -int __rtnl_register (int protocol,int msgtype, -rtnl_doit_func ,rtnl_dumpit_func ,rtnl_calcit_func ); -void rtnl_register (int protocol,int msgtype, -rtnl_doit_func ,rtnl_dumpit_func ,rtnl_calcit_func ); +#define RTNL_F_STRICT 1 + +int __rtnl_register_flags (int protocol,int msgtype, +rtnl_doit_func ,rtnl_dumpit_func ,rtnl_calcit_func , +unsigned int flags); +void rtnl_register_flags (int protocol,int msgtype, +rtnl_doit_func ,rtnl_dumpit_func ,rtnl_calcit_func , +unsigned int flags);int rtnl_unregister (int protocol,int msgtype);void rtnl_unregister_all (int protocol); +static inline int __rtnl_register (int protocol,int msgtype, +rtnl_doit_func doit,rtnl_dumpit_func dumpit, +rtnl_calcit_func calcit) +{ +return __rtnl_register_flags (protocol, msgtype, + doit, dumpit, calcit,0 ); +} + +static inline void rtnl_register (int protocol,int msgtype, +rtnl_doit_func doit,rtnl_dumpit_func dumpit, +rtnl_calcit_func calcit) +{ +rtnl_register_flags (protocol, msgtype, doit, dumpit, calcit,0 ); +} +static inline int rtnl_msg_family (const struct nlmsghdr *nlh) {if (nlmsg_len (nlh) >=sizeof (struct rtgenmsg ))
net/core/rtnetlink.c +32 -19
129 lines not on this page · raw message
Signature · 1 line
1.8.3.1
RFC PATCH 6/9 rtnetlink: add strict parameter to validate callbacks
In reply to Jiri BencThis is in preparation for rtnetlink to be able to handle strict attribute checking.
The only rtnl_link_ops users that can have nested attributes (and thus need to know whether we're in strict validation mode or not) are 8021q and veth. veth will be handled in a separate patch. 8021q is trivial, it just passes the parameter through to nla_strict_validate_nested.
--- drivers/net/bonding/bond_netlink.c | 3 ++- drivers/net/dummy.c | 3 ++- drivers/net/geneve.c | 3 ++- drivers/net/ifb.c | 3 ++- drivers/net/ipvlan/ipvlan_main.c | 3 ++- drivers/net/macvlan.c | 3 ++- drivers/net/nlmon.c | 3 ++- drivers/net/team/team.c | 3 ++- drivers/net/tun.c | 3 ++- drivers/net/veth.c | 5 +++-- drivers/net/vrf.c | 3 ++- drivers/net/vxlan.c | 3 ++- include/net/rtnetlink.h | 6 ++++-- net/8021q/vlan_netlink.c | 12 +++++++----- net/bridge/br_netlink.c | 3 ++- net/core/rtnetlink.c | 5 +++-- net/ieee802154/6lowpan/core.c | 3 ++- net/ipv4/ip_gre.c | 8 +++++--- net/ipv4/ip_vti.c | 3 ++- net/ipv6/ip6_gre.c | 8 +++++--- net/ipv6/ip6_tunnel.c | 3 ++- net/ipv6/ip6_vti.c | 3 ++- net/ipv6/sit.c | 3 ++- 23 files changed, 61 insertions(+), 34 deletions(-)
drivers/net/bonding/bond_netlink.c +2 -1
@@ -118,7 +118,8 @@ static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { [IFLA_BOND_SLAVE_QUEUE_ID] = { .type = NLA_U16 }, }; -static int bond_validate (struct nlattr *tb[],struct nlattr *data[]) +static int bond_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
drivers/net/dummy.c +2 -1
@@ -152,7 +152,8 @@ static void dummy_setup(struct net_device *dev)eth_hw_addr_random (dev); } -static int dummy_validate (struct nlattr *tb[],struct nlattr *data[]) +static int dummy_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
drivers/net/geneve.c +2 -1
@@ -765,7 +765,8 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { [IFLA_GENEVE_COLLECT_METADATA] = { .type = NLA_FLAG }, }; -static int geneve_validate (struct nlattr *tb[],struct nlattr *data[]) +static int geneve_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
drivers/net/ifb.c +2 -1
@@ -276,7 +276,8 @@ static int ifb_open(struct net_device *dev)return 0 ; } -static int ifb_validate (struct nlattr *tb[],struct nlattr *data[]) +static int ifb_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
drivers/net/ipvlan/ipvlan_main.c +2 -1
@@ -404,7 +404,8 @@ static size_t ipvlan_nl_getsize(const struct net_device *dev) ); } -static int ipvlan_nl_validate (struct nlattr *tb[],struct nlattr *data[]) +static int ipvlan_nl_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (data && data[IFLA_IPVLAN_MODE ]) {u16 mode =nla_get_u16 (data[IFLA_IPVLAN_MODE ]);
drivers/net/macvlan.c +2 -1
@@ -1121,7 +1121,8 @@ static void macvlan_port_destroy(struct net_device *dev)kfree_rcu (port, rcu); } -static int macvlan_validate (struct nlattr *tb[],struct nlattr *data[]) +static int macvlan_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
drivers/net/nlmon.c +2 -1
@@ -147,7 +147,8 @@ static void nlmon_setup(struct net_device *dev) dev->mtu =NLMSG_GOODSIZE ; } -static int nlmon_validate (struct nlattr *tb[],struct nlattr *data[]) +static int nlmon_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ])return -EINVAL ;
drivers/net/team/team.c +2 -1
@@ -2086,7 +2086,8 @@ static int team_newlink(struct net *src_net, struct net_device *dev,return register_netdevice (dev); } -static int team_validate (struct nlattr *tb[],struct nlattr *data[]) +static int team_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
drivers/net/tun.c +2 -1
@@ -1468,7 +1468,8 @@ static void tun_setup(struct net_device *dev)/* Trivial set of netlink ops to allow deleting tun or tap * device with netlink. */ -static int tun_validate (struct nlattr *tb[],struct nlattr *data[]) +static int tun_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {return -EINVAL ; }
drivers/net/veth.c +3 -2
@@ -327,7 +327,8 @@ static void veth_setup(struct net_device *dev)* netlink interface */ -static int veth_validate (struct nlattr *tb[],struct nlattr *data[]) +static int veth_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
@@ -370,7 +371,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,if (err <0 )return err; - err =veth_validate (peer_tb,NULL ); + err =veth_validate (peer_tb,NULL , false);if (err <0 )return err;
drivers/net/vrf.c +2 -1
@@ -887,7 +887,8 @@ static void vrf_setup(struct net_device *dev) dev->features |=NETIF_F_NETNS_LOCAL ; } -static int vrf_validate (struct nlattr *tb[],struct nlattr *data[]) +static int vrf_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
drivers/net/vxlan.c +2 -1
@@ -2478,7 +2478,8 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG }, }; -static int vxlan_validate (struct nlattr *tb[],struct nlattr *data[]) +static int vxlan_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN ) {
include/net/rtnetlink.h +4 -2
@@ -78,7 +78,8 @@ struct rtnl_link_ops {int maxtype;const struct nla_policy *policy;int (*validate)(struct nlattr *tb[], -struct nlattr *data[]); +struct nlattr *data[], +bool strict); int (*newlink)(struct net *src_net, struct net_device *dev,
@@ -103,7 +104,8 @@ struct rtnl_link_ops {int slave_maxtype;const struct nla_policy *slave_policy;int (*slave_validate)(struct nlattr *tb[], -struct nlattr *data[]); +struct nlattr *data[], +bool strict); int (*slave_changelink)(struct net_device *dev, struct net_device *slave_dev, struct nlattr *tb[],
net/8021q/vlan_netlink.c +7 -5
@@ -31,14 +31,16 @@ static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = { }; -static inline int vlan_validate_qos_map (struct nlattr *attr) +static inline int vlan_validate_qos_map (struct nlattr *attr,bool strict) {if (!attr)return 0 ; -return nla_validate_nested (attr,IFLA_VLAN_QOS_MAX , vlan_map_policy); +return nla_strict_validate_nested (attr,IFLA_VLAN_QOS_MAX , strict, + vlan_map_policy); } -static int vlan_validate (struct nlattr *tb[],struct nlattr *data[]) +static int vlan_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {struct ifla_vlan_flags *flags;u16 id;
@@ -77,10 +79,10 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])return -EINVAL ; } - err =vlan_validate_qos_map (data[IFLA_VLAN_INGRESS_QOS ]); + err =vlan_validate_qos_map (data[IFLA_VLAN_INGRESS_QOS ], strict);if (err <0 )return err; - err =vlan_validate_qos_map (data[IFLA_VLAN_EGRESS_QOS ]); + err =vlan_validate_qos_map (data[IFLA_VLAN_EGRESS_QOS ], strict);if (err <0 )return err;return 0 ;
net/bridge/br_netlink.c +2 -1
@@ -746,7 +746,8 @@ int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)return err; } -static int br_validate (struct nlattr *tb[],struct nlattr *data[]) +static int br_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=ETH_ALEN )
net/core/rtnetlink.c +3 -2
@@ -2197,7 +2197,7 @@ replay: data = attr; }if (ops->validate) { - err = ops->validate (tb, data); + err = ops->validate (tb, data, false);if (err <0 )return err; }
@@ -2215,7 +2215,8 @@ replay: slave_data = slave_attr; }if (m_ops->slave_validate) { - err = m_ops->slave_validate (tb, slave_data); + err = m_ops->slave_validate (tb, slave_data, + false);if (err <0 )return err; }
net/ieee802154/6lowpan/core.c +2 -1
@@ -112,7 +112,8 @@ static void lowpan_setup(struct net_device *ldev) ldev->features |=NETIF_F_NETNS_LOCAL ; } -static int lowpan_validate (struct nlattr *tb[],struct nlattr *data[]) +static int lowpan_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {if (tb[IFLA_ADDRESS ]) {if (nla_len (tb[IFLA_ADDRESS ]) !=IEEE802154_ADDR_LEN )
net/ipv4/ip_gre.c +5 -3
@@ -881,7 +881,8 @@ static struct pernet_operations ipgre_net_ops = { .size = sizeof(struct ip_tunnel_net), }; -static int ipgre_tunnel_validate (struct nlattr *tb[],struct nlattr *data[]) +static int ipgre_tunnel_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {__be16 flags;
@@ -899,7 +900,8 @@ static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])return 0 ; } -static int ipgre_tap_validate (struct nlattr *tb[],struct nlattr *data[]) +static int ipgre_tap_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {__be32 daddr;
@@ -920,7 +922,7 @@ static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) } out: -return ipgre_tunnel_validate (tb, data); +return ipgre_tunnel_validate (tb, data, strict); } static void ipgre_netlink_parms(struct net_device *dev,
net/ipv4/ip_vti.c +2 -1
@@ -435,7 +435,8 @@ static struct pernet_operations vti_net_ops = { .size = sizeof(struct ip_tunnel_net), }; -static int vti_tunnel_validate (struct nlattr *tb[],struct nlattr *data[]) +static int vti_tunnel_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {return 0 ; }
net/ipv6/ip6_gre.c +5 -3
@@ -1392,7 +1392,8 @@ static struct pernet_operations ip6gre_net_ops = { .size = sizeof(struct ip6gre_net), }; -static int ip6gre_tunnel_validate (struct nlattr *tb[],struct nlattr *data[]) +static int ip6gre_tunnel_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {__be16 flags;
@@ -1410,7 +1411,8 @@ static int ip6gre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])return 0 ; } -static int ip6gre_tap_validate (struct nlattr *tb[],struct nlattr *data[]) +static int ip6gre_tap_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {struct in6_addr daddr;
@@ -1431,7 +1433,7 @@ static int ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) } out: -return ip6gre_tunnel_validate (tb, data); +return ip6gre_tunnel_validate (tb, data, strict); }
net/ipv6/ip6_tunnel.c +2 -1
@@ -1683,7 +1683,8 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)return 0 ; } -static int ip6_tnl_validate (struct nlattr *tb[],struct nlattr *data[]) +static int ip6_tnl_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {u8 proto;
net/ipv6/ip6_vti.c +2 -1
@@ -899,7 +899,8 @@ static int __net_init vti6_fb_tnl_dev_init(struct net_device *dev)return 0 ; } -static int vti6_validate (struct nlattr *tb[],struct nlattr *data[]) +static int vti6_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {return 0 ; }
net/ipv6/sit.c +2 -1
@@ -1424,7 +1424,8 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)return 0 ; } -static int ipip6_validate (struct nlattr *tb[],struct nlattr *data[]) +static int ipip6_validate (struct nlattr *tb[],struct nlattr *data[], +bool strict) {u8 proto;
Signature · 1 line
1.8.3.1
RFC PATCH 7/9 rtnetlink: add strict parameter to validate_link_af
In reply to Jiri BencThis is in preparation for rtnetlink to be able to handle strict attribute checking.
Nothing complicated here, just pass the parameter through.
--- include/net/rtnetlink.h | 3 ++- net/core/rtnetlink.c | 3 ++- net/ipv4/devinet.c | 6 ++++-- net/ipv6/addrconf.c | 6 ++++-- 4 files changed, 12 insertions(+), 6 deletions(-)
include/net/rtnetlink.h +2 -1
@@ -148,7 +148,8 @@ struct rtnl_af_ops {size_t (*get_link_af_size)(const struct net_device *dev);int (*validate_link_af)(const struct net_device *dev, -const struct nlattr *attr); +const struct nlattr *attr, +bool strict);int (*set_link_af)(struct net_device *dev,const struct nlattr *attr); };
net/core/rtnetlink.c +2 -1
@@ -1491,7 +1491,8 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])return -EOPNOTSUPP ;if (af_ops->validate_link_af) { - err = af_ops->validate_link_af (dev, af); + err = af_ops->validate_link_af (dev, af, + false);if (err <0 )return err; }
net/ipv4/devinet.c +4 -2
@@ -1679,7 +1679,8 @@ static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { };static int inet_validate_link_af (const struct net_device *dev, -const struct nlattr *nla) +const struct nlattr *nla, +bool strict) {struct nlattr *a, *tb[IFLA_INET_MAX +1 ];int err, rem;
@@ -1687,7 +1688,8 @@ static int inet_validate_link_af(const struct net_device *dev,if (dev && !__in_dev_get_rtnl (dev))return -EAFNOSUPPORT ; - err =nla_parse_nested (tb,IFLA_INET_MAX , nla, inet_af_policy); + err =nla_strict_parse_nested (tb,IFLA_INET_MAX , strict, nla, + inet_af_policy);if (err <0 )return err;
net/ipv6/addrconf.c +4 -2
@@ -4876,14 +4876,16 @@ static const struct nla_policy inet6_af_policy[IFLA_INET6_MAX + 1] = { };static int inet6_validate_link_af (const struct net_device *dev, -const struct nlattr *nla) +const struct nlattr *nla, +bool strict) {struct nlattr *tb[IFLA_INET6_MAX +1 ];if (dev && !__in6_dev_get (dev))return -EAFNOSUPPORT ; -return nla_parse_nested (tb,IFLA_INET6_MAX , nla, inet6_af_policy); +return nla_strict_parse_nested (tb,IFLA_INET6_MAX , strict, nla, + inet6_af_policy); }static int inet6_set_link_af (struct net_device *dev,const struct nlattr *nla)
Signature · 1 line
1.8.3.1
RFC PATCH 8/9 rtnetlink: support strict checking for newlink, setlink and dellink
In reply to Jiri Benc--- net/core/rtnetlink.c | 84 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 33 deletions(-)
net/core/rtnetlink.c +51 -33
@@ -1465,7 +1465,8 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) }EXPORT_SYMBOL (rtnl_link_get_net); -static int validate_linkmsg (struct net_device *dev,struct nlattr *tb[]) +static int validate_linkmsg (struct net_device *dev,struct nlattr *tb[], +bool strict) {if (dev) { if (tb[IFLA_ADDRESS] &&
@@ -1492,7 +1493,7 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])if (af_ops->validate_link_af) { err = af_ops->validate_link_af (dev, af, - false); + strict);if (err <0 )return err; }
@@ -1637,7 +1638,8 @@ static int do_set_master(struct net_device *dev, int ifindex)#define DO_SETLINK_NOTIFY 0x03static int do_setlink (const struct sk_buff *skb,struct net_device *dev,struct ifinfomsg *ifm, -struct nlattr **tb,char *ifname,int status) +struct nlattr **tb,char *ifname,int status, +bool strict) {const struct net_device_ops *ops = dev->netdev_ops;int err;
@@ -1799,8 +1801,9 @@ static int do_setlink(const struct sk_buff *skb, err = -EINVAL ; goto errout; } - err =nla_parse_nested (vfinfo,IFLA_VF_MAX , attr, - ifla_vf_policy); + err =nla_strict_parse_nested (vfinfo,IFLA_VF_MAX , + strict, attr, + ifla_vf_policy);if (err <0 ) goto errout; err =do_setvfinfo (dev, vfinfo);
@@ -1827,8 +1830,9 @@ static int do_setlink(const struct sk_buff *skb, err = -EINVAL ; goto errout; } - err =nla_parse_nested (port,IFLA_PORT_MAX , attr, - ifla_port_policy); + err =nla_strict_parse_nested (port,IFLA_PORT_MAX , + strict, attr, + ifla_port_policy);if (err <0 ) goto errout;if (!port[IFLA_PORT_VF ]) {
@@ -1847,8 +1851,9 @@ static int do_setlink(const struct sk_buff *skb,if (tb[IFLA_PORT_SELF ]) {struct nlattr *port[IFLA_PORT_MAX +1 ]; - err =nla_parse_nested (port,IFLA_PORT_MAX , - tb[IFLA_PORT_SELF ], ifla_port_policy); + err =nla_strict_parse_nested (port,IFLA_PORT_MAX , strict, + tb[IFLA_PORT_SELF ], + ifla_port_policy);if (err <0 ) goto errout;
@@ -1908,8 +1913,10 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)int err;struct nlattr *tb[IFLA_MAX +1 ];char ifname[IFNAMSIZ ]; +bool strict = nlh->nlmsg_flags &NLM_F_STRICT ; - err =nlmsg_parse (nlh,sizeof (*ifm), tb,IFLA_MAX , ifla_policy); + err =nlmsg_strict_parse (nlh,sizeof (*ifm), tb,IFLA_MAX , strict, + ifla_policy);if (err <0 ) goto errout;
@@ -1932,11 +1939,11 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) goto errout; } - err =validate_linkmsg (dev, tb); + err =validate_linkmsg (dev, tb, strict);if (err <0 ) goto errout; - err =do_setlink (skb, dev, ifm, tb, ifname,0 ); + err =do_setlink (skb, dev, ifm, tb, ifname,0 , strict); errout:return err; }
@@ -2000,9 +2007,11 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)struct ifinfomsg *ifm;char ifname[IFNAMSIZ ];struct nlattr *tb[IFLA_MAX +1 ]; +bool strict = nlh->nlmsg_flags &NLM_F_STRICT ;int err; - err =nlmsg_parse (nlh,sizeof (*ifm), tb,IFLA_MAX , ifla_policy); + err =nlmsg_strict_parse (nlh,sizeof (*ifm), tb,IFLA_MAX , strict, + ifla_policy);if (err <0 )return err;
@@ -2102,14 +2111,14 @@ EXPORT_SYMBOL(rtnl_create_link);static int rtnl_group_changelink (const struct sk_buff *skb,struct net *net,int group,struct ifinfomsg *ifm, -struct nlattr **tb) +struct nlattr **tb,bool strict) {struct net_device *dev, *aux;int err;for_each_netdev_safe (net, dev, aux) {if (dev->group == group) { - err =do_setlink (skb, dev, ifm, tb,NULL ,0 ); + err =do_setlink (skb, dev, ifm, tb,NULL ,0 , strict);if (err <0 )return err; }
@@ -2131,12 +2140,14 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh)struct nlattr *tb[IFLA_MAX +1 ];struct nlattr *linkinfo[IFLA_INFO_MAX +1 ];unsigned char name_assign_type =NET_NAME_USER ; +bool strict = nlh->nlmsg_flags &NLM_F_STRICT ;int err;#ifdef CONFIG_MODULES replay:#endif - err =nlmsg_parse (nlh,sizeof (*ifm), tb,IFLA_MAX , ifla_policy); + err =nlmsg_strict_parse (nlh,sizeof (*ifm), tb,IFLA_MAX , strict, + ifla_policy);if (err <0 )return err;
@@ -2161,13 +2172,14 @@ replay: m_ops = master_dev->rtnl_link_ops; } - err =validate_linkmsg (dev, tb); + err =validate_linkmsg (dev, tb, strict);if (err <0 )return err;if (tb[IFLA_LINKINFO ]) { - err =nla_parse_nested (linkinfo,IFLA_INFO_MAX , - tb[IFLA_LINKINFO ], ifla_info_policy); + err =nla_strict_parse_nested (linkinfo,IFLA_INFO_MAX , + strict, tb[IFLA_LINKINFO ], + ifla_info_policy);if (err <0 )return err; }else
@@ -2190,15 +2202,16 @@ replay:if (ops) {if (ops->maxtype && linkinfo[IFLA_INFO_DATA ]) { - err =nla_parse_nested (attr, ops->maxtype, - linkinfo[IFLA_INFO_DATA ], - ops->policy); + err =nla_strict_parse_nested (attr, ops->maxtype, + strict, + linkinfo[IFLA_INFO_DATA ], + ops->policy);if (err <0 )return err; data = attr; }if (ops->validate) { - err = ops->validate (tb, data, false); + err = ops->validate (tb, data, strict);if (err <0 )return err; }
@@ -2207,17 +2220,18 @@ replay:if (m_ops) {if (m_ops->slave_maxtype && linkinfo[IFLA_INFO_SLAVE_DATA ]) { - err =nla_parse_nested (slave_attr, - m_ops->slave_maxtype, - linkinfo[IFLA_INFO_SLAVE_DATA ], - m_ops->slave_policy); + err =nla_strict_parse_nested (slave_attr, + m_ops->slave_maxtype, + strict, + linkinfo[IFLA_INFO_SLAVE_DATA ], + m_ops->slave_policy);if (err <0 )return err; slave_data = slave_attr; }if (m_ops->slave_validate) { err = m_ops->slave_validate (tb, slave_data, - false); + strict);if (err <0 )return err; }
@@ -2253,14 +2267,15 @@ replay: status |=DO_SETLINK_NOTIFY ; } -return do_setlink (skb, dev, ifm, tb, ifname, status); +return do_setlink (skb, dev, ifm, tb, ifname, status, + strict); }if (!(nlh->nlmsg_flags &NLM_F_CREATE )) {if (ifm->ifi_index ==0 && tb[IFLA_GROUP ])return rtnl_group_changelink (skb, net,nla_get_u32 (tb[IFLA_GROUP ]), - ifm, tb); + ifm, tb, strict);return -ENODEV ; }
@@ -3443,9 +3458,12 @@ void __init rtnetlink_init(void)rtnl_register (PF_UNSPEC ,RTM_GETLINK , rtnl_getlink, rtnl_dump_ifinfo, rtnl_calcit); -rtnl_register (PF_UNSPEC ,RTM_SETLINK , rtnl_setlink,NULL ,NULL ); -rtnl_register (PF_UNSPEC ,RTM_NEWLINK , rtnl_newlink,NULL ,NULL ); -rtnl_register (PF_UNSPEC ,RTM_DELLINK , rtnl_dellink,NULL ,NULL ); +rtnl_register_flags (PF_UNSPEC ,RTM_SETLINK , rtnl_setlink,NULL ,NULL , +RTNL_F_STRICT ); +rtnl_register_flags (PF_UNSPEC ,RTM_NEWLINK , rtnl_newlink,NULL ,NULL , +RTNL_F_STRICT ); +rtnl_register_flags (PF_UNSPEC ,RTM_DELLINK , rtnl_dellink,NULL ,NULL , +RTNL_F_STRICT );rtnl_register (PF_UNSPEC ,RTM_GETADDR ,NULL , rtnl_dump_all,NULL );rtnl_register (PF_UNSPEC ,RTM_GETROUTE ,NULL , rtnl_dump_all,NULL );
Signature · 1 line
1.8.3.1
RFC PATCH 9/9 veth: validate nested attributes
In reply to Jiri BencFor strict attribute checking, it's necessary to validate nested attributes in the validate rtnl_link_ops callback.
--- drivers/net/veth.c | 8 ++++++++ include/net/rtnetlink.h | 1 + net/core/rtnetlink.c | 6 ++++++ 3 files changed, 15 insertions(+)
drivers/net/veth.c +8 -0
@@ -340,6 +340,14 @@ static int veth_validate(struct nlattr *tb[], struct nlattr *data[],if (!is_valid_veth_mtu (nla_get_u32 (tb[IFLA_MTU ])))return -EINVAL ; } +if (data !=NULL && data[VETH_INFO_PEER ] !=NULL ) { +struct nlattr *nla_peer = data[VETH_INFO_PEER ]; + +return rtnl_nla_validate_ifla ( +nla_data (nla_peer) +sizeof (struct ifinfomsg ), +nla_len (nla_peer) -sizeof (struct ifinfomsg ), + strict); + }return 0 ; }
include/net/rtnetlink.h +1 -0
@@ -168,6 +168,7 @@ int rtnl_delete_link(struct net_device *dev);int rtnl_configure_link (struct net_device *dev,const struct ifinfomsg *ifm);int rtnl_nla_parse_ifla (struct nlattr **tb,const struct nlattr *head,int len); +int rtnl_nla_validate_ifla (const struct nlattr *head,int len,bool strict);#define MODULE_ALIAS_RTNL_LINK (kind) MODULE_ALIAS("rtnl-link-" kind)
net/core/rtnetlink.c +6 -0
@@ -1449,6 +1449,12 @@ int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len) }EXPORT_SYMBOL (rtnl_nla_parse_ifla); +int rtnl_nla_validate_ifla (const struct nlattr *head,int len,bool strict) +{ +return nla_strict_validate (head, len,IFLA_MAX , strict, ifla_policy); +} +EXPORT_SYMBOL (rtnl_nla_validate_ifla); +struct net *rtnl_link_get_net (struct net *src_net,struct nlattr *tb[]) {struct net *net;
Signature · 1 line
1.8.3.1
Quoted 5 lines · Jiri Benc
Before using this new facility, the application should check whether it is supported by the kernel. This is done by sending a
NLMSG_NOOPmessage withNLM_F_REQUEST|NLM_F_STRICT|NLM_F_ACKflags set. If the returned message hasNLM_F_STRICTset, the kernel does supportNLM_F_STRICTflag; otherwise, the flag should not be used.
Do you plan to update rfc3549, too? :}
Bye,
Hannes
Quoted 1 line · Hannes Frederic Sowa
Do you plan to update rfc3549, too? :}
No.
While I think we need to have a detailed documentation on netlink, I believe it should reside in Documentation/ inside the kernel tree to be easily updated, not in an outside document collection with much more heavyweight processes around getting something updated.
I would offer taking the RFC 3549 into the kernel tree and extending it but my understanding of the license is that I'm not allowed to do that (as I would modify the "document itself").
Jiri
Signature · 1 line
Jiri Benc
David Miller
maintainerFrom: Jiri Benc <[email protected]>
Date: Fri, 16 Oct 2015 09:49:51 +0200
Quoted 9 lines · Hannes Frederic Sowa
Quoted 1 line
Do you plan to update rfc3549, too? :}
No.
While I think we need to have a detailed documentation on netlink, I believe it should reside in
Documentation/inside the kernel tree to be easily updated, not in an outside document collection with much more heavyweight processes around getting something updated.
I think his point is that you'll be making changes to an RFC specified protocol.
But I think we need a better solution to this.
Quoted 2 lines · David Miller
I think his point is that you'll be making changes to an RFC specified protocol.
The RFC is only informational, it has never became an Internet standard (under the RFC terms). And no other OS picked it up. Keeping kernel uAPI documentation in IETF database sounds rather inefficient.
Quoted 1 line
But I think we need a better solution to this.
I'm not opposed to a better solution. I just don't see any that's not a gross hack. Suggestions are welcome.
Jiri
Signature · 1 line
Jiri Benc
Hi,
Quoted 7 lines · Jiri Benc
Quoted 2 lines · David Miller
I think his point is that you'll be making changes to an RFC specified protocol.
The RFC is only informational, it has never became an Internet standard (under the RFC terms). And no other OS picked it up. Keeping kernel uAPI documentation in IETF database sounds rather inefficient.
I would suggest you simply add a description to the rfc via the errata process here: <https://www.rfc-editor.org/errata_report.php>
The original cover letter should be enough to post there. I am also not sure if people do really implement this spec, at least they have a pointer to it, then. AFAIK the IESG will look into that then and even non-approved erratas will be listed on the rfc page.
Bye,
Hannes
Quoted 7 lines · Hannes Frederic Sowa
I would suggest you simply add a description to the rfc via the errata process here: <https://www.rfc-editor.org/errata_report.php>
The original cover letter should be enough to post there. I am also not sure if people do really implement this spec, at least they have a pointer to it, then. AFAIK the IESG will look into that then and even non-approved erratas will be listed on the rfc page.
Okay, we may do that. But let's postpone this discussion after we decide what route we'll go. We'll definitely need some form of documentation but it's preliminary to discuss what exact form when we haven't decided whether we'll implement something like this at all.
Jiri
Signature · 1 line
Jiri Benc
David Miller
maintainerFrom: Jiri Benc <[email protected]>
Date: Thu, 15 Oct 2015 18:39:05 +0200
Quoted 6 lines
When sending a netlink request (
NLM_F_REQUEST), any unknown attributes are ignored. This behavior is problematic in some situations. For example if the user asks for a particular config, the request finishes successfully, yet the configuraton applied does not work because some of the attributes are not supported by the kernel (e.g. because it's older than the user space tool).
Although we are probably stuck with this, it was probably a bad idea to have this behavior as the default.
Better would have been to always error on unrecognized attributes, and in the ACK give some indication of which attribute was problematic.
But anyhow we are stuck with what we have. However, I will say I am disappointed that it is so hard to simply detect that lwtunnel support is present, which as I understand is what this patch set is trying to accomplish.
And this is quite an intrusive patch series, and therefore not suitable for -stable backports. And that's exactly where you actually are going to need these changes right? Older kernels that lack lwtunnel support.
Quoted 2 lines · David Miller
Although we are probably stuck with this, it was probably a bad idea to have this behavior as the default.
I agree. But we have what we have.
Quoted 2 lines
Better would have been to always error on unrecognized attributes, and in the ACK give some indication of which attribute was problematic.
Should I try to extend the patches to return such information back to the user? It would mean more intrusiveness, as there's no space in ack to store such information (it would have been better to use attributes even in the error responses instead of a fixed structure...).
Quoted 4 lines
But anyhow we are stuck with what we have. However, I will say I am disappointed that it is so hard to simply detect that lwtunnel support is present, which as I understand is what this patch set is trying to accomplish.
Yes, main motivation is lwtunnel support. However, I'd say this is useful outside of it, too.
Quoted 4 lines
And this is quite an intrusive patch series, and therefore not suitable for -stable backports. And that's exactly where you actually are going to need these changes right? Older kernels that lack lwtunnel support.
I'm targeting net-next only and don't intend to bring this to older kernels. The patchset is designed in the way that it's possible to detect that the kernel does not support strict attribute checking. When this is detected, the tools will just assume that lwtunnel support is not there. That's completely okay, it will just mean that the 4.3 kernel will be treated as not having lwtunnel support; everything will work correctly, including openvswitch (which will use its compat code).
Jiri
Signature · 1 line
Jiri Benc
David Miller
maintainerFrom: Jiri Benc <[email protected]>
Date: Fri, 16 Oct 2015 09:39:45 +0200
Quoted 5 lines
I'm targeting net-next only and don't intend to bring this to older kernels. The patchset is designed in the way that it's possible to detect that the kernel does not support strict attribute checking. When this is detected, the tools will just assume that lwtunnel support is not there.
No, it's definitely not OK, because lwtunnel support exists in Linus's tree.
And tools should be able to work on all kernels where lwtunnel support is available.
Quoted 5 lines · David Miller
No, it's definitely not OK, because lwtunnel support exists in Linus's tree.
And tools should be able to work on all kernels where lwtunnel support is available.
You can consider the lwtunnels feature as not finished in the current Linus's tree. It works, it won't change (thus anything using it in its current form will continue to work in all the future kernels), but mainstream tools won't make use of it until a kernel version later which will get some additional support.
I don't think it's much of a problem and I don't think it is the first time this would happen.
I'm afraid I don't have any solution that could do better.
Jiri
Signature · 1 line
Jiri Benc
Quoted 13 lines · Jiri Benc
Quoted 5 lines · David Miller
No, it's definitely not OK, because lwtunnel support exists in Linus's tree.
And tools should be able to work on all kernels where lwtunnel support is available.
You can consider the lwtunnels feature as not finished in the current Linus's tree. It works, it won't change (thus anything using it in its current form will continue to work in all the future kernels), but mainstream tools won't make use of it until a kernel version later which will get some additional support.
Quoted 4 lines
I don't think it's much of a problem and I don't think it is the first time this would happen.
I'm afraid I don't have any solution that could do better.
Maybe we should be more precise here. The detection mechanism is only for tools which want to know whether lwt or another feature is supported without going through the pain of creating an object, checking its attributes and then deleting the object again if no full support was detected. The existing flow of configuration through iproute2 will be supported just like for any other new feature that we have introduced.
Therefore, I consider this a future optimization.
This is very much related to the offload problematic we had or still have of "only program in HW if you can do the full thing vs best effort" so this flag will be of use in a wider context.
Quoted 13 lines · Jiri Benc
Quoted 5 lines · David Miller
No, it's definitely not OK, because lwtunnel support exists in Linus's tree.
And tools should be able to work on all kernels where lwtunnel support is available.
You can consider the lwtunnels feature as not finished in the current Linus's tree. It works, it won't change (thus anything using it in its current form will continue to work in all the future kernels), but mainstream tools won't make use of it until a kernel version later which will get some additional support.
Quoted 4 lines
I don't think it's much of a problem and I don't think it is the first time this would happen.
I'm afraid I don't have any solution that could do better.
What about a flag that requests the version from the relevant kernel subsystem?
Generate the same initial netlink message -- e.g., type set to RTM_NEWROUTE for example -- but with no attributes and the NLM_F_VERSION flag set. Send the message using whatever socket protocol is relevant for the command/query.
Then kernel side the message makes its way to the relevant handler, the handler sees the flag asking for version and responds with its version. The version would be local to the handler and is a means for telling userspace what attributes it understands.
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Fri, 16 Oct 2015 09:57:33 -0600
Quoted 14 lines · Jiri Benc
Quoted 13 lines · David Miller
Quoted 5 lines
No, it's definitely not OK, because lwtunnel support exists in Linus's tree.
And tools should be able to work on all kernels where lwtunnel support is available.
You can consider the lwtunnels feature as not finished in the current Linus's tree. It works, it won't change (thus anything using it in its current form will continue to work in all the future kernels), but mainstream tools won't make use of it until a kernel version later which will get some additional support.
Quoted 7 lines
Quoted 4 lines
I don't think it's much of a problem and I don't think it is the first time this would happen.
I'm afraid I don't have any solution that could do better.
What about a flag that requests the version from the relevant kernel subsystem?
The whole point of having an easily extensible protocol like netlink with attributes and whatnot was to avoid messy schemes like versioning.
The big mistake was ignoring unknown attributes. I mean seriously, think about it, what if the new attribute specified by the user was some security setting or something? I'm sure even more dangerous examples can be imagined.
I'm beginning to wonder if we can just change this unilaterally to not ignore unrecognized attributes.
I am increasingly certain that things that would "break" we wouldn't want to succeed anyways.