[v2] debug: Fix fortified realpath C++ ODR violation (BZ 30516)

Message ID 20230703180444.1698963-1-adhemerval.zanella@linaro.org
State New
Headers
Series [v2] debug: Fix fortified realpath C++ ODR violation (BZ 30516) |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
redhat-pt-bot/TryBot-32bit success Build for i686
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 fail Testing failed
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Testing passed
redhat-pt-bot/TryBot-still_applies warning Patch no longer applies to master

Commit Message

Adhemerval Zanella Netto July 3, 2023, 6:04 p.m. UTC
  Although fortify wrappers are built with always_inline attribute,
C++ modules imports a precompiled header module foo.pcm generated from
foo.h which may differ if the translation unit includes or not limit.h.

Although GCC does not fully support C++ modules yet, this is a
problem when using C++ modules with clang.

To avoid lower C diagnostic coverage, a new installed header is added
that adds namespace-clean macro with value similar to current one
(__PATH_MAX).  A test is also added to check if the kernel decides to
change it.

Checked on x86_64-linux-gnu.
---
 bits/stdlib_lim.h                            | 26 ++++++++++
 stdlib/Makefile                              |  1 +
 stdlib/bits/stdlib.h                         |  6 ++-
 sysdeps/unix/sysv/linux/Makefile             | 10 ++++
 sysdeps/unix/sysv/linux/bits/stdlib_lim.h    | 26 ++++++++++
 sysdeps/unix/sysv/linux/tst-limits-consts.py | 54 ++++++++++++++++++++
 6 files changed, 121 insertions(+), 2 deletions(-)
 create mode 100644 bits/stdlib_lim.h
 create mode 100644 sysdeps/unix/sysv/linux/bits/stdlib_lim.h
 create mode 100755 sysdeps/unix/sysv/linux/tst-limits-consts.py
  

Comments

Adhemerval Zanella Netto Aug. 2, 2023, 4:26 p.m. UTC | #1
Ping.

