Skip to content

Fix integer overflow UB in timelib #17060

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 3 commits into from
Closed

Conversation

nielsdos
Copy link
Member

@nielsdos nielsdos commented Dec 5, 2024

There are edge cases where computations can cause an integer overflow, which is undefined behaviour. Lately, some fuzzers seem to be hitting these quite frequently. While this behaviour is undefined, it doesn't actually matter in practice, the worst effect is having a wrong computation result, but no sane person would do computations on e.g. the year pow(2,63).

Still, undefined behaviour is bad.
Make the wrapping behaviour defined by using -fwrapv when possible. The scope of this is limited to timelib and doesn't affect php_date.c.

The reason for this is that this may in theory prevent some optimizations and it also seems bad to affect code that lives so close to the PHP-native edge.

I tested all issues.
This fixes all but 2 issues, the remaining 2 issues are in php_date.c.

Fixes GH-13881.
Fixes GH-14075.
Fixes GH-15150.
Fixes GH-16034.
Fixes GH-16035.
Fixes GH-16048.
Fixes GH-16050.
Fixes GH-16051.
Fixes GH-16052.
Fixes GH-16775.
Fixes GH-16864.
Fixes GH-16865.
Fixes GH-16975.
Fixes GH-17025.
Fixes GH-17059.

cc @derickr @iluuu1994 @Girgias @petk

There are edge cases where computations can cause an integer overflow,
which is undefined behaviour. Lately, some fuzzers seem to be hitting
these quite frequently. While this behaviour is undefined, it doesn't
actually matter in practice, the worst effect is having a wrong
computation result, but no sane person would do computations on e.g. the
year pow(2,63).

Still, undefined behaviour is bad.
Make the wrapping behaviour defined by using -fwrapv when possible.
The scope of this is limited to timelib and doesn't affect php_date.c.

The reason for this is that this may in theory prevent some
optimizations and it also seems bad to affect code that lives so close
to the PHP-native edge.

I tested all issues.
This fixes all but 2 issues, the remaining 2 issues are in php_date.c.

Fixes phpGH-13881.
Fixes phpGH-14075.
Fixes phpGH-15150.
Fixes phpGH-16034.
Fixes phpGH-16035.
Fixes phpGH-16048.
Fixes phpGH-16050.
Fixes phpGH-16051.
Fixes phpGH-16052.
Fixes phpGH-16775.
Fixes phpGH-16864.
Fixes phpGH-16865.
Fixes phpGH-16975.
Fixes phpGH-17025.
Fixes phpGH-17059.
@nielsdos nielsdos requested a review from derickr as a code owner December 5, 2024 21:54
@nielsdos nielsdos changed the title Fix integer overflows in timelib Fix integer overflow UB in timelib Dec 5, 2024
Copy link
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

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

I don't know about the build system changes, but adding this compiler flags makes sense to me.

@iluuu1994
Copy link
Member

Waiting for somebody else to verify the autoconf part, but adding -fwrapv in general makes sense to me. Unfortunately it's not supported by MSVC, but at least we can avoid undefined behavior with GCC and Clang. The performance impact should be negligible.

@cmb69
Copy link
Member

cmb69 commented Dec 6, 2024

Thank you very much! A great pragmatic solution. Maybe add

 ext/date/config.w32 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ext/date/config.w32 b/ext/date/config.w32
index b053e27aae..3dad8d438c 100644
--- a/ext/date/config.w32
+++ b/ext/date/config.w32
@@ -5,6 +5,9 @@ PHP_DATE = "yes";
 ADD_SOURCES("ext/date/lib", "astro.c timelib.c dow.c parse_date.c parse_posix.c parse_tz.c tm2unixtime.c unixtime2tm.c parse_iso_intervals.c interval.c", "date");
 
 ADD_FLAG('CFLAGS_DATE', "/wd4244");
+if (CLANG_TOOLSET) {
+    ADD_FLAG('CFLAGS_BD_EXT_DATE_LIB', "-fwrapv");
+}
 
 var tl_config = FSO.CreateTextFile("ext/date/lib/timelib_config.h", true);
 tl_config.WriteLine("#include \"config.w32.h\"");

just in case someone fuzzes on Windows with Clang (MSVC doesn't support UBSan anyway). This is a hack, though, since ADD_SOURCES doesn't support the special-flags argument, but should do for now.

Copy link
Member

@derickr derickr left a comment

Choose a reason for hiding this comment

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

Looks good to me. Out of interest, which are the two php_date.c ones still failing?

PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -I@ext_builddir@/lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DHAVE_TIMELIB_CONFIG_H=1"
PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DHAVE_TIMELIB_CONFIG_H=1"
PHP_TIMELIB_CFLAGS="$PHP_DATE_CFLAGS"
PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -I@ext_builddir@/lib"
Copy link
Member

Choose a reason for hiding this comment

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

I'm sure this is fine, but of course -DZEND_ENABLE_STATIC_TSRMC_CACHE=1 is meaningless in the PHP_TIMELIB_CFLAGS definition?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes you are right, I'll move that one too.
Furthermore, I'll apply cmb's suggestion of applying fwrapv to Clang on Windows too.

@nielsdos
Copy link
Member Author

nielsdos commented Dec 6, 2024

Looks good to me. Out of interest, which are the two php_date.c ones still failing?

Oops, I can't count apparently!

It's only one: #14709 but it has an open PR: #14710 and the PR looks simple enough

nielsdos and others added 2 commits December 6, 2024 17:41
Co-authored-by: "Christoph M. Becker" <cmbecker69@gmx.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment