Uninitialized memory bug found in /mpn/generic/mod_1_1.c

Brett Kuntz kuntz at shaw.ca
Thu Aug 31 15:50:01 CEST 2023


> It does not exist, only pre[0] through pre[3] does. 

pre[4] **IS** pre[0] through pre[3] 

Go to line 248 inside mpn/generic/mod_1.c 

mp_limb_t pre[4]; 

That is NOT initialized. 

The next line: 

mpn_mod_1_1p_cps (pre, b); 

Only initializes pre[0], pre[1], and pre[3]. ***NOT*** pre[2]. 

The final line: 

return mpn_mod_1_1p (ap, n, b, pre); 

Reads from pre[2] erroneously and gives incorrect results if your stack memory has anything other than a 0 there. 

> But if you actually claim that an unedited GMP has a bug here, please 
construct a test case which uses documented interfaces, and which 
demonstrates the claimed bug. 

1) Edit line 248 mpn/generic/mp_limb_t pre[4]; into: 

mp_limb_t pre[4] = { -1, -1, -1, -1 }; 

2) Recompile GMP. 

3) Use the mpn_mod_1() function as described on the following page and you will now get incorrect results: 

https://gmplib.org/manual/Low_002dlevel-Functions 

-Brett Kuntz 




From: "Torbjörn Granlund" <tg at gmplib.org> 
To: "Brett Kuntz" <kuntz at shaw.ca> 
Cc: gmp-bugs at gmplib.org 
Sent: Thursday, August 31, 2023 3:40:47 AM 
Subject: Re: Uninitialized memory bug found in /mpn/generic/mod_1_1.c 

Brett Kuntz <kuntz at shaw.ca> writes: 

Take a look at function mpn_mod_1() in /mpn/generic/ mod_1.c on lines 248 - 250 

mp_limb_t pre[4]; 
mpn_mod_1_1p_cps (pre, b); 

mp_limb_t pre[4] is not initialized 

It does not exist, only pre[0] through pre[3] does. 

and the mpn_mod_1_1p_cps() function 
never writes to pre[2]. So if we change that to mp_limb_t pre[4] = { -1, 
-1, -1, -1 }; as a test we'll quickly see that inside mpn_mod_1_1p_cps() 
the value cps[2] (pre[2]) is never written to and if we print out pre[4] 
after running it we'll get output like: 0x21CFE6CFC938B36BU, 
0x0000000000000000U, 0xFFFFFFFFFFFFFFFFU, 0x9581CA13918612E1U (pre[2] is 
-1) 

/mpn/generic/mod_1_1.c lines 260-266: 

if (LIKELY (cnt != 0)) 
{ 
mp_limb_t B1modb = -b; 
B1modb *= ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt)); 
ASSERT (B1modb <= b); /* NB: not fully reduced mod b */ 
cps[2] = B1modb >> cnt; 
} 

cnt will ALWAYS equal 0 since there will be NO leading 0's when this is 
called since /mpn/generic/mod_1_1.c checks for the high bit being SET 
before calling.. which means this function only ever gets called with NO 
leading zeros!!! 

Why are you so worked up? 

The logic seems perfectly fine. 

ALSO there are unexplained differences between MOD_1_1P_METHOD 1 and 
MOD_1_1P_METHOD 2 when it comes to the function mpn_mod_1_1p_cps(). In 
one of them pre[4] is always set and in the other (method 2) pre[2] is 
skipped! Why are these two functions different? It looks like their job 
is to calculate the inverses for the following mod functions so one 
would expect them to be the same. 

There are lots of "unexplained" things in the GMP internal functions. 
But trust me, the GMP developers understand the sources. 

ALSO the x64 assembly versions of these codes also does not always set 
all 4 values of pre[4] and this has lead to incorrect results when using 
the exported function mpn_mod_1(). 

You hypothesise things here. And you're wrong. 

I benevolent reading of your claims here is that things will be bad if 
you use one variant of the internal _cps function with another variant 
of the corresponding internal mod function. If that's what you're 
trying to say, then you're right. GMP is not edit proof, local user 
edits might break it in all sorts of ways, 

But if you actually claim that an unedited GMP has a bug here, please 
construct a test case which uses documented interfaces, and which 
demonstrates the claimed bug. 

I do not understand these functions enough 

Shouting from the top of your lungs about a bug which is just the result 
of reading the sources, without allowing yourself time to understand the 
logic fully, is somewhat unfair. 

-- 
Torbjörn 
Please encrypt, key id 0xC8601622 


More information about the gmp-bugs mailing list