On 03/07/23 15:04, Adhemerval Zanella wrote:
> Although fortify wrappers are built with always_inline attribute,
> C++ modules imports a precompiled header module foo.pcm generated from
> foo.h which may differ if the translation unit includes or not limit.h.
> 
> Although GCC does not fully support C++ modules yet, this is a
> problem when using C++ modules with clang.
> 
> To avoid lower C diagnostic coverage, a new installed header is added
> that adds namespace-clean macro with value similar to current one
> (__PATH_MAX).  A test is also added to check if the kernel decides to
> change it.
> 
> Checked on x86_64-linux-gnu.
> ---
>  bits/stdlib_lim.h                            | 26 ++++++++++
>  stdlib/Makefile                              |  1 +
>  stdlib/bits/stdlib.h                         |  6 ++-
>  sysdeps/unix/sysv/linux/Makefile             | 10 ++++
>  sysdeps/unix/sysv/linux/bits/stdlib_lim.h    | 26 ++++++++++
>  sysdeps/unix/sysv/linux/tst-limits-consts.py | 54 ++++++++++++++++++++
>  6 files changed, 121 insertions(+), 2 deletions(-)
>  create mode 100644 bits/stdlib_lim.h
>  create mode 100644 sysdeps/unix/sysv/linux/bits/stdlib_lim.h
>  create mode 100755 sysdeps/unix/sysv/linux/tst-limits-consts.py
> 
> diff --git a/bits/stdlib_lim.h b/bits/stdlib_lim.h
> new file mode 100644
> index 0000000000..f0295490c0
> --- /dev/null
> +++ b/bits/stdlib_lim.h
> @@ -0,0 +1,26 @@
> +/* Implementation limits related to stdlib.h - generic version.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _BITS_STDLIB_LIM_H
> +#define _BITS_STDLIB_LIM_H 1
> +
> +/* Same as PATH_MAX, but defined in the implementation namespace so it can
> +   be used in places where including limits.h is not possible.  */
> +#undef __PATH_MAX
> +
> +#endif
> diff --git a/stdlib/Makefile b/stdlib/Makefile
> index 0975f55ee6..726a109b67 100644
> --- a/stdlib/Makefile
> +++ b/stdlib/Makefile
> @@ -33,6 +33,7 @@ headers := \
>    bits/stdlib-float.h \
>    bits/stdlib-ldbl.h \
>    bits/stdlib.h \
> +  bits/stdlib_lim.h \
>    bits/time64.h \
>    bits/timesize.h \
>    bits/types/error_t.h \
> diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
> index c6c0082ad5..ed54c24fd4 100644
> --- a/stdlib/bits/stdlib.h
> +++ b/stdlib/bits/stdlib.h
> @@ -20,6 +20,8 @@
>  # error "Never include <bits/stdlib.h> directly; use <stdlib.h> instead."
>  #endif
>  
> +#include <bits/stdlib_lim.h>
> +
>  extern char *__realpath_chk (const char *__restrict __name,
>  			     char *__restrict __resolved,
>  			     size_t __resolvedlen) __THROW __wur;
> @@ -41,8 +43,8 @@ __NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
>    if (sz == (size_t) -1)
>      return __realpath_alias (__name, __resolved);
>  
> -#if defined _LIBC_LIMITS_H_ && defined PATH_MAX
> -  if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
> +#ifdef __PATH_MAX
> +  if (__glibc_unsafe_len (__PATH_MAX, sizeof (char), sz))
>      return __realpath_chk_warn (__name, __resolved, sz);
>  #endif
>    return __realpath_chk (__name, __resolved, sz);
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index 23a84cf225..5fc559568f 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -376,6 +376,16 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py
>  	  < /dev/null > $@ 2>&1; $(evaluate-test)
>  $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps)
>  
> +tests-special += \
> +  $(objpfx)tst-limits-consts.out \
> +  # tests-special
> +$(objpfx)tst-limits-consts.out: ../sysdeps/unix/sysv/linux/tst-limits-consts.py
> +	$(sysdeps-linux-python) \
> +	  ../sysdeps/unix/sysv/linux/tst-limits-consts.py \
> +	    $(sysdeps-linux-python-cc) \
> +	  < /dev/null > $@ 2>&1; $(evaluate-test)
> +$(objpfx)tst-limits-consts.out: $(sysdeps-linux-python-deps)
> +
>  tests-special += \
>    $(objpfx)tst-mount-compile.out \
>    # tests-special
> diff --git a/sysdeps/unix/sysv/linux/bits/stdlib_lim.h b/sysdeps/unix/sysv/linux/bits/stdlib_lim.h
> new file mode 100644
> index 0000000000..935c9836d8
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/bits/stdlib_lim.h
> @@ -0,0 +1,26 @@
> +/* Implementation limits related to stdlib.h - Linux version.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _BITS_STDLIB_LIM_H
> +#define _BITS_STDLIB_LIM_H
> +
> +/* Same as PATH_MAX, but defined in the implementation namespace so it can
> +   be used in places where including limits.h is not possible.  */
> +#define __PATH_MAX	4096
> +
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/tst-limits-consts.py b/sysdeps/unix/sysv/linux/tst-limits-consts.py
> new file mode 100755
> index 0000000000..6abbc6e379
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-limits-consts.py
> @@ -0,0 +1,54 @@
> +#!/usr/bin/python3
> +# Test that glibc's limits.h constants match the kernel's.
> +# Copyright (C) 2022-2023 Free Software Foundation, Inc.
> +# This file is part of the GNU C Library.
> +#
> +# The GNU C Library is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU Lesser General Public
> +# License as published by the Free Software Foundation; either
> +# version 2.1 of the License, or (at your option) any later version.
> +#
> +# The GNU C Library is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +# Lesser General Public License for more details.
> +#
> +# You should have received a copy of the GNU Lesser General Public
> +# License along with the GNU C Library; if not, see
> +# <https://www.gnu.org/licenses/>.
> +
> +import argparse
> +import sys
> +
> +import glibcextract
> +import glibcsyscalls
> +
> +
> +def main():
> +    """The main entry point."""
> +    parser = argparse.ArgumentParser(
> +        description="Test that glibc's limits.h constants "
> +        "match the kernel's.")
> +    parser.add_argument('--cc', metavar='CC',
> +                        help='C compiler (including options) to use')
> +    args = parser.parse_args()
> +
> +    def check_single(kcte, cte):
> +        macros_1 = glibcextract.compute_macro_consts(
> +                '#include <linux/limits.h>\n',
> +                args.cc,
> +                kcte)
> +        macros_2 = glibcextract.compute_macro_consts(
> +                '#include <bits/stdlib_lim.h>\n',
> +                args.cc,
> +                cte)
> +        ret = 1
> +        for (k1, v1), (k2, v2) in zip(macros_1.items(), macros_2.items()):
> +            if v1 == v2:
> +                ret = 0
> +        return ret
> +
> +    sys.exit(check_single('PATH_MAX', '__PATH_MAX'))
> +
> +if __name__ == '__main__':
> +    main()
  

Patch

