Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: mozilla/security/nss/lib/freebl/arcfour.c

Issue 12226071: Fix RC4 reads/writes outside array bounds. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Updare comments to reflect new code, remove old comments about UMR Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* arcfour.c - the arc four algorithm. 1 /* arcfour.c - the arc four algorithm.
2 * 2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public 3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 6
7 /* See NOTES ON UMRs, Unititialized Memory Reads, below. */
8
9 #ifdef FREEBL_NO_DEPEND 7 #ifdef FREEBL_NO_DEPEND
10 #include "stubs.h" 8 #include "stubs.h"
11 #endif 9 #endif
12 10
13 #include "prerr.h" 11 #include "prerr.h"
14 #include "secerr.h" 12 #include "secerr.h"
15 13
16 #include "prtypes.h" 14 #include "prtypes.h"
17 #include "blapi.h" 15 #include "blapi.h"
18 16
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 RC4_AllocateContext(void) 110 RC4_AllocateContext(void)
113 { 111 {
114 return PORT_ZNew(RC4Context); 112 return PORT_ZNew(RC4Context);
115 } 113 }
116 114
117 SECStatus 115 SECStatus
118 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len, 116 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len,
119 const unsigned char * unused1, int unused2, 117 const unsigned char * unused1, int unused2,
120 unsigned int unused3, unsigned int unused4) 118 unsigned int unused3, unsigned int unused4)
121 { 119 {
122 » int i; 120 » unsigned int i;
123 PRUint8 j, tmp; 121 PRUint8 j, tmp;
124 PRUint8 K[256]; 122 PRUint8 K[256];
125 PRUint8 *L; 123 PRUint8 *L;
126 124
127 /* verify the key length. */ 125 /* verify the key length. */
128 PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE); 126 PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
129 if (len == 0 || len >= ARCFOUR_STATE_SIZE) { 127 if (len == 0 || len >= ARCFOUR_STATE_SIZE) {
130 PORT_SetError(SEC_ERROR_INVALID_ARGS); 128 PORT_SetError(SEC_ERROR_INVALID_ARGS);
131 return SECFailure; 129 return SECFailure;
132 } 130 }
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 341
344 #ifdef IS_LITTLE_ENDIAN 342 #ifdef IS_LITTLE_ENDIAN
345 #define RSH << 343 #define RSH <<
346 #define LSH >> 344 #define LSH >>
347 #else 345 #else
348 #define RSH >> 346 #define RSH >>
349 #define LSH << 347 #define LSH <<
350 #endif 348 #endif
351 349
352 #ifdef CONVERT_TO_WORDS 350 #ifdef CONVERT_TO_WORDS
353 /* NOTE about UMRs, Uninitialized Memory Reads.
354 *
355 * This code reads all input data a WORD at a time, rather than byte at
356 * a time, and writes all output data a WORD at a time. Shifting and
357 * masking is used to remove unwanted data and realign bytes when
358 * needed. The first and last words of output are read, modified, and
359 * written when needed to preserve any unchanged bytes. This is a huge
360 * win on machines with high memory latency.
361 *
362 * However, when the input and output buffers do not begin and end on WORD
363 * boundaries, and the WORDS in memory that contain the first and last
364 * bytes of those buffers contain uninitialized data, then this code will
365 * read those uninitialized bytes, causing a UMR error to be reported by
366 * some tools.
367 *
368 * These UMRs are NOT a problem, NOT errors, and do NOT need to be "fixed".
369 *
370 * All the words read and written contain at least one byte that is
371 * part of the input data or output data. No words are read or written
372 * that do not contain data that is part of the buffer. Therefore,
373 * these UMRs cannot cause page faults or other problems unless the
374 * buffers have been assigned to improper addresses that would cause
375 * page faults with or without UMRs.
376 */
377 static SECStatus 351 static SECStatus
378 rc4_wordconv(RC4Context *cx, unsigned char *output, 352 rc4_wordconv(RC4Context *cx, unsigned char *output,
379 unsigned int *outputLen, unsigned int maxOutputLen, 353 unsigned int *outputLen, unsigned int maxOutputLen,
380 const unsigned char *input, unsigned int inputLen) 354 const unsigned char *input, unsigned int inputLen)
381 { 355 {
382 ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE; 356 ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE;
383 ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE; 357 ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE;
384 » register WORD streamWord, mask; 358 » register WORD streamWord;
wtc 2013/02/08 17:15:55 |mask| is used to mask off the unwanted bytes in t
385 » register WORD *pInWord, *pOutWord; 359 » const register WORD *pInWord;
wtc 2013/02/08 17:15:55 Here I want to make |pInWord| a const pointer.
360 » register WORD *pOutWord;
386 register WORD inWord, nextInWord; 361 register WORD inWord, nextInWord;
wtc 2013/02/08 17:46:43 Visual C++ does not allow me to take the address o
387 PRUint8 t; 362 PRUint8 t;
388 register Stype tmpSi, tmpSj; 363 register Stype tmpSi, tmpSj;
389 register PRUint8 tmpi = cx->i; 364 register PRUint8 tmpi = cx->i;
390 register PRUint8 tmpj = cx->j; 365 register PRUint8 tmpj = cx->j;
391 unsigned int byteCount; 366 unsigned int byteCount;
392 unsigned int bufShift, invBufShift; 367 unsigned int bufShift, invBufShift;
393 int i; 368 int i;
369 const unsigned char *finalIn;
370 unsigned char *finalOut;
394 371
395 PORT_Assert(maxOutputLen >= inputLen); 372 PORT_Assert(maxOutputLen >= inputLen);
396 if (maxOutputLen < inputLen) { 373 if (maxOutputLen < inputLen) {
397 PORT_SetError(SEC_ERROR_INVALID_ARGS); 374 PORT_SetError(SEC_ERROR_INVALID_ARGS);
398 return SECFailure; 375 return SECFailure;
399 } 376 }
400 if (inputLen < 2*WORDSIZE) { 377 if (inputLen < 2*WORDSIZE) {
401 /* Ignore word conversion, do byte-at-a-time */ 378 /* Ignore word conversion, do byte-at-a-time */
402 return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, in putLen); 379 return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, in putLen);
403 } 380 }
404 *outputLen = inputLen; 381 *outputLen = inputLen;
405 » pInWord = (WORD *)(input - inOffset); 382 » pInWord = (const WORD *)(input - inOffset);
383 » pOutWord = (WORD *)(output - outOffset);
406 if (inOffset < outOffset) { 384 if (inOffset < outOffset) {
407 bufShift = 8*(outOffset - inOffset); 385 bufShift = 8*(outOffset - inOffset);
408 invBufShift = 8*WORDSIZE - bufShift; 386 invBufShift = 8*WORDSIZE - bufShift;
409 } else { 387 } else {
410 invBufShift = 8*(inOffset - outOffset); 388 invBufShift = 8*(inOffset - outOffset);
411 bufShift = 8*WORDSIZE - invBufShift; 389 bufShift = 8*WORDSIZE - invBufShift;
412 } 390 }
413 /*****************************************************************/ 391 /*****************************************************************/
414 /* Step 1: */ 392 /* Step 1: */
wtc 2013/02/08 17:15:55 Step 1 is a complete rewrite. Therefore, do not re
415 /* If the first output word is partial, consume the bytes in the */ 393 /* If the first output word is partial, consume the bytes in the */
416 /* first partial output word by loading one or two words of */ 394 /* first partial output word by loading one or two words of */
417 /* input and shifting them accordingly. Otherwise, just load */ 395 /* input and shifting them accordingly. Otherwise, just load */
418 /* in the first word of input. At the end of this block, at */ 396 /* in the first word of input. At the end of this block, at */
419 /* least one partial word of input should ALWAYS be loaded. */ 397 /* least one partial word of input should ALWAYS be loaded. */
420 /*****************************************************************/ 398 /*****************************************************************/
421 if (outOffset) { 399 if (outOffset) {
422 /* Generate input and stream words aligned relative to the
423 * partial output buffer.
424 */
425 byteCount = WORDSIZE - outOffset; 400 byteCount = WORDSIZE - outOffset;
426 » » pOutWord = (WORD *)(output - outOffset); 401 » » for (i = 0; i < byteCount; i++) {
427 » » mask = streamWord = 0;
428 #ifdef IS_LITTLE_ENDIAN
429 » » for (i = WORDSIZE - byteCount; i < WORDSIZE; i++) {
430 #else
431 » » for (i = byteCount - 1; i >= 0; --i) {
432 #endif
433 ARCFOUR_NEXT_BYTE(); 402 ARCFOUR_NEXT_BYTE();
434 » » » streamWord |= (WORD)(cx->S[t]) << 8*i; 403 » » » output[i] = cx->S[t] ^ input[i];
435 » » » mask |= MASK1BYTE << 8*i; 404 » » }
436 » » } /* } */ 405 » » /* Consumed byteCount bytes of input */
437 » » inWord = *pInWord++; /* UMR? see comments above. */ 406 » » inputLen -= byteCount;
407 » » pInWord++;
408
409 » » /* move to next word of output */
410 » » pOutWord++;
411
438 /* If buffers are relatively misaligned, shift the bytes in inWo rd 412 /* If buffers are relatively misaligned, shift the bytes in inWo rd
439 * to be aligned to the output buffer. 413 * to be aligned to the output buffer.
440 */ 414 */
441 nextInWord = 0;
442 if (inOffset < outOffset) { 415 if (inOffset < outOffset) {
443 » » » /* Have more bytes than needed, shift remainder into nex tInWord */ 416 » » » /* The first input word (which may be partial) has more bytes
444 » » » nextInWord = inWord LSH 8*(inOffset + byteCount); 417 » » » * than needed. Copy the remainder to inWord.
445 » » » inWord = inWord RSH bufShift; 418 » » » */
419 » » » inWord = 0;
420 » » » memcpy(&inWord, &input[byteCount], outOffset - inOffset) ;
446 } else if (inOffset > outOffset) { 421 } else if (inOffset > outOffset) {
447 » » » /* Didn't get enough bytes from current input word, load another 422 » » » /* Consumed some bytes in the second input word. Copy t he
448 » » » * word and then shift remainder into nextInWord. 423 » » » * remainder to inWord.
449 */ 424 */
450 » » » nextInWord = *pInWord++; 425 » » » inWord = *pInWord++;
451 » » » inWord = (inWord LSH invBufShift) | 426 » » » inWord = inWord LSH invBufShift;
452 » » » (nextInWord RSH bufShift);
453 » » » nextInWord = nextInWord LSH invBufShift;
454 } 427 }
455 /* Store output of first partial word */
456 *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask) ;
457 /* UMR? See comments above. */
458
459 /* Consumed byteCount bytes of input */
460 inputLen -= byteCount;
461 /* move to next word of output */
462 pOutWord++;
463 /* inWord has been consumed, but there may be bytes in nextInWor d */
464 inWord = nextInWord;
465 } else { 428 } else {
466 /* output is word-aligned */ 429 /* output is word-aligned */
467 pOutWord = (WORD *)output;
468 if (inOffset) { 430 if (inOffset) {
469 /* Input is not word-aligned. The first word load of in put 431 /* Input is not word-aligned. The first word load of in put
470 * will not produce a full word of input bytes, so one w ord 432 * will not produce a full word of input bytes, so one w ord
471 * must be pre-loaded. The main loop below will load in the 433 * must be pre-loaded. The main loop below will load in the
472 * next input word and shift some of its bytes into inWo rd 434 * next input word and shift some of its bytes into inWo rd
473 * in order to create a full input word. Note that the main 435 * in order to create a full input word. Note that the main
474 * loop must execute at least once because the input mus t 436 * loop must execute at least once because the input mus t
475 * be at least two words. 437 * be at least two words.
476 */ 438 */
477 » » » inWord = *pInWord++; /* UMR? see comments above. */ 439 » » » inWord = 0;
478 » » » inWord = inWord LSH invBufShift; 440 » » » memcpy(&inWord, &input[0], WORDSIZE - inOffset);
441 » » » pInWord++;
479 } else { 442 } else {
480 /* Input is word-aligned. The first word load of input 443 /* Input is word-aligned. The first word load of input
481 * will produce a full word of input bytes, so nothing 444 * will produce a full word of input bytes, so nothing
482 * needs to be loaded here. 445 * needs to be loaded here.
483 */ 446 */
484 inWord = 0; 447 inWord = 0;
485 } 448 }
486 } 449 }
487 /* Output buffer is aligned, inOffset is now measured relative to 450 /* Output buffer is aligned, inOffset is now measured relative to
488 * outOffset (and not a word boundary). 451 * outOffset (and not a word boundary).
489 */ 452 */
490 inOffset = (inOffset + WORDSIZE - outOffset) % WORDSIZE; 453 inOffset = (inOffset + WORDSIZE - outOffset) % WORDSIZE;
491 /*****************************************************************/ 454 /*****************************************************************/
492 /* Step 2: main loop */ 455 /* Step 2: main loop */
wtc 2013/02/08 17:15:55 Step 2 is unchanged, except that at the end we nee
493 /* At this point the output buffer is word-aligned. Any unused */ 456 /* At this point the output buffer is word-aligned. Any unused */
494 /* bytes from above will be in inWord (shifted correctly). If */ 457 /* bytes from above will be in inWord (shifted correctly). If */
495 /* the input buffer is unaligned relative to the output buffer, */ 458 /* the input buffer is unaligned relative to the output buffer, */
496 /* shifting has to be done. */ 459 /* shifting has to be done. */
497 /*****************************************************************/ 460 /*****************************************************************/
498 if (inOffset) { 461 if (inOffset) {
499 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { 462 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
500 nextInWord = *pInWord++; 463 nextInWord = *pInWord++;
501 inWord |= nextInWord RSH bufShift; 464 inWord |= nextInWord RSH bufShift;
502 nextInWord = nextInWord LSH invBufShift; 465 nextInWord = nextInWord LSH invBufShift;
503 ARCFOUR_NEXT_WORD(); 466 ARCFOUR_NEXT_WORD();
504 *pOutWord++ = inWord ^ streamWord; 467 *pOutWord++ = inWord ^ streamWord;
505 inWord = nextInWord; 468 inWord = nextInWord;
506 } 469 }
507 if (inputLen == 0) { 470 if (inputLen == 0) {
508 /* Nothing left to do. */ 471 /* Nothing left to do. */
509 cx->i = tmpi; 472 cx->i = tmpi;
510 cx->j = tmpj; 473 cx->j = tmpj;
511 return SECSuccess; 474 return SECSuccess;
512 } 475 }
513 » » /* If the amount of remaining input is greater than the amount 476 » » finalIn = (const unsigned char *)pInWord - WORDSIZE + inOffset;
514 » » * bytes pulled from the current input word, need to do another
515 » » * word load. What's left in inWord will be consumed in step 3.
516 » » */
517 » » if (inputLen > WORDSIZE - inOffset)
518 » » » inWord |= *pInWord RSH bufShift; /* UMR? See above. */
519 } else { 477 } else {
520 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { 478 for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
521 inWord = *pInWord++; 479 inWord = *pInWord++;
522 ARCFOUR_NEXT_WORD(); 480 ARCFOUR_NEXT_WORD();
523 *pOutWord++ = inWord ^ streamWord; 481 *pOutWord++ = inWord ^ streamWord;
524 } 482 }
525 if (inputLen == 0) { 483 if (inputLen == 0) {
526 /* Nothing left to do. */ 484 /* Nothing left to do. */
527 cx->i = tmpi; 485 cx->i = tmpi;
528 cx->j = tmpj; 486 cx->j = tmpj;
529 return SECSuccess; 487 return SECSuccess;
530 } else {
531 /* A partial input word remains at the tail. Load it.
532 * The relevant bytes will be consumed in step 3.
533 */
534 inWord = *pInWord; /* UMR? See comments above */
535 } 488 }
489 finalIn = (const unsigned char *)pInWord;
536 } 490 }
537 /*****************************************************************/ 491 /*****************************************************************/
538 /* Step 3: */ 492 /* Step 3: */
wtc 2013/02/08 17:15:55 Step 3 is a complete rewrite, but is simple.
539 » /* A partial word of input remains, and it is already loaded */ 493 » /* Do the remaining partial word of input one byte at a time. */
540 » /* into nextInWord. Shift appropriately and consume the bytes */
541 » /* used in the partial word. */
542 /*****************************************************************/ 494 /*****************************************************************/
543 » mask = streamWord = 0; 495 » finalOut = (unsigned char *)pOutWord;
544 #ifdef IS_LITTLE_ENDIAN 496 » for (i = 0; i < inputLen; i++) {
545 » for (i = 0; i < inputLen; ++i) {
546 #else
547 » for (i = WORDSIZE - 1; i >= WORDSIZE - inputLen; --i) {
548 #endif
549 ARCFOUR_NEXT_BYTE(); 497 ARCFOUR_NEXT_BYTE();
550 » » streamWord |= (WORD)(cx->S[t]) << 8*i; 498 » » finalout[i] = cx->S[t] ^ finalIn[i];
551 » » mask |= MASK1BYTE << 8*i; 499 » }
552 » } /* } */
553 » /* UMR? See comments above. */
554 » *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
555 cx->i = tmpi; 500 cx->i = tmpi;
556 cx->j = tmpj; 501 cx->j = tmpj;
557 return SECSuccess; 502 return SECSuccess;
558 } 503 }
559 #endif 504 #endif
560 #endif /* NSS_BEVAND_ARCFOUR */ 505 #endif /* NSS_BEVAND_ARCFOUR */
561 506
562 SECStatus 507 SECStatus
563 RC4_Encrypt(RC4Context *cx, unsigned char *output, 508 RC4_Encrypt(RC4Context *cx, unsigned char *output,
564 unsigned int *outputLen, unsigned int maxOutputLen, 509 unsigned int *outputLen, unsigned int maxOutputLen,
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 /* Convert the byte-stream to a word-stream */ 545 /* Convert the byte-stream to a word-stream */
601 return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen ); 546 return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen );
602 #else 547 #else
603 /* Operate on bytes, but unroll the main loop */ 548 /* Operate on bytes, but unroll the main loop */
604 return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen ); 549 return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen );
605 #endif 550 #endif
606 } 551 }
607 552
608 #undef CONVERT_TO_WORDS 553 #undef CONVERT_TO_WORDS
609 #undef USE_WORD 554 #undef USE_WORD
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698