libradius: Fix input validation bugs

Approved by:	so
Security:	FreeBSD-SA-21:12.libradius
Security:	CVE-2021-29629
MFC after:	now
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Mark Johnston 2021-05-25 13:59:09 -04:00
parent f4c460dacd
commit 8d5c781306

View File

@ -187,7 +187,7 @@ is_valid_response(struct rad_handle *h, int srv,
MD5_CTX ctx; MD5_CTX ctx;
unsigned char md5[MD5_DIGEST_LENGTH]; unsigned char md5[MD5_DIGEST_LENGTH];
const struct rad_server *srvp; const struct rad_server *srvp;
int len; int alen, len;
#ifdef WITH_SSL #ifdef WITH_SSL
HMAC_CTX *hctx; HMAC_CTX *hctx;
u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE]; u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
@ -206,8 +206,8 @@ is_valid_response(struct rad_handle *h, int srv,
/* Check the message length */ /* Check the message length */
if (h->in_len < POS_ATTRS) if (h->in_len < POS_ATTRS)
return 0; return 0;
len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1]; len = (h->in[POS_LENGTH] << 8) | h->in[POS_LENGTH + 1];
if (len > h->in_len) if (len < POS_ATTRS || len > h->in_len)
return 0; return 0;
/* Check the response authenticator */ /* Check the response authenticator */
@ -233,9 +233,16 @@ is_valid_response(struct rad_handle *h, int srv,
/* Search and verify the Message-Authenticator */ /* Search and verify the Message-Authenticator */
hctx = HMAC_CTX_new(); hctx = HMAC_CTX_new();
while (pos < len - 2) { while (pos < len - 2) {
if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) { if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) {
/* zero fill the Message-Authenticator */ if (h->in[pos + 1] != MD5_DIGEST_LENGTH + 2) {
HMAC_CTX_free(hctx);
return 0;
}
if (len - pos < MD5_DIGEST_LENGTH + 2) {
HMAC_CTX_free(hctx);
return 0;
}
memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH); memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH);
HMAC_Init_ex(hctx, srvp->secret, HMAC_Init_ex(hctx, srvp->secret,
@ -255,7 +262,12 @@ is_valid_response(struct rad_handle *h, int srv,
} }
break; break;
} }
pos += h->in[pos + 1]; alen = h->in[pos + 1];
if (alen < 2) {
HMAC_CTX_free(hctx);
return 0;
}
pos += alen;
} }
HMAC_CTX_free(hctx); HMAC_CTX_free(hctx);
} }
@ -272,7 +284,7 @@ is_valid_request(struct rad_handle *h)
MD5_CTX ctx; MD5_CTX ctx;
unsigned char md5[MD5_DIGEST_LENGTH]; unsigned char md5[MD5_DIGEST_LENGTH];
const struct rad_server *srvp; const struct rad_server *srvp;
int len; int alen, len;
#ifdef WITH_SSL #ifdef WITH_SSL
HMAC_CTX *hctx; HMAC_CTX *hctx;
u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE]; u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
@ -285,8 +297,8 @@ is_valid_request(struct rad_handle *h)
/* Check the message length */ /* Check the message length */
if (h->in_len < POS_ATTRS) if (h->in_len < POS_ATTRS)
return (0); return (0);
len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1]; len = (h->in[POS_LENGTH] << 8) | h->in[POS_LENGTH + 1];
if (len > h->in_len) if (len < POS_ATTRS || len > h->in_len)
return (0); return (0);
if (h->in[POS_CODE] != RAD_ACCESS_REQUEST) { if (h->in[POS_CODE] != RAD_ACCESS_REQUEST) {
@ -307,7 +319,18 @@ is_valid_request(struct rad_handle *h)
pos = POS_ATTRS; pos = POS_ATTRS;
hctx = HMAC_CTX_new(); hctx = HMAC_CTX_new();
while (pos < len - 2) { while (pos < len - 2) {
alen = h->in[pos + 1];
if (alen < 2)
return (0);
if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) { if (h->in[pos] == RAD_MESSAGE_AUTHENTIC) {
if (len - pos < MD5_DIGEST_LENGTH + 2) {
HMAC_CTX_free(hctx);
return (0);
}
if (alen < MD5_DIGEST_LENGTH + 2) {
HMAC_CTX_free(hctx);
return (0);
}
memcpy(resp, h->in, MSGSIZE); memcpy(resp, h->in, MSGSIZE);
/* zero fill the Request-Authenticator */ /* zero fill the Request-Authenticator */
if (h->in[POS_CODE] != RAD_ACCESS_REQUEST) if (h->in[POS_CODE] != RAD_ACCESS_REQUEST)
@ -327,7 +350,7 @@ is_valid_request(struct rad_handle *h)
} }
break; break;
} }
pos += h->in[pos + 1]; pos += alen;
} }
HMAC_CTX_free(hctx); HMAC_CTX_free(hctx);
#endif #endif
@ -929,9 +952,9 @@ rad_cvt_string(const void *data, size_t len)
* returns -1. * returns -1.
*/ */
int int
rad_get_attr(struct rad_handle *h, const void **value, size_t *len) rad_get_attr(struct rad_handle *h, const void **value, size_t *lenp)
{ {
int type; int len, type;
if (h->in_pos >= h->in_len) if (h->in_pos >= h->in_len)
return 0; return 0;
@ -940,13 +963,14 @@ rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
return -1; return -1;
} }
type = h->in[h->in_pos++]; type = h->in[h->in_pos++];
*len = h->in[h->in_pos++] - 2; len = h->in[h->in_pos++];
if (h->in_pos + (int)*len > h->in_len) { if (len < 2 || h->in_pos + len > h->in_len) {
generr(h, "Malformed attribute in response"); generr(h, "Malformed attribute in response");
return -1; return -1;
} }
*lenp = len;
*value = &h->in[h->in_pos]; *value = &h->in[h->in_pos];
h->in_pos += *len; h->in_pos += len;
return type; return type;
} }