Commit 6999aae1 authored by Sabrina Dubroca's avatar Sabrina Dubroca Committed by Steffen Klassert
Browse files

xfrm: add extack support to verify_newsa_info

parent 50c448bb
Loading
Loading
Loading
Loading
+69 −21
Original line number Diff line number Diff line
@@ -149,7 +149,8 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
}

static int verify_newsa_info(struct xfrm_usersa_info *p,
			     struct nlattr **attrs)
			     struct nlattr **attrs,
			     struct netlink_ext_ack *extack)
{
	int err;

@@ -163,10 +164,12 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
		break;
#else
		err = -EAFNOSUPPORT;
		NL_SET_ERR_MSG(extack, "IPv6 support disabled");
		goto out;
#endif

	default:
		NL_SET_ERR_MSG(extack, "Invalid address family");
		goto out;
	}

@@ -175,65 +178,98 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
		break;

	case AF_INET:
		if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32)
		if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32) {
			NL_SET_ERR_MSG(extack, "Invalid prefix length in selector (must be <= 32 for IPv4)");
			goto out;
		}

		break;

	case AF_INET6:
#if IS_ENABLED(CONFIG_IPV6)
		if (p->sel.prefixlen_d > 128 || p->sel.prefixlen_s > 128)
		if (p->sel.prefixlen_d > 128 || p->sel.prefixlen_s > 128) {
			NL_SET_ERR_MSG(extack, "Invalid prefix length in selector (must be <= 128 for IPv6)");
			goto out;
		}

		break;
#else
		NL_SET_ERR_MSG(extack, "IPv6 support disabled");
		err = -EAFNOSUPPORT;
		goto out;
#endif

	default:
		NL_SET_ERR_MSG(extack, "Invalid address family in selector");
		goto out;
	}

	err = -EINVAL;
	switch (p->id.proto) {
	case IPPROTO_AH:
		if ((!attrs[XFRMA_ALG_AUTH]	&&
		     !attrs[XFRMA_ALG_AUTH_TRUNC]) ||
		    attrs[XFRMA_ALG_AEAD]	||
		if (!attrs[XFRMA_ALG_AUTH]	&&
		    !attrs[XFRMA_ALG_AUTH_TRUNC]) {
			NL_SET_ERR_MSG(extack, "Missing required attribute for AH: AUTH_TRUNC or AUTH");
			goto out;
		}

		if (attrs[XFRMA_ALG_AEAD]	||
		    attrs[XFRMA_ALG_CRYPT]	||
		    attrs[XFRMA_ALG_COMP]	||
		    attrs[XFRMA_TFCPAD])
		    attrs[XFRMA_TFCPAD]) {
			NL_SET_ERR_MSG(extack, "Invalid attributes for AH: AEAD, CRYPT, COMP, TFCPAD");
			goto out;
		}
		break;

	case IPPROTO_ESP:
		if (attrs[XFRMA_ALG_COMP])
		if (attrs[XFRMA_ALG_COMP]) {
			NL_SET_ERR_MSG(extack, "Invalid attribute for ESP: COMP");
			goto out;
		}

		if (!attrs[XFRMA_ALG_AUTH] &&
		    !attrs[XFRMA_ALG_AUTH_TRUNC] &&
		    !attrs[XFRMA_ALG_CRYPT] &&
		    !attrs[XFRMA_ALG_AEAD])
		    !attrs[XFRMA_ALG_AEAD]) {
			NL_SET_ERR_MSG(extack, "Missing required attribute for ESP: at least one of AUTH, AUTH_TRUNC, CRYPT, AEAD");
			goto out;
		}

		if ((attrs[XFRMA_ALG_AUTH] ||
		     attrs[XFRMA_ALG_AUTH_TRUNC] ||
		     attrs[XFRMA_ALG_CRYPT]) &&
		    attrs[XFRMA_ALG_AEAD])
		    attrs[XFRMA_ALG_AEAD]) {
			NL_SET_ERR_MSG(extack, "Invalid attribute combination for ESP: AEAD can't be used with AUTH, AUTH_TRUNC, CRYPT");
			goto out;
		}

		if (attrs[XFRMA_TFCPAD] &&
		    p->mode != XFRM_MODE_TUNNEL)
		    p->mode != XFRM_MODE_TUNNEL) {
			NL_SET_ERR_MSG(extack, "TFC padding can only be used in tunnel mode");
			goto out;
		}
		break;

	case IPPROTO_COMP:
		if (!attrs[XFRMA_ALG_COMP]	||
		    attrs[XFRMA_ALG_AEAD]	||
		if (!attrs[XFRMA_ALG_COMP]) {
			NL_SET_ERR_MSG(extack, "Missing required attribute for COMP: COMP");
			goto out;
		}

		if (attrs[XFRMA_ALG_AEAD]	||
		    attrs[XFRMA_ALG_AUTH]	||
		    attrs[XFRMA_ALG_AUTH_TRUNC]	||
		    attrs[XFRMA_ALG_CRYPT]	||
		    attrs[XFRMA_TFCPAD]		||
		    (ntohl(p->id.spi) >= 0x10000))
		    attrs[XFRMA_TFCPAD]) {
			NL_SET_ERR_MSG(extack, "Invalid attributes for COMP: AEAD, AUTH, AUTH_TRUNC, CRYPT, TFCPAD");
			goto out;
		}

		if (ntohl(p->id.spi) >= 0x10000) {
			NL_SET_ERR_MSG(extack, "SPI is too large for COMP (must be < 0x10000)");
			goto out;
		}
		break;

#if IS_ENABLED(CONFIG_IPV6)
@@ -246,13 +282,20 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
		    attrs[XFRMA_ALG_CRYPT]	||
		    attrs[XFRMA_ENCAP]		||
		    attrs[XFRMA_SEC_CTX]	||
		    attrs[XFRMA_TFCPAD]		||
		    !attrs[XFRMA_COADDR])
		    attrs[XFRMA_TFCPAD]) {
			NL_SET_ERR_MSG(extack, "Invalid attributes for DSTOPTS/ROUTING");
			goto out;
		}

		if (!attrs[XFRMA_COADDR]) {
			NL_SET_ERR_MSG(extack, "Missing required COADDR attribute for DSTOPTS/ROUTING");
			goto out;
		}
		break;
#endif

	default:
		NL_SET_ERR_MSG(extack, "Unsupported protocol");
		goto out;
	}

@@ -266,7 +309,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
		goto out;
	if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP)))
		goto out;
	if ((err = verify_sec_ctx_len(attrs, NULL)))
	if ((err = verify_sec_ctx_len(attrs, extack)))
		goto out;
	if ((err = verify_replay(p, attrs)))
		goto out;
@@ -280,14 +323,19 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
		break;

	default:
		NL_SET_ERR_MSG(extack, "Unsupported mode");
		goto out;
	}

	err = 0;

	if (attrs[XFRMA_MTIMER_THRESH])
		if (!attrs[XFRMA_ENCAP])
	if (attrs[XFRMA_MTIMER_THRESH]) {
		if (!attrs[XFRMA_ENCAP]) {
			NL_SET_ERR_MSG(extack, "MTIMER_THRESH attribute can only be set on ENCAP states");
			err = -EINVAL;
			goto out;
		}
	}

out:
	return err;
@@ -688,7 +736,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
	int err;
	struct km_event c;

	err = verify_newsa_info(p, attrs);
	err = verify_newsa_info(p, attrs, extack);
	if (err)
		return err;