Skip to content

Commit eab38df

Browse files
dhowellsgregkh
authored andcommitted
rxrpc: Fix several cases where a padded len isn't checked in ticket decode
commit 5f2f97656ada8d811d3c1bef503ced266fcd53a0 upstream. This fixes CVE-2017-7482. When a kerberos 5 ticket is being decoded so that it can be loaded into an rxrpc-type key, there are several places in which the length of a variable-length field is checked to make sure that it's not going to overrun the available data - but the data is padded to the nearest four-byte boundary and the code doesn't check for this extra. This could lead to the size-remaining variable wrapping and the data pointer going over the end of the buffer. Fix this by making the various variable-length data checks use the padded length. Reported-by: 石磊 <shilei-c@360.cn> Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Marc Dionne <marc.c.dionne@auristor.com> Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 800d745 commit eab38df

1 file changed

Lines changed: 34 additions & 30 deletions

File tree

net/rxrpc/ar-key.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,
215215
unsigned int *_toklen)
216216
{
217217
const __be32 *xdr = *_xdr;
218-
unsigned int toklen = *_toklen, n_parts, loop, tmp;
218+
unsigned int toklen = *_toklen, n_parts, loop, tmp, paddedlen;
219219

220220
/* there must be at least one name, and at least #names+1 length
221221
* words */
@@ -245,16 +245,16 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,
245245
toklen -= 4;
246246
if (tmp <= 0 || tmp > AFSTOKEN_STRING_MAX)
247247
return -EINVAL;
248-
if (tmp > toklen)
248+
paddedlen = (tmp + 3) & ~3;
249+
if (paddedlen > toklen)
249250
return -EINVAL;
250251
princ->name_parts[loop] = kmalloc(tmp + 1, GFP_KERNEL);
251252
if (!princ->name_parts[loop])
252253
return -ENOMEM;
253254
memcpy(princ->name_parts[loop], xdr, tmp);
254255
princ->name_parts[loop][tmp] = 0;
255-
tmp = (tmp + 3) & ~3;
256-
toklen -= tmp;
257-
xdr += tmp >> 2;
256+
toklen -= paddedlen;
257+
xdr += paddedlen >> 2;
258258
}
259259

260260
if (toklen < 4)
@@ -263,16 +263,16 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,
263263
toklen -= 4;
264264
if (tmp <= 0 || tmp > AFSTOKEN_K5_REALM_MAX)
265265
return -EINVAL;
266-
if (tmp > toklen)
266+
paddedlen = (tmp + 3) & ~3;
267+
if (paddedlen > toklen)
267268
return -EINVAL;
268269
princ->realm = kmalloc(tmp + 1, GFP_KERNEL);
269270
if (!princ->realm)
270271
return -ENOMEM;
271272
memcpy(princ->realm, xdr, tmp);
272273
princ->realm[tmp] = 0;
273-
tmp = (tmp + 3) & ~3;
274-
toklen -= tmp;
275-
xdr += tmp >> 2;
274+
toklen -= paddedlen;
275+
xdr += paddedlen >> 2;
276276

277277
_debug("%s/...@%s", princ->name_parts[0], princ->realm);
278278

