auths/spa: fix for CVE-2020-12783 This is a combined patch of git commits: 57aa14b216432be381b6295c312065b2fd034f86 a04174dc2a84ae1008c23b6a7109e7fa3fb7b8b0 leaving out whitespace noise for a smaller patch and made it apply to the 4.93 release modified paths because Exim dists differ in layout from the git repo Fix SPA authenticator, checking client-supplied data before using it. Bug 2571 Rework SPA fix to avoid overflows. Bug 2571 --- a/src/auths/auth-spa.c +++ b/src/auths/auth-spa.c @@ -405,7 +405,7 @@ int /* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */ { int len = 0; - register uschar digit1, digit2, digit3, digit4; + uschar digit1, digit2, digit3, digit4; if (in[0] == '+' && in[1] == ' ') in += 2; --- a/src/auths/spa.c +++ b/src/auths/spa.c @@ -139,7 +139,8 @@ SPAAuthChallenge challenge; SPAAuthResponse response; SPAAuthResponse *responseptr = &response; uschar msgbuf[2048]; -uschar *clearpass; +uschar *clearpass, *s; +unsigned off; /* send a 334, MS Exchange style, and grab the client's request, unless we already have it via an initial response. */ @@ -194,9 +195,19 @@ that causes failure if the size of msgbuf is exceeded. ****/ { int i; - char *p = ((char*)responseptr) + IVAL(&responseptr->uUser.offset,0); + char * p; int len = SVAL(&responseptr->uUser.len,0)/2; + if ( (off = IVAL(&responseptr->uUser.offset,0)) >= sizeof(SPAAuthResponse) + || len >= sizeof(responseptr->buffer)/2 + || (p = (CS responseptr) + off) + len*2 >= CS (responseptr+1) + ) + { + DEBUG(D_auth) + debug_printf("auth_spa_server(): bad uUser spec in response\n"); + return FAIL; + } + if (len + 1 >= sizeof(msgbuf)) return FAIL; for (i = 0; i < len; ++i) { @@ -245,12 +256,16 @@ spa_smb_nt_encrypt(clearpass, challenge.challengeData, ntRespData); /* compare NT hash (LM may not be available) */ -if (memcmp(ntRespData, - ((unsigned char*)responseptr)+IVAL(&responseptr->ntResponse.offset,0), - 24) == 0) - /* success. we have a winner. */ - { +off = IVAL(&responseptr->ntResponse.offset,0); +if (off >= sizeof(SPAAuthResponse) - 24) + { + DEBUG(D_auth) + debug_printf("auth_spa_server(): bad ntRespData spec in response\n"); + return FAIL; + } +s = (US responseptr) + off; + +if (memcmp(ntRespData, s, 24) == 0) return auth_check_serv_cond(ablock); - } /* Expand server_condition as an authorization check (PH) */