diff options
Diffstat (limited to 'net/tipc/netlink_compat.c')
| -rw-r--r-- | net/tipc/netlink_compat.c | 54 | 
1 files changed, 52 insertions, 2 deletions
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 40f5cae623a7..4ad3586da8f0 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -87,6 +87,11 @@ static int tipc_skb_tailroom(struct sk_buff *skb)  	return limit;  } +static inline int TLV_GET_DATA_LEN(struct tlv_desc *tlv) +{ +	return TLV_GET_LEN(tlv) - TLV_SPACE(0); +} +  static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len)  {  	struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb); @@ -166,6 +171,11 @@ static struct sk_buff *tipc_get_err_tlv(char *str)  	return buf;  } +static inline bool string_is_valid(char *s, int len) +{ +	return memchr(s, '\0', len) ? true : false; +} +  static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,  				   struct tipc_nl_compat_msg *msg,  				   struct sk_buff *arg) @@ -379,6 +389,7 @@ static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd,  	struct nlattr *prop;  	struct nlattr *bearer;  	struct tipc_bearer_config *b; +	int len;  	b = (struct tipc_bearer_config *)TLV_DATA(msg->req); @@ -386,6 +397,10 @@ static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd,  	if (!bearer)  		return -EMSGSIZE; +	len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME); +	if (!string_is_valid(b->name, len)) +		return -EINVAL; +  	if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name))  		return -EMSGSIZE; @@ -411,6 +426,7 @@ static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd,  {  	char *name;  	struct nlattr *bearer; +	int len;  	name = (char *)TLV_DATA(msg->req); @@ -418,6 +434,10 @@ static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd,  	if (!bearer)  		return -EMSGSIZE; +	len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME); +	if (!string_is_valid(name, len)) +		return -EINVAL; +  	if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name))  		return -EMSGSIZE; @@ -478,6 +498,7 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg,  	struct nlattr *prop[TIPC_NLA_PROP_MAX + 1];  	struct nlattr *stats[TIPC_NLA_STATS_MAX + 1];  	int err; +	int len;  	if (!attrs[TIPC_NLA_LINK])  		return -EINVAL; @@ -504,6 +525,11 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg,  		return err;  	name = (char *)TLV_DATA(msg->req); + +	len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); +	if (!string_is_valid(name, len)) +		return -EINVAL; +  	if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0)  		return 0; @@ -644,6 +670,7 @@ static int tipc_nl_compat_media_set(struct sk_buff *skb,  	struct nlattr *prop;  	struct nlattr *media;  	struct tipc_link_config *lc; +	int len;  	lc = (struct tipc_link_config *)TLV_DATA(msg->req); @@ -651,6 +678,10 @@ static int tipc_nl_compat_media_set(struct sk_buff *skb,  	if (!media)  		return -EMSGSIZE; +	len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_MEDIA_NAME); +	if (!string_is_valid(lc->name, len)) +		return -EINVAL; +  	if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name))  		return -EMSGSIZE; @@ -671,6 +702,7 @@ static int tipc_nl_compat_bearer_set(struct sk_buff *skb,  	struct nlattr *prop;  	struct nlattr *bearer;  	struct tipc_link_config *lc; +	int len;  	lc = (struct tipc_link_config *)TLV_DATA(msg->req); @@ -678,6 +710,10 @@ static int tipc_nl_compat_bearer_set(struct sk_buff *skb,  	if (!bearer)  		return -EMSGSIZE; +	len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_MEDIA_NAME); +	if (!string_is_valid(lc->name, len)) +		return -EINVAL; +  	if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name))  		return -EMSGSIZE; @@ -726,9 +762,14 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd,  	struct tipc_link_config *lc;  	struct tipc_bearer *bearer;  	struct tipc_media *media; +	int len;  	lc = (struct tipc_link_config *)TLV_DATA(msg->req); +	len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); +	if (!string_is_valid(lc->name, len)) +		return -EINVAL; +  	media = tipc_media_find(lc->name);  	if (media) {  		cmd->doit = &__tipc_nl_media_set; @@ -750,6 +791,7 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd,  {  	char *name;  	struct nlattr *link; +	int len;  	name = (char *)TLV_DATA(msg->req); @@ -757,6 +799,10 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd,  	if (!link)  		return -EMSGSIZE; +	len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); +	if (!string_is_valid(name, len)) +		return -EINVAL; +  	if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name))  		return -EMSGSIZE; @@ -778,6 +824,8 @@ static int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg)  	};  	ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req); +	if (TLV_GET_DATA_LEN(msg->req) < sizeof(struct tipc_name_table_query)) +		return -EINVAL;  	depth = ntohl(ntq->depth); @@ -904,8 +952,10 @@ static int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, u32 sock)  	hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI,  			  TIPC_NL_PUBL_GET); -	if (!hdr) +	if (!hdr) { +		kfree_skb(args);  		return -EMSGSIZE; +	}  	nest = nla_nest_start(args, TIPC_NLA_SOCK);  	if (!nest) { @@ -1206,7 +1256,7 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)  	}  	len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN); -	if (len && !TLV_OK(msg.req, len)) { +	if (!len || !TLV_OK(msg.req, len)) {  		msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);  		err = -EOPNOTSUPP;  		goto send;  | 