@@ -291,7 +291,7 @@ static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td,
291291
unsigned int *_toklen)
292292
{
293293
const __be32 *xdr = *_xdr;
294-
unsigned int toklen = *_toklen, len;
294+
unsigned int toklen = *_toklen, len, paddedlen;
295295

296296
/* there must be at least one tag and one length word */
297297
if (toklen <= 8)
@@ -305,15 +305,17 @@ static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td,
305305
toklen -= 8;
306306
if (len > max_data_size)
307307
return -EINVAL;
308+
paddedlen = (len + 3) & ~3;
309+
if (paddedlen > toklen)
310+
return -EINVAL;
308311
td->data_len = len;
309312

310313
if (len > 0) {
311314
td->data = kmemdup(xdr, len, GFP_KERNEL);
312315
if (!td->data)
313316
return -ENOMEM;
314-
len = (len + 3) & ~3;
315-
toklen -= len;
316-
xdr += len >> 2;
317+
toklen -= paddedlen;
318+
xdr += paddedlen >> 2;
317319
}
318320

319321
_debug("tag %x len %x", td->tag, td->data_len);
@@ -385,7 +387,7 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
385387
const __be32 **_xdr, unsigned int *_toklen)
386388
{
387389
const __be32 *xdr = *_xdr;
388-
unsigned int toklen = *_toklen, len;
390+
unsigned int toklen = *_toklen, len, paddedlen;
389391

390392
/* there must be at least one length word */
391393
if (toklen <= 4)
@@ -397,6 +399,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
397399
toklen -= 4;
398400
if (len > AFSTOKEN_K5_TIX_MAX)
399401
return -EINVAL;
402+
paddedlen = (len + 3) & ~3;
403+
if (paddedlen > toklen)
404+
return -EINVAL;
400405
*_tktlen = len;
401406

402407
_debug("ticket len %u", len);
@@ -405,9 +410,8 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
405410
*_ticket = kmemdup(xdr, len, GFP_KERNEL);
406411
if (!*_ticket)
407412
return -ENOMEM;
408-
len = (len + 3) & ~3;
409-
toklen -= len;
410-
xdr += len >> 2;
413+
toklen -= paddedlen;
414+
xdr += paddedlen >> 2;
411415
}
412416

413417
*_xdr = xdr;
@@ -550,7 +554,7 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
550554
{
551555
const __be32 *xdr = prep->data, *token;
552556
const char *cp;
553-
unsigned int len, tmp, loop, ntoken, toklen, sec_ix;
557+
unsigned int len, paddedlen, loop, ntoken, toklen, sec_ix;
554558
size_t datalen = prep->datalen;
555559
int ret;
556560

@@ -576,22 +580,21 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
576580
if (len < 1 || len > AFSTOKEN_CELL_MAX)
577581
goto not_xdr;
578582
datalen -= 4;
579-
tmp = (len + 3) & ~3;
580-
if (tmp > datalen)
583+
paddedlen = (len + 3) & ~3;
584+
if (paddedlen > datalen)
581585
goto not_xdr;
582586

583587
cp = (const char *) xdr;
584588
for (loop = 0; loop < len; loop++)
585589
if (!isprint(cp[loop]))
586590
goto not_xdr;
587-
if (len < tmp)
588-
for (; loop < tmp; loop++)
589-
if (cp[loop])
590-
goto not_xdr;
591+
for (; loop < paddedlen; loop++)
592+
if (cp[loop])
593+
goto not_xdr;
591594
_debug("cellname: [%u/%u] '%*.*s'",
592-
len, tmp, len, len, (const char *) xdr);
593-
datalen -= tmp;
594-
xdr += tmp >> 2;
595+
len, paddedlen, len, len, (const char *) xdr);
596+
datalen -= paddedlen;
597+
xdr += paddedlen >> 2;
595598

596599
/* get the token count */
597600
if (datalen < 12)
@@ -612,10 +615,11 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
612615
sec_ix = ntohl(*xdr);
613616
datalen -= 4;
614617
_debug("token: [%x/%zx] %x", toklen, datalen, sec_ix);
615-
if (toklen < 20 || toklen > datalen)
618+
paddedlen = (toklen + 3) & ~3;
619+
if (toklen < 20 || toklen > datalen || paddedlen > datalen)
616620
goto not_xdr;
617-
datalen -= (toklen + 3) & ~3;
618-
xdr += (toklen + 3) >> 2;
621+
datalen -= paddedlen;
622+
xdr += paddedlen >> 2;
619623

620624
} while (--loop > 0);
621625

0 commit comments

Comments
 (0)