aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2021-05-25 17:59:09 +0000
committerMark Johnston <markj@FreeBSD.org>2021-05-26 20:30:23 +0000
commit8d5c7813061dfa0b187500dfe3aeea7a28181c13 (patch)
tree92a5189c575c4e9afd59a0e72e0a7b6605246b3c
parentf4c460dacdda5c6e1896a0c51d6096c4f3417b32 (diff)
downloadsrc-8d5c7813061dfa0b187500dfe3aeea7a28181c13.tar.gz
src-8d5c7813061dfa0b187500dfe3aeea7a28181c13.zip
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
-rw-r--r--lib/libradius/radlib.c54
1 files changed, 39 insertions, 15 deletions
diff --git a/lib/libradius/radlib.c b/lib/libradius/radlib.c
index e01c486a1ba6..18aee8b53024 100644
--- a/lib/libradius/radlib.c
+++ b/lib/libradius/radlib.c
@@ -187,7 +187,7 @@ is_valid_response(struct rad_handle *h, int srv,
MD5_CTX ctx;
unsigned char md5[MD5_DIGEST_LENGTH];
const struct rad_server *srvp;
- int len;
+ int alen, len;
#ifdef WITH_SSL
HMAC_CTX *hctx;
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 */
if (h->in_len < POS_ATTRS)
return 0;
- len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1];
- if (len > h->in_len)
+ len = (h->in[POS_LENGTH] << 8) | h->in[POS_LENGTH + 1];
+ if (len < POS_ATTRS || len > h->in_len)
return 0;
/* Check the response authenticator */
@@ -233,9 +233,16 @@ is_valid_response(struct rad_handle *h, int srv,
/* Search and verify the Message-Authenticator */
hctx = HMAC_CTX_new();
while (pos < len - 2) {
-
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);
HMAC_Init_ex(hctx, srvp->secret,
@@ -255,7 +262,12 @@ is_valid_response(struct rad_handle *h, int srv,
}
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);
}
@@ -272,7 +284,7 @@ is_valid_request(struct rad_handle *h)
MD5_CTX ctx;
unsigned char md5[MD5_DIGEST_LENGTH];
const struct rad_server *srvp;
- int len;
+ int alen, len;
#ifdef WITH_SSL
HMAC_CTX *hctx;
u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
@@ -285,8 +297,8 @@ is_valid_request(struct rad_handle *h)
/* Check the message length */
if (h->in_len < POS_ATTRS)
return (0);
- len = h->in[POS_LENGTH] << 8 | h->in[POS_LENGTH+1];
- if (len > h->in_len)
+ len = (h->in[POS_LENGTH] << 8) | h->in[POS_LENGTH + 1];
+ if (len < POS_ATTRS || len > h->in_len)
return (0);
if (h->in[POS_CODE] != RAD_ACCESS_REQUEST) {
@@ -307,7 +319,18 @@ is_valid_request(struct rad_handle *h)
pos = POS_ATTRS;
hctx = HMAC_CTX_new();
while (pos < len - 2) {
+ alen = h->in[pos + 1];
+ if (alen < 2)
+ return (0);
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);
/* zero fill the Request-Authenticator */
if (h->in[POS_CODE] != RAD_ACCESS_REQUEST)
@@ -327,7 +350,7 @@ is_valid_request(struct rad_handle *h)
}
break;
}
- pos += h->in[pos + 1];
+ pos += alen;
}
HMAC_CTX_free(hctx);
#endif
@@ -929,9 +952,9 @@ rad_cvt_string(const void *data, size_t len)
* returns -1.
*/
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)
return 0;
@@ -940,13 +963,14 @@ rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
return -1;
}
type = h->in[h->in_pos++];
- *len = h->in[h->in_pos++] - 2;
- if (h->in_pos + (int)*len > h->in_len) {
+ len = h->in[h->in_pos++];
+ if (len < 2 || h->in_pos + len > h->in_len) {
generr(h, "Malformed attribute in response");
return -1;
}
+ *lenp = len;
*value = &h->in[h->in_pos];
- h->in_pos += *len;
+ h->in_pos += len;
return type;
}