Skip to content

Commit

Permalink
Bug 1723674 - Move nsUUIDGenerator logic to new nsID::GenerateUUID() …
Browse files Browse the repository at this point in the history
…factory functions that use nsRandomGenerator. r=keeler

This changeset is an adaptation of the accepted changes (but not landed) for bug 1700675:

https://phabricator.services.mozilla.com/D118714

Also, clean up some old (1998!) JavaDoc comments that just make the code more difficult to read.

Differential Revision: https://phabricator.services.mozilla.com/D124312
  • Loading branch information
cpeterso committed Oct 14, 2021
1 parent 04c791a commit c67e007
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 162 deletions.
63 changes: 62 additions & 1 deletion xpcom/base/nsID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,69 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsID.h"
#include "nsMemory.h"

#include <limits.h>

#include "mozilla/Assertions.h"
#include "mozilla/RandomNum.h"
#include "mozilla/Sprintf.h"
#include "nss.h"
#include "ScopedNSSTypes.h"

[[nodiscard]] static bool GenerateRandomBytesFromNSS(void* aBuffer,
size_t aLength) {
MOZ_ASSERT(aBuffer);

// Bounds check that we can safely truncate size_t `aLength` to an int.
if (aLength == 0 || aLength > INT_MAX) {
MOZ_ASSERT_UNREACHABLE("Bad aLength");
return false;
}
int len = static_cast<int>(aLength);

if (!NSS_IsInitialized()) {
return false;
}

mozilla::UniquePK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
MOZ_ASSERT_UNREACHABLE("Null slot");
return false;
}

SECStatus srv = PK11_GenerateRandomOnSlot(
slot.get(), static_cast<unsigned char*>(aBuffer), len);
MOZ_ASSERT(srv == SECSuccess);
return (srv == SECSuccess);
}

nsresult nsID::GenerateUUIDInPlace(nsID& aId) {
// Firefox needs to generate some UUIDs before NSS has been initialized. We
// prefer NSS's RNG, but if NSS is not available yet or returns an error, fall
// back to MFBT's GenerateRandomBytes().
if (!GenerateRandomBytesFromNSS(&aId, sizeof(nsID)) &&
!mozilla::GenerateRandomBytesFromOS(&aId, sizeof(nsID))) {
MOZ_ASSERT_UNREACHABLE("GenerateRandomBytesFromOS() failed");
return NS_ERROR_NOT_AVAILABLE;
}

// Put in the version
aId.m2 &= 0x0fff;
aId.m2 |= 0x4000;

// Put in the variant
aId.m3[0] &= 0x3f;
aId.m3[0] |= 0x80;

return NS_OK;
}

nsID nsID::GenerateUUID() {
nsID uuid;
nsresult rv = GenerateUUIDInPlace(uuid);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
return uuid;
}

