Skip to content

Fix undefined behaviour in GENERATE_SEED() #10942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

nielsdos
Copy link
Member

Signed multiply overflow is undefined behaviour.
If you run the CI tests with UBSAN enabled on a 32-bit platform, this is quite easy to hit. On 64-bit it's more difficult to hit though, but not impossible.

Signed multiply overflow is undefined behaviour.
If you run the CI tests with UBSAN enabled on a 32-bit platform, this is
quite easy to hit. On 64-bit it's more difficult to hit though, but not
impossible.
@TimWolla
Copy link
Member

The change looks correct to me, but where are you still hitting GENERATE_SEED()? I believe everything should attempt to use the CSPRNG first and the CSPRNG is effectively infallible on modern systems.

@nielsdos
Copy link
Member Author

In gmp_init_random() there's a GENERATE_SEED():

php-src/ext/gmp/gmp.c

Lines 1717 to 1727 in 93e0f6b

static void gmp_init_random(void)
{
if (!GMPG(rand_initialized)) {
/* Initialize */
gmp_randinit_mt(GMPG(rand_state));
/* Seed */
gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
GMPG(rand_initialized) = 1;
}
}

Copy link
Member

@TimWolla TimWolla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Be careful with the merge to PHP 8.2, as all the random stuff moved into the random extension.

#else
#define GENERATE_SEED() (((zend_long) (time(0) * getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg())))
#define GENERATE_SEED() (((zend_long) ((zend_ulong) time(0) * (zend_ulong) getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg())))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also:

Suggested change
#define GENERATE_SEED() (((zend_long) ((zend_ulong) time(0) * (zend_ulong) getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg())))
#define GENERATE_SEED() (((zend_long) ((zend_ulong) time(NULL) * (zend_ulong) getpid())) ^ ((zend_long) (1000000.0 * php_combined_lcg())))

while you're at it?

@@ -61,9 +61,9 @@
(__n) = (__min) + (zend_long) ((double) ( (double) (__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))

#ifdef PHP_WIN32
#define GENERATE_SEED() (((zend_long) (time(0) * GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg())))
#define GENERATE_SEED() (((zend_long) ((zend_ulong) time(0) * (zend_ulong) GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg())))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#define GENERATE_SEED() (((zend_long) ((zend_ulong) time(0) * (zend_ulong) GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg())))
#define GENERATE_SEED() (((zend_long) ((zend_ulong) time(NULL) * (zend_ulong) GetCurrentProcessId())) ^ ((zend_long) (1000000.0 * php_combined_lcg())))

@nielsdos
Copy link
Member Author

Thanks for the review. Noted, I'll look at what moved and I'll apply your suggestion in the merge. I'll wait first until CI is green.

@TimWolla
Copy link
Member

In gmp_init_random() there's a GENERATE_SEED():

Okay, then this should likely be augmented with something like php_random_bytes_silent(&seed, sizeof(unsigned long)) == FAILURE to only use GENERATE_SEED() if the CSPRNG fails. A similar pattern is already in use in other locations. Are you interested in creating such a follow-up (likely master-only)?

The manual will also need a warning that the GMP RNG is not cryptographically secure.

@nielsdos
Copy link
Member Author

Okay, then this should likely be augmented with something like php_random_bytes_silent(&seed, sizeof(unsigned long)) == FAILURE to only use GENERATE_SEED() if the CSPRNG fails. A similar pattern is already in use in other locations. Are you interested in creating such a follow-up (likely master-only)?

Sure I'll take a look after this gets merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants