]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netlabel: validate unlabeled address and mask attribute lengths
authorChenguang Zhao <zhaochenguang@kylinos.cn>
Wed, 3 Jun 2026 01:13:53 +0000 (09:13 +0800)
committerJakub Kicinski <kuba@kernel.org>
Sat, 6 Jun 2026 02:05:06 +0000 (19:05 -0700)
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>
net/netlabel/netlabel_unlabeled.c

index ca7a9e2a3de7813aea30924a61cb5d4433e369a7..870e7699326a4a3917724adb63212a055b75cbfc 100644 (file)
@@ -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;