diff options
| author | Chenguang Zhao <zhaochenguang@kylinos.cn> | 2026-06-03 09:13:53 +0800 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-06-05 19:05:06 -0700 |
| commit | 9772589b57e44aedc240211c5c3f7a684a034d3a (patch) | |
| tree | c9dc6992140681df03a277d7955f44dacb77036a | |
| parent | 3847d94783c0b893c27ff0b26a3325796d9444c6 (diff) | |
| download | linux-stable-9772589b57e44aedc240211c5c3f7a684a034d3a.tar.gz linux-stable-9772589b57e44aedc240211c5c3f7a684a034d3a.zip | |
netlabel: validate unlabeled address and mask attribute lengths
netlbl_unlabel_addrinfo_get() used the address attribute length to
determine whether the attribute data could be read as an IPv4 or IPv6
address, but did not independently validate the corresponding mask
attribute length. A crafted Generic Netlink request could therefore
provide a valid IPv4/IPv6 address attribute with a shorter mask
attribute, which would later be read as a full struct in_addr or
struct in6_addr.
NLA_BINARY policy lengths are maximum lengths by default, so use
NLA_POLICY_EXACT_LEN() for the unlabeled IPv4/IPv6 address and mask
attributes. This rejects short attributes during policy validation and
also exposes the exact length requirements through policy introspection.
Fixes: 8cc44579d1bd ("NetLabel: Introduce static network labels for unlabeled connections")
Signed-off-by: Chenguang Zhao <zhaochenguang@kylinos.cn>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | net/netlabel/netlabel_unlabeled.c | 30 |
1 files changed, 10 insertions, 20 deletions
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index ca7a9e2a3de7..870e7699326a 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -114,14 +114,14 @@ static struct genl_family netlbl_unlabel_gnl_family; /* NetLabel Netlink attribute policy */ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, - [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY, - .len = sizeof(struct in_addr) }, - [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY, - .len = sizeof(struct in_addr) }, + [NLBL_UNLABEL_A_IPV6ADDR] = + NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), + [NLBL_UNLABEL_A_IPV6MASK] = + NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)), + [NLBL_UNLABEL_A_IPV4ADDR] = + NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), + [NLBL_UNLABEL_A_IPV4MASK] = + NLA_POLICY_EXACT_LEN(sizeof(struct in_addr)), [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } @@ -757,24 +757,14 @@ static int netlbl_unlabel_addrinfo_get(struct genl_info *info, void **mask, u32 *len) { - u32 addr_len; - if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR] && info->attrs[NLBL_UNLABEL_A_IPV4MASK]) { - addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); - if (addr_len != sizeof(struct in_addr) && - addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK])) - return -EINVAL; - *len = addr_len; + *len = sizeof(struct in_addr); *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]); *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]); return 0; } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) { - addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); - if (addr_len != sizeof(struct in6_addr) && - addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK])) - return -EINVAL; - *len = addr_len; + *len = sizeof(struct in6_addr); *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]); *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]); return 0; |
