Index: patches/nss-arcfour.patch |
=================================================================== |
--- patches/nss-arcfour.patch (revision 0) |
+++ patches/nss-arcfour.patch (revision 0) |
@@ -0,0 +1,303 @@ |
+Index: mozilla/security/nss/lib/freebl/arcfour.c |
+=================================================================== |
+--- mozilla/security/nss/lib/freebl/arcfour.c (revision 181529) |
++++ mozilla/security/nss/lib/freebl/arcfour.c (working copy) |
+@@ -4,8 +4,6 @@ |
+ * License, v. 2.0. If a copy of the MPL was not distributed with this |
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
+ |
+-/* See NOTES ON UMRs, Unititialized Memory Reads, below. */ |
+- |
+ #ifdef FREEBL_NO_DEPEND |
+ #include "stubs.h" |
+ #endif |
+@@ -18,7 +16,7 @@ |
+ |
+ /* Architecture-dependent defines */ |
+ |
+-#if defined(SOLARIS) || defined(HPUX) || defined(i386) || defined(IRIX) || \ |
++#if defined(SOLARIS) || defined(HPUX) || defined(NSS_X86) || \ |
+ defined(_WIN64) |
+ /* Convert the byte-stream to a word-stream */ |
+ #define CONVERT_TO_WORDS |
+@@ -119,7 +117,7 @@ |
+ const unsigned char * unused1, int unused2, |
+ unsigned int unused3, unsigned int unused4) |
+ { |
+- int i; |
++ unsigned int i; |
+ PRUint8 j, tmp; |
+ PRUint8 K[256]; |
+ PRUint8 *L; |
+@@ -127,7 +125,7 @@ |
+ /* verify the key length. */ |
+ PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE); |
+ if (len == 0 || len >= ARCFOUR_STATE_SIZE) { |
+- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
++ PORT_SetError(SEC_ERROR_BAD_KEY); |
+ return SECFailure; |
+ } |
+ if (cx == NULL) { |
+@@ -215,7 +213,7 @@ |
+ unsigned int index; |
+ PORT_Assert(maxOutputLen >= inputLen); |
+ if (maxOutputLen < inputLen) { |
+- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
++ PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
+ return SECFailure; |
+ } |
+ for (index=0; index < inputLen; index++) { |
+@@ -248,7 +246,7 @@ |
+ int index; |
+ PORT_Assert(maxOutputLen >= inputLen); |
+ if (maxOutputLen < inputLen) { |
+- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
++ PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
+ return SECFailure; |
+ } |
+ for (index = inputLen / 8; index-- > 0; input += 8, output += 8) { |
+@@ -349,40 +347,26 @@ |
+ #define LSH << |
+ #endif |
+ |
++#ifdef IS_LITTLE_ENDIAN |
++#define LEFTMOST_BYTE_SHIFT 0 |
++#define NEXT_BYTE_SHIFT(shift) shift + 8 |
++#else |
++#define LEFTMOST_BYTE_SHIFT 8*(WORDSIZE - 1) |
++#define NEXT_BYTE_SHIFT(shift) shift - 8 |
++#endif |
++ |
+ #ifdef CONVERT_TO_WORDS |
+-/* NOTE about UMRs, Uninitialized Memory Reads. |
+- * |
+- * This code reads all input data a WORD at a time, rather than byte at |
+- * a time, and writes all output data a WORD at a time. Shifting and |
+- * masking is used to remove unwanted data and realign bytes when |
+- * needed. The first and last words of output are read, modified, and |
+- * written when needed to preserve any unchanged bytes. This is a huge |
+- * win on machines with high memory latency. |
+- * |
+- * However, when the input and output buffers do not begin and end on WORD |
+- * boundaries, and the WORDS in memory that contain the first and last |
+- * bytes of those buffers contain uninitialized data, then this code will |
+- * read those uninitialized bytes, causing a UMR error to be reported by |
+- * some tools. |
+- * |
+- * These UMRs are NOT a problem, NOT errors, and do NOT need to be "fixed". |
+- * |
+- * All the words read and written contain at least one byte that is |
+- * part of the input data or output data. No words are read or written |
+- * that do not contain data that is part of the buffer. Therefore, |
+- * these UMRs cannot cause page faults or other problems unless the |
+- * buffers have been assigned to improper addresses that would cause |
+- * page faults with or without UMRs. |
+- */ |
+ static SECStatus |
+ rc4_wordconv(RC4Context *cx, unsigned char *output, |
+ unsigned int *outputLen, unsigned int maxOutputLen, |
+ const unsigned char *input, unsigned int inputLen) |
+ { |
+- ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE; |
+- ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE; |
+- register WORD streamWord, mask; |
+- register WORD *pInWord, *pOutWord; |
++ PR_STATIC_ASSERT(sizeof(PRUword) == sizeof(ptrdiff_t)); |
++ unsigned int inOffset = (PRUword)input % WORDSIZE; |
++ unsigned int outOffset = (PRUword)output % WORDSIZE; |
++ register WORD streamWord; |
++ register const WORD *pInWord; |
++ register WORD *pOutWord; |
+ register WORD inWord, nextInWord; |
+ PRUint8 t; |
+ register Stype tmpSi, tmpSj; |
+@@ -390,11 +374,13 @@ |
+ register PRUint8 tmpj = cx->j; |
+ unsigned int byteCount; |
+ unsigned int bufShift, invBufShift; |
+- int i; |
++ unsigned int i; |
++ const unsigned char *finalIn; |
++ unsigned char *finalOut; |
+ |
+ PORT_Assert(maxOutputLen >= inputLen); |
+ if (maxOutputLen < inputLen) { |
+- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
++ PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
+ return SECFailure; |
+ } |
+ if (inputLen < 2*WORDSIZE) { |
+@@ -402,7 +388,8 @@ |
+ return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen); |
+ } |
+ *outputLen = inputLen; |
+- pInWord = (WORD *)(input - inOffset); |
++ pInWord = (const WORD *)(input - inOffset); |
++ pOutWord = (WORD *)(output - outOffset); |
+ if (inOffset < outOffset) { |
+ bufShift = 8*(outOffset - inOffset); |
+ invBufShift = 8*WORDSIZE - bufShift; |
+@@ -419,52 +406,42 @@ |
+ /* least one partial word of input should ALWAYS be loaded. */ |
+ /*****************************************************************/ |
+ if (outOffset) { |
+- /* Generate input and stream words aligned relative to the |
+- * partial output buffer. |
+- */ |
+ byteCount = WORDSIZE - outOffset; |
+- pOutWord = (WORD *)(output - outOffset); |
+- mask = streamWord = 0; |
+-#ifdef IS_LITTLE_ENDIAN |
+- for (i = WORDSIZE - byteCount; i < WORDSIZE; i++) { |
+-#else |
+- for (i = byteCount - 1; i >= 0; --i) { |
+-#endif |
++ for (i = 0; i < byteCount; i++) { |
+ ARCFOUR_NEXT_BYTE(); |
+- streamWord |= (WORD)(cx->S[t]) << 8*i; |
+- mask |= MASK1BYTE << 8*i; |
+- } /* } */ |
+- inWord = *pInWord++; /* UMR? see comments above. */ |
++ output[i] = cx->S[t] ^ input[i]; |
++ } |
++ /* Consumed byteCount bytes of input */ |
++ inputLen -= byteCount; |
++ pInWord++; |
++ |
++ /* move to next word of output */ |
++ pOutWord++; |
++ |
+ /* If buffers are relatively misaligned, shift the bytes in inWord |
+ * to be aligned to the output buffer. |
+ */ |
+- nextInWord = 0; |
+ if (inOffset < outOffset) { |
+- /* Have more bytes than needed, shift remainder into nextInWord */ |
+- nextInWord = inWord LSH 8*(inOffset + byteCount); |
+- inWord = inWord RSH bufShift; |
++ /* The first input word (which may be partial) has more bytes |
++ * than needed. Copy the remainder to inWord. |
++ */ |
++ unsigned int shift = LEFTMOST_BYTE_SHIFT; |
++ inWord = 0; |
++ for (i = 0; i < outOffset - inOffset; i++) { |
++ inWord |= (WORD)input[byteCount + i] << shift; |
++ shift = NEXT_BYTE_SHIFT(shift); |
++ } |
+ } else if (inOffset > outOffset) { |
+- /* Didn't get enough bytes from current input word, load another |
+- * word and then shift remainder into nextInWord. |
++ /* Consumed some bytes in the second input word. Copy the |
++ * remainder to inWord. |
+ */ |
+- nextInWord = *pInWord++; |
+- inWord = (inWord LSH invBufShift) | |
+- (nextInWord RSH bufShift); |
+- nextInWord = nextInWord LSH invBufShift; |
++ inWord = *pInWord++; |
++ inWord = inWord LSH invBufShift; |
++ } else { |
++ inWord = 0; |
+ } |
+- /* Store output of first partial word */ |
+- *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask); |
+- /* UMR? See comments above. */ |
+- |
+- /* Consumed byteCount bytes of input */ |
+- inputLen -= byteCount; |
+- /* move to next word of output */ |
+- pOutWord++; |
+- /* inWord has been consumed, but there may be bytes in nextInWord */ |
+- inWord = nextInWord; |
+ } else { |
+ /* output is word-aligned */ |
+- pOutWord = (WORD *)output; |
+ if (inOffset) { |
+ /* Input is not word-aligned. The first word load of input |
+ * will not produce a full word of input bytes, so one word |
+@@ -474,8 +451,13 @@ |
+ * loop must execute at least once because the input must |
+ * be at least two words. |
+ */ |
+- inWord = *pInWord++; /* UMR? see comments above. */ |
+- inWord = inWord LSH invBufShift; |
++ unsigned int shift = LEFTMOST_BYTE_SHIFT; |
++ inWord = 0; |
++ for (i = 0; i < WORDSIZE - inOffset; i++) { |
++ inWord |= (WORD)input[i] << shift; |
++ shift = NEXT_BYTE_SHIFT(shift); |
++ } |
++ pInWord++; |
+ } else { |
+ /* Input is word-aligned. The first word load of input |
+ * will produce a full word of input bytes, so nothing |
+@@ -510,12 +492,7 @@ |
+ cx->j = tmpj; |
+ return SECSuccess; |
+ } |
+- /* If the amount of remaining input is greater than the amount |
+- * bytes pulled from the current input word, need to do another |
+- * word load. What's left in inWord will be consumed in step 3. |
+- */ |
+- if (inputLen > WORDSIZE - inOffset) |
+- inWord |= *pInWord RSH bufShift; /* UMR? See above. */ |
++ finalIn = (const unsigned char *)pInWord - WORDSIZE + inOffset; |
+ } else { |
+ for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) { |
+ inWord = *pInWord++; |
+@@ -527,31 +504,18 @@ |
+ cx->i = tmpi; |
+ cx->j = tmpj; |
+ return SECSuccess; |
+- } else { |
+- /* A partial input word remains at the tail. Load it. |
+- * The relevant bytes will be consumed in step 3. |
+- */ |
+- inWord = *pInWord; /* UMR? See comments above */ |
+ } |
++ finalIn = (const unsigned char *)pInWord; |
+ } |
+ /*****************************************************************/ |
+ /* Step 3: */ |
+- /* A partial word of input remains, and it is already loaded */ |
+- /* into nextInWord. Shift appropriately and consume the bytes */ |
+- /* used in the partial word. */ |
++ /* Do the remaining partial word of input one byte at a time. */ |
+ /*****************************************************************/ |
+- mask = streamWord = 0; |
+-#ifdef IS_LITTLE_ENDIAN |
+- for (i = 0; i < inputLen; ++i) { |
+-#else |
+- for (i = WORDSIZE - 1; i >= WORDSIZE - inputLen; --i) { |
+-#endif |
++ finalOut = (unsigned char *)pOutWord; |
++ for (i = 0; i < inputLen; i++) { |
+ ARCFOUR_NEXT_BYTE(); |
+- streamWord |= (WORD)(cx->S[t]) << 8*i; |
+- mask |= MASK1BYTE << 8*i; |
+- } /* } */ |
+- /* UMR? See comments above. */ |
+- *pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask); |
++ finalOut[i] = cx->S[t] ^ finalIn[i]; |
++ } |
+ cx->i = tmpi; |
+ cx->j = tmpj; |
+ return SECSuccess; |
+@@ -566,7 +530,7 @@ |
+ { |
+ PORT_Assert(maxOutputLen >= inputLen); |
+ if (maxOutputLen < inputLen) { |
+- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
++ PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
+ return SECFailure; |
+ } |
+ #if defined(NSS_BEVAND_ARCFOUR) |
+@@ -588,7 +552,7 @@ |
+ { |
+ PORT_Assert(maxOutputLen >= inputLen); |
+ if (maxOutputLen < inputLen) { |
+- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
++ PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
+ return SECFailure; |
+ } |
+ /* decrypt and encrypt are same operation. */ |