void nsID::Clear() {
m0 = 0;
Expand Down
17 changes: 6 additions & 11 deletions xpcom/base/nsID.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,27 @@
*/

struct nsID {
/**
* @name Identifier values
*/

//@{
uint32_t m0;
uint16_t m1;
uint16_t m2;
uint8_t m3[8];
//@}

/**
* @name Methods
* Create a new random UUID.
* GenerateUUIDInPlace() is fallible, whereas GenerateUUID() will abort in
* the unlikely case that the OS RNG returns an error.
*/
[[nodiscard]] static nsresult GenerateUUIDInPlace(nsID& aId);
static nsID GenerateUUID();

//@{
/**
* Ensures everything is zeroed out.
*/
void Clear();

/**
* Equivalency method. Compares this nsID with another.
* @return <b>true</b> if they are the same, <b>false</b> if not.
* @return true if they are the same, false if not.
*/

inline bool Equals(const nsID& aOther) const {
Expand Down Expand Up @@ -89,8 +86,6 @@ struct nsID {

// Infallibly duplicate an nsID. Must be freed with free().
nsID* Clone() const;

//@}
};

#ifndef XPCOM_GLUE_AVOID_NSPR
Expand Down
135 changes: 1 addition & 134 deletions xpcom/base/nsUUIDGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,12 @@
* 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/. */

#if defined(XP_WIN)
# include "mozilla/mscom/COMWrappers.h"
#elif defined(XP_MACOSX)
# include <CoreFoundation/CoreFoundation.h>
#else
# include <stdlib.h>
# include "prrng.h"
#endif

#include "nsUUIDGenerator.h"

#ifdef ANDROID
extern "C" NS_EXPORT void arc4random_buf(void*, size_t);
#endif

using namespace mozilla;

NS_IMPL_ISUPPORTS(nsUUIDGenerator, nsIUUIDGenerator)

nsUUIDGenerator::nsUUIDGenerator() : mLock("nsUUIDGenerator.mLock") {}

nsUUIDGenerator::~nsUUIDGenerator() = default;

nsresult nsUUIDGenerator::Init() {
// We're a service, so we're guaranteed that Init() is not going
// to be reentered while we're inside Init().

#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(HAVE_ARC4RANDOM)
/* initialize random number generator using NSPR random noise */
unsigned int seed;

size_t bytes = 0;
while (bytes < sizeof(seed)) {
size_t nbytes = PR_GetRandomNoise(((unsigned char*)&seed) + bytes,
sizeof(seed) - bytes);
if (nbytes == 0) {
return NS_ERROR_FAILURE;
}
bytes += nbytes;
}

/* Initialize a new RNG state, and immediately switch
* back to the previous one -- we want to use mState
* only for our own calls to random().
*/
mSavedState = initstate(seed, mState, sizeof(mState));
setstate(mSavedState);

mRBytes = 4;
# ifdef RAND_MAX
if ((unsigned long)RAND_MAX < 0xffffffffUL) {
mRBytes = 3;
}
if ((unsigned long)RAND_MAX < 0x00ffffffUL) {
mRBytes = 2;
}
if ((unsigned long)RAND_MAX < 0x0000ffffUL) {
mRBytes = 1;
}
if ((unsigned long)RAND_MAX < 0x000000ffUL) {
return NS_ERROR_FAILURE;
}
# endif

#endif /* non XP_WIN and non XP_MACOSX and non ARC4RANDOM */

return NS_OK;
}

NS_IMETHODIMP
nsUUIDGenerator::GenerateUUID(nsID** aRet) {
nsID* id = static_cast<nsID*>(moz_xmalloc(sizeof(nsID)));
Expand All @@ -89,75 +26,5 @@ nsUUIDGenerator::GenerateUUID(nsID** aRet) {

NS_IMETHODIMP
nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId) {
// The various code in this method is probably not threadsafe, so lock
// across the whole method.
MutexAutoLock lock(mLock);

#if defined(XP_WIN)
HRESULT hr = mozilla::mscom::wrapped::CoCreateGuid((GUID*)aId);
if (FAILED(hr)) {
return NS_ERROR_FAILURE;
}
#elif defined(XP_MACOSX)
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
if (!uuid) {
return NS_ERROR_FAILURE;
}

CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid);
memcpy(aId, &bytes, sizeof(nsID));

CFRelease(uuid);
#else /* not windows or OS X; generate randomness using random(). */
/* XXX we should be saving the return of setstate here and switching
* back to it; instead, we use the value returned when we called
* initstate, since older glibc's have broken setstate() return values
*/
# ifndef HAVE_ARC4RANDOM
setstate(mState);
# endif

# ifdef HAVE_ARC4RANDOM_BUF
arc4random_buf(aId, sizeof(nsID));
# else /* HAVE_ARC4RANDOM_BUF */
size_t bytesLeft = sizeof(nsID);
while (bytesLeft > 0) {
# ifdef HAVE_ARC4RANDOM
long rval = arc4random();
const size_t mRBytes = 4;
# else
long rval = random();
# endif

uint8_t* src = (uint8_t*)&rval;
// We want to grab the mRBytes least significant bytes of rval, since
// mRBytes less than sizeof(rval) means the high bytes are 0.
# ifdef IS_BIG_ENDIAN
src += sizeof(rval) - mRBytes;
# endif
uint8_t* dst = ((uint8_t*)aId) + (sizeof(nsID) - bytesLeft);
size_t toWrite = (bytesLeft < mRBytes ? bytesLeft : mRBytes);
for (size_t i = 0; i < toWrite; i++) {
dst[i] = src[i];
}

bytesLeft -= toWrite;
}
# endif /* HAVE_ARC4RANDOM_BUF */

/* Put in the version */
aId->m2 &= 0x0fff;
aId->m2 |= 0x4000;

/* Put in the variant */
aId->m3[0] &= 0x3f;
aId->m3[0] |= 0x80;

# ifndef HAVE_ARC4RANDOM
/* Restore the previous RNG state */
setstate(mSavedState);
# endif
#endif

return NS_OK;
return nsID::GenerateUUIDInPlace(*aId);
}
15 changes: 0 additions & 15 deletions xpcom/base/nsUUIDGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,16 @@
#ifndef _NSUUIDGENERATOR_H_
#define _NSUUIDGENERATOR_H_

#include "mozilla/Attributes.h"
#include "mozilla/Mutex.h"

#include "nsIUUIDGenerator.h"

class nsUUIDGenerator final : public nsIUUIDGenerator {
public:
nsUUIDGenerator();

NS_DECL_THREADSAFE_ISUPPORTS

NS_DECL_NSIUUIDGENERATOR

nsresult Init();

private:
~nsUUIDGenerator();

protected:
mozilla::Mutex mLock;
#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(HAVE_ARC4RANDOM)
char mState[128];
char* mSavedState;
uint8_t mRBytes;
#endif
};

#define NS_UUID_GENERATOR_CONTRACTID "@mozilla.org/uuid-generator;1"
Expand Down
1 change: 0 additions & 1 deletion xpcom/build/components.conf
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ Classes = [
'interfaces': ['nsIUUIDGenerator'],
'type': 'nsUUIDGenerator',
'headers': ['/xpcom/base/nsUUIDGenerator.h'],
'init_method': 'Init',
'processes': ProcessSelector.ALLOW_IN_SOCKET_PROCESS,
},
{
Expand Down

0 comments on commit c67e007

Please sign in to comment.