xfrm: add extack support to verify_newsa_info

Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
Sabrina Dubroca 2022-09-14 19:04:00 +02:00 коммит произвёл Steffen Klassert
Родитель 50c448bbc1
Коммит 6999aae17a
1 изменённых файлов: 69 добавлений и 21 удалений

Просмотреть файл

@ -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;