Make user supplied data checks a bit stricter.

key_msg2sp() is used for parsing data from setsockopt(IP[V6]_IPSEC_POLICY)
call. This socket option is usually used to configure IPsec bypass for
socket. Only privileged user can set this socket option.
The message syntax is described here
	http://www.kame.net/newsletter/20021210/

and our libipsec is usually used to create the correct request.
Add additional checks:
* that sadb_x_ipsecrequest_len is not out of bounds of user supplied buffer
* that src/dst's sa_len is the same
* that 2*sa_len is not out of bounds of user supplied buffer
* that 2*sa_len fits into bounds of sadb_x_ipsecrequest

Reported by:	Ilja van Sprundel
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D11796
This commit is contained in:
Andrey V. Elsukov 2017-08-09 19:58:38 +00:00
parent 16398a1141
commit e54647920b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=322328

View File

@ -1403,7 +1403,8 @@ key_msg2sp(struct sadb_x_policy *xpl0, size_t len, int *error)
while (tlen > 0) {
/* length check */
if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) {
if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr) ||
xisr->sadb_x_ipsecrequest_len > tlen) {
ipseclog((LOG_DEBUG, "%s: invalid ipsecrequest "
"length.\n", __func__));
key_freesp(&newsp);
@ -1517,10 +1518,12 @@ key_msg2sp(struct sadb_x_policy *xpl0, size_t len, int *error)
if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
struct sockaddr *paddr;
len = tlen - sizeof(*xisr);
paddr = (struct sockaddr *)(xisr + 1);
/* validity check */
if (paddr->sa_len
> sizeof(isr->saidx.src)) {
if (len < sizeof(struct sockaddr) ||
len < 2 * paddr->sa_len ||
paddr->sa_len > sizeof(isr->saidx.src)) {
ipseclog((LOG_DEBUG, "%s: invalid "
"request address length.\n",
__func__));
@ -1528,13 +1531,26 @@ key_msg2sp(struct sadb_x_policy *xpl0, size_t len, int *error)
*error = EINVAL;
return NULL;
}
/*
* Request length should be enough to keep
* source and destination addresses.
*/
if (xisr->sadb_x_ipsecrequest_len <
sizeof(*xisr) + 2 * paddr->sa_len) {
ipseclog((LOG_DEBUG, "%s: invalid "
"ipsecrequest length.\n",
__func__));
key_freesp(&newsp);
*error = EINVAL;
return (NULL);
}
bcopy(paddr, &isr->saidx.src, paddr->sa_len);
paddr = (struct sockaddr *)((caddr_t)paddr +
paddr->sa_len);
/* validity check */
if (paddr->sa_len
> sizeof(isr->saidx.dst)) {
if (paddr->sa_len !=
isr->saidx.src.sa.sa_len) {
ipseclog((LOG_DEBUG, "%s: invalid "
"request address length.\n",
__func__));