Hi,
These tests fail in trunk on my x86_64 build:
crypt_sha256.phpt
crypt_variation1.phpt
The differences are like this:
Expected: <$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5>
Got <$5$saltst$JTS/fkywz8NvjeCGmWDndJPi7ZrRFhQKBLNtQZWE2C3>
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);
I did not investigate this for real - I am merely passing the info that
I readily have. I hope this helps.
Alexander
Hi!
Hi,
These tests fail in trunk on my x86_64 build:
crypt_sha256.phpt
crypt_variation1.phptThe differences are like this:
Expected:<$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5>
Got<$5$saltst$JTS/fkywz8NvjeCGmWDndJPi7ZrRFhQKBLNtQZWE2C3>That is, the salts are truncated. There's a relevant recent change in
crypt.c involving the line:
Yes, we had buffer overflow error there since the buffer salt[] was
PHP_MAX_SALT_LEN+1 but if salt was longer salt[salt_in_len] later wrote
0 into bad place.
But for SHA max salt len should be something like 123, so I wonder how
comes it got truncated in that case.
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Expected:<$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5>
Got<$5$saltst$JTS/fkywz8NvjeCGmWDndJPi7ZrRFhQKBLNtQZWE2C3>
[...]
Yes, we had buffer overflow error there since the buffer salt[] was
PHP_MAX_SALT_LEN+1 but if salt was longer salt[salt_in_len] later wrote
0 into bad place.
Is this buffer overflow still not fixed in 5.4, or does 5.4 also have
the salt truncation bug above? Either way, it sounds like you need to
figure this out and include a fix in 5.4, before 5.4 proper is released.
Ditto for 5.3.7.
But for SHA max salt len should be something like 123, so I wonder how
comes it got truncated in that case.
I trust that you'll figure it out.
Thanks,
Alexander
> Hi,
>
> These tests fail in trunk on my x86_64 build:
>
> crypt_sha256.phpt
> crypt_variation1.phpt
>
> The differences are like this:
>
> Expected:<$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5>
> Got<$5$saltst$JTS/fkywz8NvjeCGmWDndJPi7ZrRFhQKBLNtQZWE2C3>
>
> 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
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.
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
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi Stas, Pierre -
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:
-
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). -
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
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=312952Now that I look at this, I think there are more problems around this
place in the code:
- 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).
Upon a closer look, the NUL termination might not be needed - neither
for the key nor for the salt. Ulrich Drepper's reference implementation
similarly does not NUL-terminate these, and does not appear to rely on
NUL termination in further code. Has the code in PHP somehow deviated
from this convention?
Pierre - what was the reason for your commit?
...Oh, I think I see the problem: __php_stpncpy() is not sufficiently
correct. It starts by calling strlen(src). Maybe fixing it to more
closely match the real thing would be a cleaner fix?
Either way, crypt_sha256.c and crypt_sha512.c need to be made similar in
this respect. Right now, they are not.
- 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.)
This problem appears to be present in Ulrich Drepper's reference
implementation as well.
We also need to check the MD5-crypt code for this.
No alloca() in the code in ext/standard/php_crypt_r.c. Instead, it
assumes that the MD5 implementation itself is able to handle unaligned
inputs, which it is.
Alexander
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=312952Now that I look at this, I think there are more problems around this
place in the code:
- 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).Upon a closer look, the NUL termination might not be needed - neither
for the key nor for the salt. Ulrich Drepper's reference implementation
similarly does not NUL-terminate these, and does not appear to rely on
NUL termination in further code. Has the code in PHP somehow deviated
from this convention?Pierre - what was the reason for your commit?
...Oh, I think I see the problem: __php_stpncpy() is not sufficiently
correct. It starts by calling strlen(src). Maybe fixing it to more
closely match the real thing would be a cleaner fix?
I'm sorry, I misattributed the commit. It was by Ilia, "Fixed bug
relating to un-initialized memory access". So I guess it was about the
strlen()
, unless there's another place accessing beyond salt_len as well.
Alexander
Hi!
Now that I look at this, I think there are more problems around this
place in the code:
I just fixed the immediate problem, but giving a second look to this
code I don't really understand why there should be NULL
termination at
all - we know the length anyway, and can use it directly.
And underlying functions seem never to rely on null-termination.
- alloca() of potentially user-controlled size is unsafe - it may
result in the stack pointer being moved outside of allowable range and
This is true. This code doesn't seem to have any limits on key length.
We probably should add a check somewhere in crypt.c. I'll look into it
soon.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
hi,
it seems that the changes break BC too, pls see
https://bugs.php.net/bug.php?id=55477
Does that ring a bell to you?
Hi,
These tests fail in trunk on my x86_64 build:
crypt_sha256.phpt
crypt_variation1.phptThe differences are like this:
Expected: <$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5>
Got <$5$saltst$JTS/fkywz8NvjeCGmWDndJPi7ZrRFhQKBLNtQZWE2C3>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);
I did not investigate this for real - I am merely passing the info that
I readily have. I hope this helps.Alexander
--
--
Pierre
@pierrejoye | http://blog.thepimp.net | http://www.libgd.org
we expected this imo.
internals@lists.php.net/msg51683.html" rel="nofollow" target="_blank">http://www.mail-archive.com/internals@lists.php.net/msg51683.html
internals@lists.php.net/msg51687.html" rel="nofollow" target="_blank">http://www.mail-archive.com/internals@lists.php.net/msg51687.html
hi,
it seems that the changes break BC too, pls see
https://bugs.php.net/bug.php?id=55477Does that ring a bell to you?
Hi,
These tests fail in trunk on my x86_64 build:
crypt_sha256.phpt
crypt_variation1.phptThe differences are like this:
Expected: <$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5>
Got <$5$saltst$JTS/fkywz8NvjeCGmWDndJPi7ZrRFhQKBLNtQZWE2C3>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);
I did not investigate this for real - I am merely passing the info that
I readily have. I hope this helps.Alexander
--
--
Pierre@pierrejoye | http://blog.thepimp.net | http://www.libgd.org
--
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
we expected this imo.
internals@lists.php.net/msg51683.html" rel="nofollow" target="_blank">http://www.mail-archive.com/internals@lists.php.net/msg51683.html
internals@lists.php.net/msg51687.html" rel="nofollow" target="_blank">http://www.mail-archive.com/internals@lists.php.net/msg51687.html
Definitely.
it seems that the changes break BC too, pls see
https://bugs.php.net/bug.php?id=55477
We may recommend to Christian to change $2a$ in existing hashes to $2x$ if
the goal is to preserve compatibility for all old passwords despite of
the security risk associated with doing so. The change as implemented
in PHP 5.3.7+ favors security and correctness over backwards compatibility,
but it also lets users (admins of PHP app installs) use the new $2x$
prefix on existing hashes to preserve backwards compatibility for those
and incur the associated security risk until all such passwords are
changed (using $2a$ or $2y$ for newly changed passwords).
No change to the PHP code is needed.
BTW, this is not the right thread to discuss this on (the "bug" has
nothing to do with CRYPT_SHA256).
Alexander
we expected this imo.
internals@lists.php.net/msg51683.html" rel="nofollow" target="_blank">http://www.mail-archive.com/internals@lists.php.net/msg51683.html
internals@lists.php.net/msg51687.html" rel="nofollow" target="_blank">http://www.mail-archive.com/internals@lists.php.net/msg51687.htmlDefinitely.
it seems that the changes break BC too, pls see
https://bugs.php.net/bug.php?id=55477We may recommend to Christian to change $2a$ in existing hashes to $2x$ if
the goal is to preserve compatibility for all old passwords despite of
the security risk associated with doing so. The change as implemented
in PHP 5.3.7+ favors security and correctness over backwards compatibility,
but it also lets users (admins of PHP app installs) use the new $2x$
prefix on existing hashes to preserve backwards compatibility for those
and incur the associated security risk until all such passwords are
changed (using $2a$ or $2y$ for newly changed passwords).No change to the PHP code is needed.
Can you add this comment to the bug please? So every user reading it
will be informed. That's also something we have to document better.
BTW, this is not the right thread to discuss this on (the "bug" has
nothing to do with CRYPT_SHA256).
Oops, reply to the wrong one, sorry :)
--
Pierre
@pierrejoye | http://blog.thepimp.net | http://www.libgd.org