diff --git a/bits/stdlib_lim.h b/bits/stdlib_lim.h
new file mode 100644
index 0000000000..f0295490c0
--- /dev/null
+++ b/bits/stdlib_lim.h
@@ -0,0 +1,26 @@ 
+/* Implementation limits related to stdlib.h - generic version.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_STDLIB_LIM_H
+#define _BITS_STDLIB_LIM_H 1
+
+/* Same as PATH_MAX, but defined in the implementation namespace so it can
+   be used in places where including limits.h is not possible.  */
+#undef __PATH_MAX
+
+#endif
diff --git a/stdlib/Makefile b/stdlib/Makefile
index 0975f55ee6..726a109b67 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -33,6 +33,7 @@  headers := \
   bits/stdlib-float.h \
   bits/stdlib-ldbl.h \
   bits/stdlib.h \
+  bits/stdlib_lim.h \
   bits/time64.h \
   bits/timesize.h \
   bits/types/error_t.h \
diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
index c6c0082ad5..ed54c24fd4 100644
--- a/stdlib/bits/stdlib.h
+++ b/stdlib/bits/stdlib.h
@@ -20,6 +20,8 @@ 
 # error "Never include <bits/stdlib.h> directly; use <stdlib.h> instead."
 #endif
 
+#include <bits/stdlib_lim.h>
+
 extern char *__realpath_chk (const char *__restrict __name,
 			     char *__restrict __resolved,
 			     size_t __resolvedlen) __THROW __wur;
@@ -41,8 +43,8 @@  __NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
   if (sz == (size_t) -1)
     return __realpath_alias (__name, __resolved);
 
-#if defined _LIBC_LIMITS_H_ && defined PATH_MAX
-  if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
+#ifdef __PATH_MAX
+  if (__glibc_unsafe_len (__PATH_MAX, sizeof (char), sz))
     return __realpath_chk_warn (__name, __resolved, sz);
 #endif
   return __realpath_chk (__name, __resolved, sz);
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 23a84cf225..5fc559568f 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -376,6 +376,16 @@  $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py
 	  < /dev/null > $@ 2>&1; $(evaluate-test)
 $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps)
 
+tests-special += \
+  $(objpfx)tst-limits-consts.out \
+  # tests-special
+$(objpfx)tst-limits-consts.out: ../sysdeps/unix/sysv/linux/tst-limits-consts.py
+	$(sysdeps-linux-python) \
+	  ../sysdeps/unix/sysv/linux/tst-limits-consts.py \
+	    $(sysdeps-linux-python-cc) \
+	  < /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-limits-consts.out: $(sysdeps-linux-python-deps)
+
 tests-special += \
   $(objpfx)tst-mount-compile.out \
   # tests-special
diff --git a/sysdeps/unix/sysv/linux/bits/stdlib_lim.h b/sysdeps/unix/sysv/linux/bits/stdlib_lim.h
new file mode 100644
index 0000000000..935c9836d8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bits/stdlib_lim.h
@@ -0,0 +1,26 @@ 
+/* Implementation limits related to stdlib.h - Linux version.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_STDLIB_LIM_H
+#define _BITS_STDLIB_LIM_H
+
+/* Same as PATH_MAX, but defined in the implementation namespace so it can
+   be used in places where including limits.h is not possible.  */
+#define __PATH_MAX	4096
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/tst-limits-consts.py b/sysdeps/unix/sysv/linux/tst-limits-consts.py
new file mode 100755
index 0000000000..6abbc6e379
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-limits-consts.py
@@ -0,0 +1,54 @@ 
+#!/usr/bin/python3
+# Test that glibc's limits.h constants match the kernel's.
+# Copyright (C) 2022-2023 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+import glibcsyscalls
+
+
+def main():
+    """The main entry point."""
+    parser = argparse.ArgumentParser(
+        description="Test that glibc's limits.h constants "
+        "match the kernel's.")
+    parser.add_argument('--cc', metavar='CC',
+                        help='C compiler (including options) to use')
+    args = parser.parse_args()
+
+    def check_single(kcte, cte):
+        macros_1 = glibcextract.compute_macro_consts(
+                '#include <linux/limits.h>\n',
+                args.cc,
+                kcte)
+        macros_2 = glibcextract.compute_macro_consts(
+                '#include <bits/stdlib_lim.h>\n',
+                args.cc,
+                cte)
+        ret = 1
+        for (k1, v1), (k2, v2) in zip(macros_1.items(), macros_2.items()):
+            if v1 == v2:
+                ret = 0
+        return ret
+
+    sys.exit(check_single('PATH_MAX', '__PATH_MAX'))
+
+if __name__ == '__main__':
+    main()