Hi Stas, Pierre - On Sun, Jul 31, 2011 at 02:43:12PM -0700, Stas Malyshev wrote: > On 7/19/11 4:44 PM, Solar Designer wrote: > >That is, the salts are truncated. There's a relevant recent change in > >crypt.c involving the line: > > > > salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len); > > Thanks for the report. > This problem seems to be unrelated to this change, but in fact looks > like it's related to this code in
You appear to be correct. > if ((salt - (char *) 0) % __alignof__(uint32_t) != 0) { > char *tmp = (char *) alloca(salt_len + 1 + > __alignof__(uint32_t)); > salt = copied_salt = > memcpy(tmp + __alignof__(uint32_t) - (tmp - (char *) 0) % > __alignof__ (uint32_t), salt, salt_len); > tmp[salt_len] = 0; > } > > As you can see, the last line cuts the string relative to tmp, but salt > is copied to tmp with offest, which leads to salt truncation. Changing > it from tmp to copied_salt seems to fix the problem. I'll apply the fix > in a minute. Right. > The change that introduced this problem is: > http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/standard/crypt_sha256.c?r1=300427&r2=312952 Now that I look at this, I think there are more problems around this place in the code: 1. Pierre's commit that inadvertently introduced the truncation was a bugfix, adding the previously missed NUL termination of the copied salt. However, the similar piece of code copying the key appears to still lack the NUL termination (it works by pure luck). 2. alloca() of potentially user-controlled size is unsafe - it may result in the stack pointer being moved outside of allowable range and onto other areas, such as the heap. With a large enough allocation, it'd jump over the few guard pages there might be. In the worst case, this will ultimately allow for arbitrary machine code execution via an overly long password. (BTW, we need to check glibc for similar issues.) You could move away from using alloca() there or introduce some sane length limits (less than one page). But then you need to decide on the proper action on failure. Another approach would be to avoid the copying, although it may have a performance impact (having to deal with potentially unaligned data inside loops), would involve more invasive changes, and thus would require testing and benchmarking - so probably not an option for the upcoming releases now (and maybe beyond scope of PHP development at all). Oh, there are two more alloca() calls further down the function - one of the salt (not an issue if we limit the salt length above), and one of the key (problematic). This needs to be dealt with as well. So perhaps you need to have the function return NULL right after the first strlen(key) if the length turns out to be excessive (more than 2048 bytes? which is half a page on x86). Then the wrapper code in crypt.c will translate this into "*0". crypt_sha512.c has similar issues - both with NUL termination and with unlimited alloca(). We also need to check the MD5-crypt code for this. I hope this helps... Alexander -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php