forked from rpms/glibc
import glibc-2.28-225.el8
This commit is contained in:
parent
3994a3375d
commit
7db8dcfedc
2024
SOURCES/glibc-rh1159809-1.patch
Normal file
2024
SOURCES/glibc-rh1159809-1.patch
Normal file
File diff suppressed because one or more lines are too long
79
SOURCES/glibc-rh1159809-10.patch
Normal file
79
SOURCES/glibc-rh1159809-10.patch
Normal file
@ -0,0 +1,79 @@
|
||||
commit dbb75513f5cf9285c77c9e55777c5c35b653f890
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Sep 6 07:38:10 2022 +0200
|
||||
|
||||
elf: Rename _dl_sort_maps parameter from skip to force_first
|
||||
|
||||
The new implementation will not be able to skip an arbitrary number
|
||||
of objects.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index 99354dc08a010dd3..7a586749adc3fa7d 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -27,12 +27,12 @@
|
||||
If FOR_FINI is true, this is called for finishing an object. */
|
||||
static void
|
||||
_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
|
||||
- unsigned int skip, bool for_fini)
|
||||
+ bool force_first, bool for_fini)
|
||||
{
|
||||
/* Allows caller to do the common optimization of skipping the first map,
|
||||
usually the main binary. */
|
||||
- maps += skip;
|
||||
- nmaps -= skip;
|
||||
+ maps += force_first;
|
||||
+ nmaps -= force_first;
|
||||
|
||||
/* A list of one element need not be sorted. */
|
||||
if (nmaps <= 1)
|
||||
@@ -182,7 +182,7 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
|
||||
static void
|
||||
_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
- unsigned int skip __attribute__ ((unused)), bool for_fini)
|
||||
+ bool force_first __attribute__ ((unused)), bool for_fini)
|
||||
{
|
||||
for (int i = nmaps - 1; i >= 0; i--)
|
||||
maps[i]->l_visited = 0;
|
||||
@@ -286,7 +286,7 @@ _dl_sort_maps_init (void)
|
||||
|
||||
void
|
||||
_dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
- unsigned int skip, bool for_fini)
|
||||
+ bool force_first, bool for_fini)
|
||||
{
|
||||
/* It can be tempting to use a static function pointer to store and call
|
||||
the current selected sorting algorithm routine, but experimentation
|
||||
@@ -296,9 +296,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
input cases. A simple if-case with direct function calls appears to
|
||||
be the fastest. */
|
||||
if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
|
||||
- _dl_sort_maps_original (maps, nmaps, skip, for_fini);
|
||||
+ _dl_sort_maps_original (maps, nmaps, force_first, for_fini);
|
||||
else
|
||||
- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
|
||||
+ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
|
||||
}
|
||||
|
||||
#endif /* HAVE_TUNABLES. */
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 9f09a4a280396659..2c1b4c47c6a6c643 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -1056,9 +1056,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
|
||||
initializer functions have completed. */
|
||||
extern void _dl_fini (void) attribute_hidden;
|
||||
|
||||
-/* Sort array MAPS according to dependencies of the contained objects. */
|
||||
+/* Sort array MAPS according to dependencies of the contained objects.
|
||||
+ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies
|
||||
+ say otherwise. */
|
||||
extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
- unsigned int skip, bool for_fini) attribute_hidden;
|
||||
+ bool force_first, bool for_fini) attribute_hidden;
|
||||
|
||||
/* The dynamic linker calls this function before and having changing
|
||||
any shared object mappings. The `r_state' member of `struct r_debug'
|
90
SOURCES/glibc-rh1159809-11.patch
Normal file
90
SOURCES/glibc-rh1159809-11.patch
Normal file
@ -0,0 +1,90 @@
|
||||
commit 1df71d32fe5f5905ffd5d100e5e9ca8ad6210891
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Sep 20 11:00:42 2022 +0200
|
||||
|
||||
elf: Implement force_first handling in _dl_sort_maps_dfs (bug 28937)
|
||||
|
||||
The implementation in _dl_close_worker requires that the first
|
||||
element of l_initfini is always this very map (“We are always the
|
||||
zeroth entry, and since we don't include ourselves in the
|
||||
dependency analysis start at 1.”). Rather than fixing that
|
||||
assumption, this commit adds an implementation of the force_first
|
||||
argument to the new dependency sorting algorithm. This also means
|
||||
that the directly dlopen'ed shared object is always initialized last,
|
||||
which is the least surprising behavior in the presence of cycles.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index 7a586749adc3fa7d..6f5c17b47b98fbc7 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
|
||||
static void
|
||||
_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
- bool force_first __attribute__ ((unused)), bool for_fini)
|
||||
+ bool force_first, bool for_fini)
|
||||
{
|
||||
+ struct link_map *first_map = maps[0];
|
||||
for (int i = nmaps - 1; i >= 0; i--)
|
||||
maps[i]->l_visited = 0;
|
||||
|
||||
@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
Adjusting the order so that maps[0] is last traversed naturally avoids
|
||||
this problem.
|
||||
|
||||
- Further, the old "optimization" of skipping the main object at maps[0]
|
||||
- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
|
||||
- no longer valid, since traversing along object dependency-links
|
||||
- may "find" the main object even when it is not included in the initial
|
||||
- order (e.g. a dlopen()'ed shared object can have circular dependencies
|
||||
- linked back to itself). In such a case, traversing N-1 objects will
|
||||
- create a N-object result, and raise problems.
|
||||
-
|
||||
To summarize, just passing in the full list, and iterating from back
|
||||
to front makes things much more straightforward. */
|
||||
|
||||
@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
}
|
||||
|
||||
memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
|
||||
+
|
||||
+ /* Skipping the first object at maps[0] is not valid in general,
|
||||
+ since traversing along object dependency-links may "find" that
|
||||
+ first object even when it is not included in the initial order
|
||||
+ (e.g., a dlopen'ed shared object can have circular dependencies
|
||||
+ linked back to itself). In such a case, traversing N-1 objects
|
||||
+ will create a N-object result, and raise problems. Instead,
|
||||
+ force the object back into first place after sorting. This naive
|
||||
+ approach may introduce further dependency ordering violations
|
||||
+ compared to rotating the cycle until the first map is again in
|
||||
+ the first position, but as there is a cycle, at least one
|
||||
+ violation is already present. */
|
||||
+ if (force_first && maps[0] != first_map)
|
||||
+ {
|
||||
+ int i;
|
||||
+ for (i = 0; maps[i] != first_map; ++i)
|
||||
+ ;
|
||||
+ assert (i < nmaps);
|
||||
+ memmove (&maps[1], maps, i * sizeof (maps[0]));
|
||||
+ maps[0] = first_map;
|
||||
+ }
|
||||
}
|
||||
|
||||
void
|
||||
diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
|
||||
index 5f7f18ef270bc12d..4bf9052db16fb352 100644
|
||||
--- a/elf/dso-sort-tests-1.def
|
||||
+++ b/elf/dso-sort-tests-1.def
|
||||
@@ -64,3 +64,10 @@ output: b>a>{}<a<b
|
||||
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
|
||||
output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
|
||||
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
|
||||
+
|
||||
+# Test that even in the presence of dependency loops involving dlopen'ed
|
||||
+# object, that object is initialized last (and not unloaded prematurely).
|
||||
+# Final destructor order is indeterminate due to the cycle.
|
||||
+tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
|
||||
+output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
|
||||
+output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1
|
35
SOURCES/glibc-rh1159809-12.patch
Normal file
35
SOURCES/glibc-rh1159809-12.patch
Normal file
@ -0,0 +1,35 @@
|
||||
Downstream-specific patch to link DSO sorting tests with -ldl
|
||||
if needed. Upstream does not need this because <dlfcn.h> interfaces
|
||||
are part of libc.
|
||||
|
||||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||||
index 43b5ec4d920ad6a3..ae85e0f4a6ae5b3e 100644
|
||||
--- a/scripts/dso-ordering-test.py
|
||||
+++ b/scripts/dso-ordering-test.py
|
||||
@@ -657,6 +657,8 @@ def process_testcase(t):
|
||||
% (test_name + "-" + dep + ".FAKE.so",
|
||||
("$(objpfx)" + test_subdir + "/"
|
||||
+ test_name + "-" + dep + ".so")))
|
||||
+ makefile.write(
|
||||
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % dso)
|
||||
rule = ("$(objpfx)" + test_subdir + "/"
|
||||
+ test_name + "-" + dep + ".FAKE.os: "
|
||||
"$(objpfx)" + test_srcdir
|
||||
@@ -685,6 +687,8 @@ def process_testcase(t):
|
||||
+ test_descr.soname_map[o] + ".so")
|
||||
ldflags += (" -Wl,-soname=" + soname)
|
||||
makefile.write("LDFLAGS-%s = %s\n" % (dso, ldflags))
|
||||
+ makefile.write(
|
||||
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % dso)
|
||||
if o in test_descr.callrefs:
|
||||
makefile.write("%s-no-z-defs = yes\n" % (dso))
|
||||
|
||||
@@ -702,6 +706,8 @@ def process_testcase(t):
|
||||
+ test_descr.soname_map['#'] + ".so")
|
||||
ldflags += (" -Wl,-soname=" + soname)
|
||||
makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags))
|
||||
+ makefile.write(
|
||||
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % test_name)
|
||||
rule = ("$(objpfx)" + test_subdir + "/" + test_name + ".o: "
|
||||
"$(objpfx)" + test_srcdir + test_name + ".c\n"
|
||||
"\t$(compile.c) $(OUTPUT_OPTION)\n")
|
189
SOURCES/glibc-rh1159809-2.patch
Normal file
189
SOURCES/glibc-rh1159809-2.patch
Normal file
@ -0,0 +1,189 @@
|
||||
commit b4bbedb1e75737a80bcc3d53d6eef1fbe0b5f4d5
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Sat Nov 6 14:13:27 2021 -0700
|
||||
|
||||
dso-ordering-test.py: Put all sources in one directory [BZ #28550]
|
||||
|
||||
Put all sources for DSO sorting tests in the dso-sort-tests-src directory
|
||||
and compile test relocatable objects with
|
||||
|
||||
$(objpfx)tst-dso-ordering1-dir/tst-dso-ordering1-a.os: $(objpfx)dso-sort-tests-src/tst-dso-ordering1-a.c
|
||||
$(compile.c) $(OUTPUT_OPTION)
|
||||
|
||||
to avoid random $< values from $(before-compile) when compiling test
|
||||
relocatable objects with
|
||||
|
||||
$(objpfx)%$o: $(objpfx)%.c $(before-compile); $$(compile-command.c)
|
||||
compile-command.c = $(compile.c) $(OUTPUT_OPTION) $(compile-mkdep-flags)
|
||||
compile.c = $(CC) $< -c $(CFLAGS) $(CPPFLAGS)
|
||||
|
||||
for 3 "make -j 28" parallel builds on a machine with 112 cores at the
|
||||
same time.
|
||||
|
||||
This partially fixes BZ #28550.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||||
index 944ee740527d60fd..bde0406be9da14fc 100644
|
||||
--- a/scripts/dso-ordering-test.py
|
||||
+++ b/scripts/dso-ordering-test.py
|
||||
@@ -526,9 +526,13 @@ def process_testcase(t):
|
||||
base_test_name = t.test_name
|
||||
test_subdir = base_test_name + "-dir"
|
||||
testpfx = objpfx + test_subdir + "/"
|
||||
+ test_srcdir = "dso-sort-tests-src/"
|
||||
+ testpfx_src = objpfx + test_srcdir
|
||||
|
||||
if not os.path.exists(testpfx):
|
||||
os.mkdir(testpfx)
|
||||
+ if not os.path.exists(testpfx_src):
|
||||
+ os.mkdir(testpfx_src)
|
||||
|
||||
def find_objs_not_depended_on(t):
|
||||
objs_not_depended_on = []
|
||||
@@ -595,6 +599,11 @@ def process_testcase(t):
|
||||
# Print out needed Makefile fragments for use in glibc/elf/Makefile.
|
||||
module_names = ""
|
||||
for o in test_descr.objs:
|
||||
+ rule = ("$(objpfx)" + test_subdir + "/" + test_name
|
||||
+ + "-" + o + ".os: $(objpfx)" + test_srcdir
|
||||
+ + test_name + "-" + o + ".c\n"
|
||||
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||||
+ makefile.write (rule)
|
||||
module_names += " " + test_subdir + "/" + test_name + "-" + o
|
||||
makefile.write("modules-names +=%s\n" % (module_names))
|
||||
|
||||
@@ -637,7 +646,7 @@ def process_testcase(t):
|
||||
# object. This only needs to be done at most once for
|
||||
# an object name.
|
||||
if not dep in fake_created:
|
||||
- f = open(testpfx + test_name + "-" + dep
|
||||
+ f = open(testpfx_src + test_name + "-" + dep
|
||||
+ ".FAKE.c", "w")
|
||||
f.write(" \n")
|
||||
f.close()
|
||||
@@ -648,6 +657,12 @@ def process_testcase(t):
|
||||
% (test_name + "-" + dep + ".FAKE.so",
|
||||
("$(objpfx)" + test_subdir + "/"
|
||||
+ test_name + "-" + dep + ".so")))
|
||||
+ rule = ("$(objpfx)" + test_subdir + "/"
|
||||
+ + test_name + "-" + dep + ".FAKE.os: "
|
||||
+ "$(objpfx)" + test_srcdir
|
||||
+ + test_name + "-" + dep + ".FAKE.c\n"
|
||||
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||||
+ makefile.write (rule)
|
||||
makefile.write \
|
||||
("modules-names += %s\n"
|
||||
% (test_subdir + "/"
|
||||
@@ -687,6 +702,10 @@ def process_testcase(t):
|
||||
+ test_descr.soname_map['#'] + ".so")
|
||||
ldflags += (" -Wl,-soname=" + soname)
|
||||
makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags))
|
||||
+ rule = ("$(objpfx)" + test_subdir + "/" + test_name + ".o: "
|
||||
+ "$(objpfx)" + test_srcdir + test_name + ".c\n"
|
||||
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||||
+ makefile.write (rule)
|
||||
|
||||
not_depended_objs = find_objs_not_depended_on(test_descr)
|
||||
if not_depended_objs:
|
||||
@@ -745,7 +764,7 @@ def process_testcase(t):
|
||||
" something_failed=true\n"
|
||||
"else\n"
|
||||
" diff -wu ${common_objpfx}elf/%s/%s%s.output \\\n"
|
||||
- " ${common_objpfx}elf/%s/%s%s.exp\n"
|
||||
+ " ${common_objpfx}elf/%s%s%s.exp\n"
|
||||
" if [ $? -ne 0 ]; then\n"
|
||||
" echo '%sFAIL: %s%s expected output comparison'\n"
|
||||
" something_failed=true\n"
|
||||
@@ -753,14 +772,14 @@ def process_testcase(t):
|
||||
"fi\n"
|
||||
% (("X" if xfail else ""), test_name, tunable_descr,
|
||||
test_subdir, test_name, tunable_sfx,
|
||||
- test_subdir, base_test_name, exp_tunable_sfx,
|
||||
+ test_srcdir, base_test_name, exp_tunable_sfx,
|
||||
("X" if xfail else ""), test_name, tunable_descr))
|
||||
|
||||
# Generate C files according to dependency and calling relations from
|
||||
# description string.
|
||||
for obj in test_descr.objs:
|
||||
src_name = test_name + "-" + obj + ".c"
|
||||
- f = open(testpfx + src_name, "w")
|
||||
+ f = open(testpfx_src + src_name, "w")
|
||||
if obj in test_descr.callrefs:
|
||||
called_objs = test_descr.callrefs[obj]
|
||||
for callee in called_objs:
|
||||
@@ -804,7 +823,7 @@ def process_testcase(t):
|
||||
f.close()
|
||||
|
||||
# Open C file for writing main program
|
||||
- f = open(testpfx + test_name + ".c", "w")
|
||||
+ f = open(testpfx_src + test_name + ".c", "w")
|
||||
|
||||
# if there are some operations in main(), it means we need -ldl
|
||||
f.write("#include <stdio.h>\n")
|
||||
@@ -885,7 +904,7 @@ def process_testcase(t):
|
||||
for obj in test_descr.objs:
|
||||
src_name = test_name + "-" + obj + ".c"
|
||||
obj_name = test_name + "-" + obj + ".os"
|
||||
- run_cmd([build_gcc, "-c", "-fPIC", testpfx + src_name,
|
||||
+ run_cmd([build_gcc, "-c", "-fPIC", testpfx_src + src_name,
|
||||
"-o", testpfx + obj_name])
|
||||
|
||||
obj_processed = {}
|
||||
@@ -903,10 +922,12 @@ def process_testcase(t):
|
||||
deps.append(dep + ".FAKE")
|
||||
if not dep in fake_created:
|
||||
base_name = testpfx + test_name + "-" + dep
|
||||
+ src_base_name = (testpfx_src + test_name
|
||||
+ + "-" + dep)
|
||||
cmd = [build_gcc, "-Wl,--no-as-needed",
|
||||
("-Wl,-soname=" + base_name + ".so"),
|
||||
"-shared", base_name + ".FAKE.c",
|
||||
- "-o", base_name + ".FAKE.so"]
|
||||
+ "-o", src_base_name + ".FAKE.so"]
|
||||
run_cmd(cmd)
|
||||
fake_created[dep] = True
|
||||
dso_deps = map(lambda d: testpfx + test_name + "-" + d + ".so",
|
||||
@@ -932,7 +953,7 @@ def process_testcase(t):
|
||||
main_deps = map(lambda d: testpfx + test_name + "-" + d + ".so",
|
||||
deps)
|
||||
cmd = [build_gcc, "-Wl,--no-as-needed", "-o", testpfx + test_name,
|
||||
- testpfx + test_name + ".c", "-L%s" % (os.getcwd()),
|
||||
+ testpfx_src + test_name + ".c", "-L%s" % (os.getcwd()),
|
||||
"-Wl,-rpath-link=%s" % (os.getcwd())]
|
||||
if '#' in test_descr.soname_map:
|
||||
soname = ("-Wl,-soname=" + testpfx + test_name + "-"
|
||||
@@ -987,14 +1008,14 @@ def process_testcase(t):
|
||||
sfx = ""
|
||||
if r[0] != "":
|
||||
sfx = "-" + r[0].replace("=","_")
|
||||
- f = open(testpfx + t.test_name + sfx + ".exp", "w")
|
||||
+ f = open(testpfx_src + t.test_name + sfx + ".exp", "w")
|
||||
(output, xfail) = r[1]
|
||||
f.write('%s' % output)
|
||||
f.close()
|
||||
|
||||
# Create header part of top-level testcase shell script, to wrap execution
|
||||
# and output comparison together.
|
||||
- t.sh = open(testpfx + t.test_name + ".sh", "w")
|
||||
+ t.sh = open(testpfx_src + t.test_name + ".sh", "w")
|
||||
t.sh.write("#!/bin/sh\n")
|
||||
t.sh.write("# Test driver for %s, generated by "
|
||||
"dso-ordering-test.py\n" % (t.test_name))
|
||||
@@ -1022,12 +1043,12 @@ def process_testcase(t):
|
||||
sfx = ""
|
||||
if r[0] != "":
|
||||
sfx = "-" + r[0].replace("=","_")
|
||||
- expected_output_files += " $(objpfx)%s/%s%s.exp" % (test_subdir,
|
||||
+ expected_output_files += " $(objpfx)%s%s%s.exp" % (test_srcdir,
|
||||
t.test_name, sfx)
|
||||
makefile.write \
|
||||
- ("$(objpfx)%s.out: $(objpfx)%s/%s.sh%s "
|
||||
+ ("$(objpfx)%s.out: $(objpfx)%s%s.sh%s "
|
||||
"$(common-objpfx)support/test-run-command\n"
|
||||
- % (t.test_name, test_subdir, t.test_name,
|
||||
+ % (t.test_name, test_srcdir, t.test_name,
|
||||
expected_output_files))
|
||||
makefile.write("\t$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' "
|
||||
"'$(run-program-env)' > $@; $(evaluate-test)\n")
|
589
SOURCES/glibc-rh1159809-3.patch
Normal file
589
SOURCES/glibc-rh1159809-3.patch
Normal file
@ -0,0 +1,589 @@
|
||||
commit 15a0c5730d1d5aeb95f50c9ec7470640084feae8
|
||||
Author: Chung-Lin Tang <cltang@codesourcery.com>
|
||||
Date: Thu Oct 21 21:41:22 2021 +0800
|
||||
|
||||
elf: Fix slow DSO sorting behavior in dynamic loader (BZ #17645)
|
||||
|
||||
This second patch contains the actual implementation of a new sorting algorithm
|
||||
for shared objects in the dynamic loader, which solves the slow behavior that
|
||||
the current "old" algorithm falls into when the DSO set contains circular
|
||||
dependencies.
|
||||
|
||||
The new algorithm implemented here is simply depth-first search (DFS) to obtain
|
||||
the Reverse-Post Order (RPO) sequence, a topological sort. A new l_visited:1
|
||||
bitfield is added to struct link_map to more elegantly facilitate such a search.
|
||||
|
||||
The DFS algorithm is applied to the input maps[nmap-1] backwards towards
|
||||
maps[0]. This has the effect of a more "shallow" recursion depth in general
|
||||
since the input is in BFS. Also, when combined with the natural order of
|
||||
processing l_initfini[] at each node, this creates a resulting output sorting
|
||||
closer to the intuitive "left-to-right" order in most cases.
|
||||
|
||||
Another notable implementation adjustment related to this _dl_sort_maps change
|
||||
is the removing of two char arrays 'used' and 'done' in _dl_close_worker to
|
||||
represent two per-map attributes. This has been changed to simply use two new
|
||||
bit-fields l_map_used:1, l_map_done:1 added to struct link_map. This also allows
|
||||
discarding the clunky 'used' array sorting that _dl_sort_maps had to sometimes
|
||||
do along the way.
|
||||
|
||||
Tunable support for switching between different sorting algorithms at runtime is
|
||||
also added. A new tunable 'glibc.rtld.dynamic_sort' with current valid values 1
|
||||
(old algorithm) and 2 (new DFS algorithm) has been added. At time of commit
|
||||
of this patch, the default setting is 1 (old algorithm).
|
||||
|
||||
Signed-off-by: Chung-Lin Tang <cltang@codesourcery.com>
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
elf/dl-tunables.list
|
||||
(No mem.tagging tunable downstream.)
|
||||
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index 74ca9a85dd309780..22225efb3226c3e1 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -167,8 +167,6 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
|
||||
bool any_tls = false;
|
||||
const unsigned int nloaded = ns->_ns_nloaded;
|
||||
- char used[nloaded];
|
||||
- char done[nloaded];
|
||||
struct link_map *maps[nloaded];
|
||||
|
||||
/* Run over the list and assign indexes to the link maps and enter
|
||||
@@ -176,24 +174,21 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
int idx = 0;
|
||||
for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next)
|
||||
{
|
||||
+ l->l_map_used = 0;
|
||||
+ l->l_map_done = 0;
|
||||
l->l_idx = idx;
|
||||
maps[idx] = l;
|
||||
++idx;
|
||||
-
|
||||
}
|
||||
assert (idx == nloaded);
|
||||
|
||||
- /* Prepare the bitmaps. */
|
||||
- memset (used, '\0', sizeof (used));
|
||||
- memset (done, '\0', sizeof (done));
|
||||
-
|
||||
/* Keep track of the lowest index link map we have covered already. */
|
||||
int done_index = -1;
|
||||
while (++done_index < nloaded)
|
||||
{
|
||||
struct link_map *l = maps[done_index];
|
||||
|
||||
- if (done[done_index])
|
||||
+ if (l->l_map_done)
|
||||
/* Already handled. */
|
||||
continue;
|
||||
|
||||
@@ -204,12 +199,12 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
/* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
|
||||
acquire is sufficient and correct. */
|
||||
&& atomic_load_acquire (&l->l_tls_dtor_count) == 0
|
||||
- && !used[done_index])
|
||||
+ && !l->l_map_used)
|
||||
continue;
|
||||
|
||||
/* We need this object and we handle it now. */
|
||||
- done[done_index] = 1;
|
||||
- used[done_index] = 1;
|
||||
+ l->l_map_used = 1;
|
||||
+ l->l_map_done = 1;
|
||||
/* Signal the object is still needed. */
|
||||
l->l_idx = IDX_STILL_USED;
|
||||
|
||||
@@ -225,9 +220,9 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
{
|
||||
assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
|
||||
|
||||
- if (!used[(*lp)->l_idx])
|
||||
+ if (!(*lp)->l_map_used)
|
||||
{
|
||||
- used[(*lp)->l_idx] = 1;
|
||||
+ (*lp)->l_map_used = 1;
|
||||
/* If we marked a new object as used, and we've
|
||||
already processed it, then we need to go back
|
||||
and process again from that point forward to
|
||||
@@ -250,9 +245,9 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
{
|
||||
assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
|
||||
|
||||
- if (!used[jmap->l_idx])
|
||||
+ if (!jmap->l_map_used)
|
||||
{
|
||||
- used[jmap->l_idx] = 1;
|
||||
+ jmap->l_map_used = 1;
|
||||
if (jmap->l_idx - 1 < done_index)
|
||||
done_index = jmap->l_idx - 1;
|
||||
}
|
||||
@@ -262,8 +257,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
|
||||
/* Sort the entries. We can skip looking for the binary itself which is
|
||||
at the front of the search list for the main namespace. */
|
||||
- _dl_sort_maps (maps + (nsid == LM_ID_BASE), nloaded - (nsid == LM_ID_BASE),
|
||||
- used + (nsid == LM_ID_BASE), true);
|
||||
+ _dl_sort_maps (maps, nloaded, (nsid == LM_ID_BASE), true);
|
||||
|
||||
/* Call all termination functions at once. */
|
||||
bool unload_any = false;
|
||||
@@ -277,7 +271,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
/* All elements must be in the same namespace. */
|
||||
assert (imap->l_ns == nsid);
|
||||
|
||||
- if (!used[i])
|
||||
+ if (!imap->l_map_used)
|
||||
{
|
||||
assert (imap->l_type == lt_loaded && !imap->l_nodelete_active);
|
||||
|
||||
@@ -315,7 +309,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
if (i < first_loaded)
|
||||
first_loaded = i;
|
||||
}
|
||||
- /* Else used[i]. */
|
||||
+ /* Else imap->l_map_used. */
|
||||
else if (imap->l_type == lt_loaded)
|
||||
{
|
||||
struct r_scope_elem *new_list = NULL;
|
||||
@@ -524,7 +518,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
for (unsigned int i = first_loaded; i < nloaded; ++i)
|
||||
{
|
||||
struct link_map *imap = maps[i];
|
||||
- if (!used[i])
|
||||
+ if (!imap->l_map_used)
|
||||
{
|
||||
assert (imap->l_type == lt_loaded);
|
||||
|
||||
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
|
||||
index 007069f670eced95..9365d54c8e03e5f4 100644
|
||||
--- a/elf/dl-deps.c
|
||||
+++ b/elf/dl-deps.c
|
||||
@@ -612,10 +612,9 @@ Filters not supported with LD_TRACE_PRELINKING"));
|
||||
|
||||
/* If libc.so.6 is the main map, it participates in the sort, so
|
||||
that the relocation order is correct regarding libc.so.6. */
|
||||
- if (l_initfini[0] == GL (dl_ns)[l_initfini[0]->l_ns].libc_map)
|
||||
- _dl_sort_maps (l_initfini, nlist, NULL, false);
|
||||
- else
|
||||
- _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false);
|
||||
+ _dl_sort_maps (l_initfini, nlist,
|
||||
+ (l_initfini[0] != GL (dl_ns)[l_initfini[0]->l_ns].libc_map),
|
||||
+ false);
|
||||
|
||||
/* Terminate the list of dependencies. */
|
||||
l_initfini[nlist] = NULL;
|
||||
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
|
||||
index eea9d8aad736a99e..e14259a3c8806e0d 100644
|
||||
--- a/elf/dl-fini.c
|
||||
+++ b/elf/dl-fini.c
|
||||
@@ -95,8 +95,7 @@ _dl_fini (void)
|
||||
/* Now we have to do the sorting. We can skip looking for the
|
||||
binary itself which is at the front of the search list for
|
||||
the main namespace. */
|
||||
- _dl_sort_maps (maps + (ns == LM_ID_BASE), nmaps - (ns == LM_ID_BASE),
|
||||
- NULL, true);
|
||||
+ _dl_sort_maps (maps, nmaps, (ns == LM_ID_BASE), true);
|
||||
|
||||
/* We do not rely on the linked list of loaded object anymore
|
||||
from this point on. We have our own list here (maps). The
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index b2a01ede627be1e9..398a08f28c4d9ff1 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -16,16 +16,24 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
+#include <assert.h>
|
||||
#include <ldsodefs.h>
|
||||
+#include <elf/dl-tunables.h>
|
||||
|
||||
+/* Note: this is the older, "original" sorting algorithm, being used as
|
||||
+ default up to 2.35.
|
||||
|
||||
-/* Sort array MAPS according to dependencies of the contained objects.
|
||||
- Array USED, if non-NULL, is permutated along MAPS. If FOR_FINI this is
|
||||
- called for finishing an object. */
|
||||
-void
|
||||
-_dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
|
||||
- bool for_fini)
|
||||
+ Sort array MAPS according to dependencies of the contained objects.
|
||||
+ If FOR_FINI is true, this is called for finishing an object. */
|
||||
+static void
|
||||
+_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
|
||||
+ unsigned int skip, bool for_fini)
|
||||
{
|
||||
+ /* Allows caller to do the common optimization of skipping the first map,
|
||||
+ usually the main binary. */
|
||||
+ maps += skip;
|
||||
+ nmaps -= skip;
|
||||
+
|
||||
/* A list of one element need not be sorted. */
|
||||
if (nmaps <= 1)
|
||||
return;
|
||||
@@ -66,14 +74,6 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
|
||||
(k - i) * sizeof (maps[0]));
|
||||
maps[k] = thisp;
|
||||
|
||||
- if (used != NULL)
|
||||
- {
|
||||
- char here_used = used[i];
|
||||
- memmove (&used[i], &used[i + 1],
|
||||
- (k - i) * sizeof (used[0]));
|
||||
- used[k] = here_used;
|
||||
- }
|
||||
-
|
||||
if (seen[i + 1] > nmaps - i)
|
||||
{
|
||||
++i;
|
||||
@@ -120,3 +120,183 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
|
||||
next:;
|
||||
}
|
||||
}
|
||||
+
|
||||
+#if !HAVE_TUNABLES
|
||||
+/* In this case, just default to the original algorithm. */
|
||||
+strong_alias (_dl_sort_maps_original, _dl_sort_maps);
|
||||
+#else
|
||||
+
|
||||
+/* We use a recursive function due to its better clarity and ease of
|
||||
+ implementation, as well as faster execution speed. We already use
|
||||
+ alloca() for list allocation during the breadth-first search of
|
||||
+ dependencies in _dl_map_object_deps(), and this should be on the
|
||||
+ same order of worst-case stack usage.
|
||||
+
|
||||
+ Note: the '*rpo' parameter is supposed to point to one past the
|
||||
+ last element of the array where we save the sort results, and is
|
||||
+ decremented before storing the current map at each level. */
|
||||
+
|
||||
+static void
|
||||
+dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
+ bool *do_reldeps)
|
||||
+{
|
||||
+ if (map->l_visited)
|
||||
+ return;
|
||||
+
|
||||
+ map->l_visited = 1;
|
||||
+
|
||||
+ if (map->l_initfini)
|
||||
+ {
|
||||
+ for (int i = 0; map->l_initfini[i] != NULL; i++)
|
||||
+ {
|
||||
+ struct link_map *dep = map->l_initfini[i];
|
||||
+ if (dep->l_visited == 0
|
||||
+ && dep->l_main_map == 0)
|
||||
+ dfs_traversal (rpo, dep, do_reldeps);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (__glibc_unlikely (do_reldeps != NULL && map->l_reldeps != NULL))
|
||||
+ {
|
||||
+ /* Indicate that we encountered relocation dependencies during
|
||||
+ traversal. */
|
||||
+ *do_reldeps = true;
|
||||
+
|
||||
+ for (int m = map->l_reldeps->act - 1; m >= 0; m--)
|
||||
+ {
|
||||
+ struct link_map *dep = map->l_reldeps->list[m];
|
||||
+ if (dep->l_visited == 0
|
||||
+ && dep->l_main_map == 0)
|
||||
+ dfs_traversal (rpo, dep, do_reldeps);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ *rpo -= 1;
|
||||
+ **rpo = map;
|
||||
+}
|
||||
+
|
||||
+/* Topologically sort array MAPS according to dependencies of the contained
|
||||
+ objects. */
|
||||
+
|
||||
+static void
|
||||
+_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
+ unsigned int skip __attribute__ ((unused)), bool for_fini)
|
||||
+{
|
||||
+ for (int i = nmaps - 1; i >= 0; i--)
|
||||
+ maps[i]->l_visited = 0;
|
||||
+
|
||||
+ /* We apply DFS traversal for each of maps[i] until the whole total order
|
||||
+ is found and we're at the start of the Reverse-Postorder (RPO) sequence,
|
||||
+ which is a topological sort.
|
||||
+
|
||||
+ We go from maps[nmaps - 1] backwards towards maps[0] at this level.
|
||||
+ Due to the breadth-first search (BFS) ordering we receive, going
|
||||
+ backwards usually gives a more shallow depth-first recursion depth,
|
||||
+ adding more stack usage safety. Also, combined with the natural
|
||||
+ processing order of l_initfini[] at each node during DFS, this maintains
|
||||
+ an ordering closer to the original link ordering in the sorting results
|
||||
+ under most simpler cases.
|
||||
+
|
||||
+ Another reason we order the top level backwards, it that maps[0] is
|
||||
+ usually exactly the main object of which we're in the midst of
|
||||
+ _dl_map_object_deps() processing, and maps[0]->l_initfini[] is still
|
||||
+ blank. If we start the traversal from maps[0], since having no
|
||||
+ dependencies yet filled in, maps[0] will always be immediately
|
||||
+ incorrectly placed at the last place in the order (first in reverse).
|
||||
+ Adjusting the order so that maps[0] is last traversed naturally avoids
|
||||
+ this problem.
|
||||
+
|
||||
+ Further, the old "optimization" of skipping the main object at maps[0]
|
||||
+ from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
|
||||
+ no longer valid, since traversing along object dependency-links
|
||||
+ may "find" the main object even when it is not included in the initial
|
||||
+ order (e.g. a dlopen()'ed shared object can have circular dependencies
|
||||
+ linked back to itself). In such a case, traversing N-1 objects will
|
||||
+ create a N-object result, and raise problems.
|
||||
+
|
||||
+ To summarize, just passing in the full list, and iterating from back
|
||||
+ to front makes things much more straightforward. */
|
||||
+
|
||||
+ /* Array to hold RPO sorting results, before we copy back to maps[]. */
|
||||
+ struct link_map *rpo[nmaps];
|
||||
+
|
||||
+ /* The 'head' position during each DFS iteration. Note that we start at
|
||||
+ one past the last element due to first-decrement-then-store (see the
|
||||
+ bottom of above dfs_traversal() routine). */
|
||||
+ struct link_map **rpo_head = &rpo[nmaps];
|
||||
+
|
||||
+ bool do_reldeps = false;
|
||||
+ bool *do_reldeps_ref = (for_fini ? &do_reldeps : NULL);
|
||||
+
|
||||
+ for (int i = nmaps - 1; i >= 0; i--)
|
||||
+ {
|
||||
+ dfs_traversal (&rpo_head, maps[i], do_reldeps_ref);
|
||||
+
|
||||
+ /* We can break early if all objects are already placed. */
|
||||
+ if (rpo_head == rpo)
|
||||
+ goto end;
|
||||
+ }
|
||||
+ assert (rpo_head == rpo);
|
||||
+
|
||||
+ end:
|
||||
+ /* Here we may do a second pass of sorting, using only l_initfini[]
|
||||
+ static dependency links. This is avoided if !FOR_FINI or if we didn't
|
||||
+ find any reldeps in the first DFS traversal.
|
||||
+
|
||||
+ The reason we do this is: while it is unspecified how circular
|
||||
+ dependencies should be handled, the presumed reasonable behavior is to
|
||||
+ have destructors to respect static dependency links as much as possible,
|
||||
+ overriding reldeps if needed. And the first sorting pass, which takes
|
||||
+ l_initfini/l_reldeps links equally, may not preserve this priority.
|
||||
+
|
||||
+ Hence we do a 2nd sorting pass, taking only DT_NEEDED links into account
|
||||
+ (see how the do_reldeps argument to dfs_traversal() is NULL below). */
|
||||
+ if (do_reldeps)
|
||||
+ {
|
||||
+ for (int i = nmaps - 1; i >= 0; i--)
|
||||
+ rpo[i]->l_visited = 0;
|
||||
+
|
||||
+ struct link_map **maps_head = &maps[nmaps];
|
||||
+ for (int i = nmaps - 1; i >= 0; i--)
|
||||
+ {
|
||||
+ dfs_traversal (&maps_head, rpo[i], NULL);
|
||||
+
|
||||
+ /* We can break early if all objects are already placed.
|
||||
+ The below memcpy is not needed in the do_reldeps case here,
|
||||
+ since we wrote back to maps[] during DFS traversal. */
|
||||
+ if (maps_head == maps)
|
||||
+ return;
|
||||
+ }
|
||||
+ assert (maps_head == maps);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+_dl_sort_maps_init (void)
|
||||
+{
|
||||
+ int32_t algorithm = TUNABLE_GET (glibc, rtld, dynamic_sort, int32_t, NULL);
|
||||
+ GLRO(dl_dso_sort_algo) = algorithm == 1 ? dso_sort_algorithm_original
|
||||
+ : dso_sort_algorithm_dfs;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+_dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
+ unsigned int skip, bool for_fini)
|
||||
+{
|
||||
+ /* It can be tempting to use a static function pointer to store and call
|
||||
+ the current selected sorting algorithm routine, but experimentation
|
||||
+ shows that current processors still do not handle indirect branches
|
||||
+ that efficiently, plus a static function pointer will involve
|
||||
+ PTR_MANGLE/DEMANGLE, further impairing performance of small, common
|
||||
+ input cases. A simple if-case with direct function calls appears to
|
||||
+ be the fastest. */
|
||||
+ if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
|
||||
+ _dl_sort_maps_original (maps, nmaps, skip, for_fini);
|
||||
+ else
|
||||
+ _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
|
||||
+}
|
||||
+
|
||||
+#endif /* HAVE_TUNABLES. */
|
||||
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||||
index e9943e889ef447ad..ae03aec9764e29d3 100644
|
||||
--- a/elf/dl-support.c
|
||||
+++ b/elf/dl-support.c
|
||||
@@ -155,6 +155,8 @@ size_t _dl_phnum;
|
||||
uint64_t _dl_hwcap __attribute__ ((nocommon));
|
||||
uint64_t _dl_hwcap2 __attribute__ ((nocommon));
|
||||
|
||||
+enum dso_sort_algorithm _dl_dso_sort_algo;
|
||||
+
|
||||
/* The value of the FPU control word the kernel will preset in hardware. */
|
||||
fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
|
||||
|
||||
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
|
||||
index 998c5d52bcab8193..4e8a986541fc4c09 100644
|
||||
--- a/elf/dl-sysdep.c
|
||||
+++ b/elf/dl-sysdep.c
|
||||
@@ -223,6 +223,9 @@ _dl_sysdep_start (void **start_argptr,
|
||||
|
||||
__tunables_init (_environ);
|
||||
|
||||
+ /* Initialize DSO sorting algorithm after tunables. */
|
||||
+ _dl_sort_maps_init ();
|
||||
+
|
||||
#ifdef DL_SYSDEP_INIT
|
||||
DL_SYSDEP_INIT;
|
||||
#endif
|
||||
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
|
||||
index 6408a8e5ae92d2c6..54ef2a921310b229 100644
|
||||
--- a/elf/dl-tunables.list
|
||||
+++ b/elf/dl-tunables.list
|
||||
@@ -140,4 +140,13 @@ glibc {
|
||||
default: 512
|
||||
}
|
||||
}
|
||||
+
|
||||
+ rtld {
|
||||
+ dynamic_sort {
|
||||
+ type: INT_32
|
||||
+ minval: 1
|
||||
+ maxval: 2
|
||||
+ default: 1
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
|
||||
index 873ddf55d91155c6..5f7f18ef270bc12d 100644
|
||||
--- a/elf/dso-sort-tests-1.def
|
||||
+++ b/elf/dso-sort-tests-1.def
|
||||
@@ -62,5 +62,5 @@ output: b>a>{}<a<b
|
||||
# The below expected outputs are what the two algorithms currently produce
|
||||
# respectively, for regression testing purposes.
|
||||
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
|
||||
-xfail_output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
|
||||
+output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
|
||||
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index b47e84ca2fb6f03c..cd2cc4024a3581c2 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -1453,6 +1453,9 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
main_map->l_name = (char *) "";
|
||||
*user_entry = main_map->l_entry;
|
||||
|
||||
+ /* Set bit indicating this is the main program map. */
|
||||
+ main_map->l_main_map = 1;
|
||||
+
|
||||
#ifdef HAVE_AUX_VECTOR
|
||||
/* Adjust the on-stack auxiliary vector so that it looks like the
|
||||
binary was executed directly. */
|
||||
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
|
||||
index 4f3f7ee4e30a2b42..118afc271057afd4 100644
|
||||
--- a/elf/tst-rtld-list-tunables.exp
|
||||
+++ b/elf/tst-rtld-list-tunables.exp
|
||||
@@ -10,5 +10,6 @@ glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
+glibc.rtld.dynamic_sort: 1 (min: 1, max: 2)
|
||||
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
|
||||
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
|
||||
diff --git a/include/link.h b/include/link.h
|
||||
index dd491989beb41353..041ff5f753a9ee11 100644
|
||||
--- a/include/link.h
|
||||
+++ b/include/link.h
|
||||
@@ -181,6 +181,11 @@ struct link_map
|
||||
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
|
||||
unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */
|
||||
unsigned int l_reserved:2; /* Reserved for internal use. */
|
||||
+ unsigned int l_main_map:1; /* Nonzero for the map of the main program. */
|
||||
+ unsigned int l_visited:1; /* Used internally for map dependency
|
||||
+ graph traversal. */
|
||||
+ unsigned int l_map_used:1; /* These two bits are used during traversal */
|
||||
+ unsigned int l_map_done:1; /* of maps in _dl_close_worker. */
|
||||
unsigned int l_phdr_allocated:1; /* Nonzero if the data structure pointed
|
||||
to by `l_phdr' is allocated. */
|
||||
unsigned int l_soname_added:1; /* Nonzero if the SONAME is for sure in
|
||||
diff --git a/manual/tunables.texi b/manual/tunables.texi
|
||||
index 43272cf885d1e3e6..c3f96cdc85208926 100644
|
||||
--- a/manual/tunables.texi
|
||||
+++ b/manual/tunables.texi
|
||||
@@ -303,6 +303,17 @@ changed once allocated at process startup. The default allocation of
|
||||
optional static TLS is 512 bytes and is allocated in every thread.
|
||||
@end deftp
|
||||
|
||||
+@deftp Tunable glibc.rtld.dynamic_sort
|
||||
+Sets the algorithm to use for DSO sorting, valid values are @samp{1} and
|
||||
+@samp{2}. For value of @samp{1}, an older O(n^3) algorithm is used, which is
|
||||
+long time tested, but may have performance issues when dependencies between
|
||||
+shared objects contain cycles due to circular dependencies. When set to the
|
||||
+value of @samp{2}, a different algorithm is used, which implements a
|
||||
+topological sort through depth-first search, and does not exhibit the
|
||||
+performance issues of @samp{1}.
|
||||
+
|
||||
+The default value of this tunable is @samp{1}.
|
||||
+@end deftp
|
||||
|
||||
@node Elision Tunables
|
||||
@section Elision Tunables
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 5e56550a4d556fa7..9f09a4a280396659 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -240,6 +240,13 @@ enum allowmask
|
||||
};
|
||||
|
||||
|
||||
+/* DSO sort algorithm to use (check dl-sort-maps.c). */
|
||||
+enum dso_sort_algorithm
|
||||
+ {
|
||||
+ dso_sort_algorithm_original,
|
||||
+ dso_sort_algorithm_dfs
|
||||
+ };
|
||||
+
|
||||
struct audit_ifaces
|
||||
{
|
||||
void (*activity) (uintptr_t *, unsigned int);
|
||||
@@ -633,6 +640,8 @@ struct rtld_global_ro
|
||||
platforms. */
|
||||
EXTERN uint64_t _dl_hwcap2;
|
||||
|
||||
+ EXTERN enum dso_sort_algorithm _dl_dso_sort_algo;
|
||||
+
|
||||
#ifdef SHARED
|
||||
/* We add a function table to _rtld_global which is then used to
|
||||
call the function instead of going through the PLT. The result
|
||||
@@ -1049,7 +1058,7 @@ extern void _dl_fini (void) attribute_hidden;
|
||||
|
||||
/* Sort array MAPS according to dependencies of the contained objects. */
|
||||
extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
- char *used, bool for_fini) attribute_hidden;
|
||||
+ unsigned int skip, bool for_fini) attribute_hidden;
|
||||
|
||||
/* The dynamic linker calls this function before and having changing
|
||||
any shared object mappings. The `r_state' member of `struct r_debug'
|
||||
@@ -1167,6 +1176,9 @@ extern struct link_map * _dl_get_dl_main_map (void)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
+/* Initialize the DSO sort algorithm to use. */
|
||||
+extern void _dl_sort_maps_init (void) attribute_hidden;
|
||||
+
|
||||
/* Initialization of libpthread for statically linked applications.
|
||||
If libpthread is not linked in, this is an empty function. */
|
||||
void __pthread_initialize_minimal (void) weak_function;
|
25
SOURCES/glibc-rh1159809-4.patch
Normal file
25
SOURCES/glibc-rh1159809-4.patch
Normal file
@ -0,0 +1,25 @@
|
||||
commit d3bf2f5927d51258a51ac7fde04f4805f8ee294a
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Wed Nov 3 09:19:30 2021 -0300
|
||||
|
||||
elf: Do not run DSO sorting if tunables is not enabled
|
||||
|
||||
Since the argorithm selection requires tunables.
|
||||
|
||||
Checked on x86_64-linux-gnu with --enable-tunables=no.
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index e92f62f279566684..3b5e1f59e6696a2b 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -998,8 +998,10 @@ include $(objpfx)$(1).generated-makefile
|
||||
endef
|
||||
|
||||
# Generate from each testcase description file
|
||||
+ifeq (yes,$(have-tunables))
|
||||
$(eval $(call include_dsosort_tests,dso-sort-tests-1.def))
|
||||
$(eval $(call include_dsosort_tests,dso-sort-tests-2.def))
|
||||
+endif
|
||||
|
||||
check-abi: $(objpfx)check-abi-ld.out
|
||||
tests-special += $(objpfx)check-abi-ld.out
|
45
SOURCES/glibc-rh1159809-5.patch
Normal file
45
SOURCES/glibc-rh1159809-5.patch
Normal file
@ -0,0 +1,45 @@
|
||||
commit 1f67d8286b5da9266a138198ef1f15c27cbb0010
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Mon Nov 15 16:28:39 2021 -0800
|
||||
|
||||
elf: Use a temporary file to generate Makefile fragments [BZ #28550]
|
||||
|
||||
1. Use a temporary file to generate Makefile fragments for DSO sorting
|
||||
tests and use -include on them.
|
||||
2. Add Makefile fragments to postclean-generated so that a "make clean"
|
||||
removes the autogenerated fragments and a subsequent "make" regenerates
|
||||
them.
|
||||
|
||||
This partially fixes BZ #28550.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 3b5e1f59e6696a2b..22a8060f7d3bb1a1 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -986,6 +986,7 @@ tests-special += \
|
||||
# tests-special
|
||||
endif
|
||||
|
||||
+ifndef avoid-generated
|
||||
# DSO sorting tests:
|
||||
# The dso-ordering-test.py script generates testcase source files in $(objpfx),
|
||||
# creating a $(objpfx)<testcase-name>-dir for each testcase, and creates a
|
||||
@@ -993,9 +994,14 @@ endif
|
||||
define include_dsosort_tests
|
||||
$(objpfx)$(1).generated-makefile: $(1)
|
||||
$(PYTHON) $(..)scripts/dso-ordering-test.py \
|
||||
- --description-file $$< --objpfx $(objpfx) --output-makefile $$@
|
||||
-include $(objpfx)$(1).generated-makefile
|
||||
+ --description-file $$< --objpfx $(objpfx) --output-makefile $$@T
|
||||
+ mv $$@T $$@
|
||||
+-include $(objpfx)$(1).generated-makefile
|
||||
endef
|
||||
+endif
|
||||
+
|
||||
+postclean-generated += $(objpfx)/dso-sort-tests-2.generated-makefile \
|
||||
+ $(objpfx)/dso-sort-tests-2.generated-makefile
|
||||
|
||||
# Generate from each testcase description file
|
||||
ifeq (yes,$(have-tunables))
|
49
SOURCES/glibc-rh1159809-6.patch
Normal file
49
SOURCES/glibc-rh1159809-6.patch
Normal file
@ -0,0 +1,49 @@
|
||||
commit 0884724a95b60452ad483dbe086d237d02ba624d
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Dec 14 12:37:44 2021 +0100
|
||||
|
||||
elf: Use new dependency sorting algorithm by default
|
||||
|
||||
The default has to change eventually, and there are no known failures
|
||||
that require a delay.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
|
||||
index 54ef2a921310b229..f11ca5b3e8b09b43 100644
|
||||
--- a/elf/dl-tunables.list
|
||||
+++ b/elf/dl-tunables.list
|
||||
@@ -146,7 +146,7 @@ glibc {
|
||||
type: INT_32
|
||||
minval: 1
|
||||
maxval: 2
|
||||
- default: 1
|
||||
+ default: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
|
||||
index 118afc271057afd4..478ee8ab091685eb 100644
|
||||
--- a/elf/tst-rtld-list-tunables.exp
|
||||
+++ b/elf/tst-rtld-list-tunables.exp
|
||||
@@ -10,6 +10,6 @@ glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
|
||||
-glibc.rtld.dynamic_sort: 1 (min: 1, max: 2)
|
||||
+glibc.rtld.dynamic_sort: 2 (min: 1, max: 2)
|
||||
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
|
||||
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
|
||||
diff --git a/manual/tunables.texi b/manual/tunables.texi
|
||||
index c3f96cdc85208926..7b70e80391ee87f7 100644
|
||||
--- a/manual/tunables.texi
|
||||
+++ b/manual/tunables.texi
|
||||
@@ -312,7 +312,7 @@ value of @samp{2}, a different algorithm is used, which implements a
|
||||
topological sort through depth-first search, and does not exhibit the
|
||||
performance issues of @samp{1}.
|
||||
|
||||
-The default value of this tunable is @samp{1}.
|
||||
+The default value of this tunable is @samp{2}.
|
||||
@end deftp
|
||||
|
||||
@node Elision Tunables
|
357
SOURCES/glibc-rh1159809-7.patch
Normal file
357
SOURCES/glibc-rh1159809-7.patch
Normal file
@ -0,0 +1,357 @@
|
||||
commit 3a0588ae48fb35384a6bd33f9b66403badfa1262
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Tue Feb 8 15:22:49 2022 -0300
|
||||
|
||||
elf: Fix DFS sorting algorithm for LD_TRACE_LOADED_OBJECTS with missing libraries (BZ #28868)
|
||||
|
||||
On _dl_map_object the underlying file is not opened in trace mode
|
||||
(in other cases where the underlying file can't be opened,
|
||||
_dl_map_object quits with an error). If there any missing libraries
|
||||
being processed, they will not be considered on final nlist size
|
||||
passed on _dl_sort_maps later in the function. And it is then used by
|
||||
_dl_sort_maps_dfs on the stack allocated working maps:
|
||||
|
||||
222 /* Array to hold RPO sorting results, before we copy back to maps[]. */
|
||||
223 struct link_map *rpo[nmaps];
|
||||
224
|
||||
225 /* The 'head' position during each DFS iteration. Note that we start at
|
||||
226 one past the last element due to first-decrement-then-store (see the
|
||||
227 bottom of above dfs_traversal() routine). */
|
||||
228 struct link_map **rpo_head = &rpo[nmaps];
|
||||
|
||||
However while transversing the 'l_initfini' on dfs_traversal it will
|
||||
still consider the l_faked maps and thus update rpo more times than the
|
||||
allocated working 'rpo', overflowing the stack object.
|
||||
|
||||
As suggested in bugzilla, one option would be to avoid sorting the maps
|
||||
for trace mode. However I think ignoring l_faked object does make
|
||||
sense (there is one less constraint to call the sorting function), it
|
||||
allows a slight less stack usage for trace, and it is slight simpler
|
||||
solution.
|
||||
|
||||
The tests does trigger the stack overflow, however I tried to make
|
||||
it more generic to check different scenarios or missing objects.
|
||||
|
||||
Checked on x86_64-linux-gnu.
|
||||
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
(differences in backported tests)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 22a8060f7d3bb1a1..634c3113227d64a6 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -584,6 +584,11 @@ modules-names = \
|
||||
libmarkermod5-3 \
|
||||
libmarkermod5-4 \
|
||||
libmarkermod5-5 \
|
||||
+ libtracemod1-1 \
|
||||
+ libtracemod2-1 \
|
||||
+ libtracemod3-1 \
|
||||
+ libtracemod4-1 \
|
||||
+ libtracemod5-1 \
|
||||
ltglobmod1 \
|
||||
ltglobmod2 \
|
||||
neededobj1 \
|
||||
@@ -983,6 +988,11 @@ tests-special += \
|
||||
$(objpfx)tst-initorder2-cmp.out \
|
||||
$(objpfx)tst-unused-dep-cmp.out \
|
||||
$(objpfx)tst-unused-dep.out \
|
||||
+ $(objpfx)tst-trace1.out \
|
||||
+ $(objpfx)tst-trace2.out \
|
||||
+ $(objpfx)tst-trace3.out \
|
||||
+ $(objpfx)tst-trace4.out \
|
||||
+ $(objpfx)tst-trace5.out \
|
||||
# tests-special
|
||||
endif
|
||||
|
||||
@@ -2619,6 +2629,51 @@ $(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig
|
||||
|
||||
$(objpfx)tst-dlmopen-gethostbyname: $(libdl)
|
||||
$(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so
|
||||
+
|
||||
+LDFLAGS-libtracemod1-1.so += -Wl,-soname,libtracemod1.so
|
||||
+LDFLAGS-libtracemod2-1.so += -Wl,-soname,libtracemod2.so
|
||||
+LDFLAGS-libtracemod3-1.so += -Wl,-soname,libtracemod3.so
|
||||
+LDFLAGS-libtracemod4-1.so += -Wl,-soname,libtracemod4.so
|
||||
+LDFLAGS-libtracemod5-1.so += -Wl,-soname,libtracemod5.so
|
||||
+
|
||||
+$(objpfx)libtracemod1-1.so: $(objpfx)libtracemod2-1.so \
|
||||
+ $(objpfx)libtracemod3-1.so
|
||||
+$(objpfx)libtracemod2-1.so: $(objpfx)libtracemod4-1.so \
|
||||
+ $(objpfx)libtracemod5-1.so
|
||||
+
|
||||
+define libtracemod-x
|
||||
+$(objpfx)libtracemod$(1)/libtracemod$(1).so: $(objpfx)libtracemod$(1)-1.so
|
||||
+ $$(make-target-directory)
|
||||
+ cp $$< $$@
|
||||
+endef
|
||||
+libtracemod-suffixes = 1 2 3 4 5
|
||||
+$(foreach i,$(libtracemod-suffixes), $(eval $(call libtracemod-x,$(i))))
|
||||
+
|
||||
+define tst-trace-skeleton
|
||||
+$(objpfx)tst-trace$(1).out: $(objpfx)libtracemod1/libtracemod1.so \
|
||||
+ $(objpfx)libtracemod2/libtracemod2.so \
|
||||
+ $(objpfx)libtracemod3/libtracemod3.so \
|
||||
+ $(objpfx)libtracemod4/libtracemod4.so \
|
||||
+ $(objpfx)libtracemod5/libtracemod5.so \
|
||||
+ $(..)scripts/tst-ld-trace.py \
|
||||
+ tst-trace$(1).exp
|
||||
+ ${ $(PYTHON) $(..)scripts/tst-ld-trace.py \
|
||||
+ "$(test-wrapper-env) $(elf-objpfx)$(rtld-installed-name) \
|
||||
+ --library-path $(common-objpfx):$(strip $(2)) \
|
||||
+ $(objpfx)libtracemod1/libtracemod1.so" tst-trace$(1).exp \
|
||||
+ } > $$@; $$(evaluate-test)
|
||||
+endef
|
||||
+
|
||||
+$(eval $(call tst-trace-skeleton,1,))
|
||||
+$(eval $(call tst-trace-skeleton,2,\
|
||||
+ $(objpfx)libtracemod2))
|
||||
+$(eval $(call tst-trace-skeleton,3,\
|
||||
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3))
|
||||
+$(eval $(call tst-trace-skeleton,4,\
|
||||
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3:$(objpfx)libtracemod4))
|
||||
+$(eval $(call tst-trace-skeleton,5,\
|
||||
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3:$(objpfx)libtracemod4:$(objpfx)libtracemod5))
|
||||
+
|
||||
$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
$(objpfx)tst-audit-tlsdesc-mod2.so \
|
||||
$(shared-thread-library)
|
||||
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
|
||||
index 9365d54c8e03e5f4..9ff589c8562b2dd1 100644
|
||||
--- a/elf/dl-deps.c
|
||||
+++ b/elf/dl-deps.c
|
||||
@@ -489,6 +489,8 @@ _dl_map_object_deps (struct link_map *map,
|
||||
|
||||
for (nlist = 0, runp = known; runp; runp = runp->next)
|
||||
{
|
||||
+ /* _dl_sort_maps ignores l_faked object, so it is safe to not consider
|
||||
+ them for nlist. */
|
||||
if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
|
||||
/* This can happen when we trace the loading. */
|
||||
--map->l_searchlist.r_nlist;
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index 398a08f28c4d9ff1..99354dc08a010dd3 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -140,7 +140,9 @@ static void
|
||||
dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
bool *do_reldeps)
|
||||
{
|
||||
- if (map->l_visited)
|
||||
+ /* _dl_map_object_deps ignores l_faked objects when calculating the
|
||||
+ number of maps before calling _dl_sort_maps, ignore them as well. */
|
||||
+ if (map->l_visited || map->l_faked)
|
||||
return;
|
||||
|
||||
map->l_visited = 1;
|
||||
diff --git a/elf/libtracemod1-1.c b/elf/libtracemod1-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod1-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/libtracemod2-1.c b/elf/libtracemod2-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod2-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/libtracemod3-1.c b/elf/libtracemod3-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod3-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/libtracemod4-1.c b/elf/libtracemod4-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod4-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/libtracemod5-1.c b/elf/libtracemod5-1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7c89c9a5a40b9668
|
||||
--- /dev/null
|
||||
+++ b/elf/libtracemod5-1.c
|
||||
@@ -0,0 +1 @@
|
||||
+/* Empty */
|
||||
diff --git a/elf/tst-trace1.exp b/elf/tst-trace1.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..4a6f5211a68fe2c8
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace1.exp
|
||||
@@ -0,0 +1,4 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 0
|
||||
+libtracemod3.so 0
|
||||
diff --git a/elf/tst-trace2.exp b/elf/tst-trace2.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..e13506e2eb9aeca2
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace2.exp
|
||||
@@ -0,0 +1,6 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 1
|
||||
+libtracemod3.so 0
|
||||
+libtracemod4.so 0
|
||||
+libtracemod5.so 0
|
||||
diff --git a/elf/tst-trace3.exp b/elf/tst-trace3.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..e574549d12a53d72
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace3.exp
|
||||
@@ -0,0 +1,6 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 1
|
||||
+libtracemod3.so 1
|
||||
+libtracemod4.so 0
|
||||
+libtracemod5.so 0
|
||||
diff --git a/elf/tst-trace4.exp b/elf/tst-trace4.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..31ca97b35bde0009
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace4.exp
|
||||
@@ -0,0 +1,6 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 1
|
||||
+libtracemod3.so 1
|
||||
+libtracemod4.so 1
|
||||
+libtracemod5.so 0
|
||||
diff --git a/elf/tst-trace5.exp b/elf/tst-trace5.exp
|
||||
new file mode 100644
|
||||
index 0000000000000000..5d7d95372656396f
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-trace5.exp
|
||||
@@ -0,0 +1,6 @@
|
||||
+ld 1
|
||||
+libc 1
|
||||
+libtracemod2.so 1
|
||||
+libtracemod3.so 1
|
||||
+libtracemod4.so 1
|
||||
+libtracemod5.so 1
|
||||
diff --git a/scripts/tst-ld-trace.py b/scripts/tst-ld-trace.py
|
||||
new file mode 100755
|
||||
index 0000000000000000..f5a402800377f44b
|
||||
--- /dev/null
|
||||
+++ b/scripts/tst-ld-trace.py
|
||||
@@ -0,0 +1,108 @@
|
||||
+#!/usr/bin/python3
|
||||
+# Dump the output of LD_TRACE_LOADED_OBJECTS in architecture neutral format.
|
||||
+# Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
+# Copyright The GNU Toolchain Authors.
|
||||
+# 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 os
|
||||
+import subprocess
|
||||
+import sys
|
||||
+
|
||||
+try:
|
||||
+ subprocess.run
|
||||
+except:
|
||||
+ class _CompletedProcess:
|
||||
+ def __init__(self, args, returncode, stdout=None, stderr=None):
|
||||
+ self.args = args
|
||||
+ self.returncode = returncode
|
||||
+ self.stdout = stdout
|
||||
+ self.stderr = stderr
|
||||
+
|
||||
+ def _run(*popenargs, input=None, timeout=None, check=False, **kwargs):
|
||||
+ assert(timeout is None)
|
||||
+ with subprocess.Popen(*popenargs, **kwargs) as process:
|
||||
+ try:
|
||||
+ stdout, stderr = process.communicate(input)
|
||||
+ except:
|
||||
+ process.kill()
|
||||
+ process.wait()
|
||||
+ raise
|
||||
+ returncode = process.poll()
|
||||
+ if check and returncode:
|
||||
+ raise subprocess.CalledProcessError(returncode, popenargs)
|
||||
+ return _CompletedProcess(popenargs, returncode, stdout, stderr)
|
||||
+
|
||||
+ subprocess.run = _run
|
||||
+
|
||||
+def is_vdso(lib):
|
||||
+ return lib.startswith('linux-gate') or lib.startswith('linux-vdso')
|
||||
+
|
||||
+
|
||||
+def parse_trace(cmd, fref):
|
||||
+ new_env = os.environ.copy()
|
||||
+ new_env['LD_TRACE_LOADED_OBJECTS'] = '1'
|
||||
+ trace_out = subprocess.run(cmd, stdout=subprocess.PIPE, check=True,
|
||||
+ universal_newlines=True, env=new_env).stdout
|
||||
+ trace = []
|
||||
+ for line in trace_out.splitlines():
|
||||
+ line = line.strip()
|
||||
+ if is_vdso(line):
|
||||
+ continue
|
||||
+ fields = line.split('=>' if '=>' in line else ' ')
|
||||
+ lib = os.path.basename(fields[0].strip())
|
||||
+ if lib.startswith('ld'):
|
||||
+ lib = 'ld'
|
||||
+ elif lib.startswith('libc'):
|
||||
+ lib = 'libc'
|
||||
+ found = 1 if fields[1].strip() != 'not found' else 0
|
||||
+ trace += ['{} {}'.format(lib, found)]
|
||||
+ trace = sorted(trace)
|
||||
+
|
||||
+ reference = sorted(line.replace('\n','') for line in fref.readlines())
|
||||
+
|
||||
+ ret = 0 if trace == reference else 1
|
||||
+ if ret != 0:
|
||||
+ for i in reference:
|
||||
+ if i not in trace:
|
||||
+ print("Only in {}: {}".format(fref.name, i))
|
||||
+ for i in trace:
|
||||
+ if i not in reference:
|
||||
+ print("Only in trace: {}".format(i))
|
||||
+
|
||||
+ sys.exit(ret)
|
||||
+
|
||||
+
|
||||
+def get_parser():
|
||||
+ parser = argparse.ArgumentParser(description=__doc__)
|
||||
+ parser.add_argument('command',
|
||||
+ help='comand to run')
|
||||
+ parser.add_argument('reference',
|
||||
+ help='reference file to compare')
|
||||
+ return parser
|
||||
+
|
||||
+
|
||||
+def main(argv):
|
||||
+ parser = get_parser()
|
||||
+ opts = parser.parse_args(argv)
|
||||
+ with open(opts.reference, 'r') as fref:
|
||||
+ # Remove the initial 'env' command.
|
||||
+ parse_trace(opts.command.split()[1:], fref)
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ main(sys.argv[1:])
|
36
SOURCES/glibc-rh1159809-8.patch
Normal file
36
SOURCES/glibc-rh1159809-8.patch
Normal file
@ -0,0 +1,36 @@
|
||||
commit a2211c76c3b994099fd58a06d6072d7495d699cd
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Mar 18 18:18:35 2022 +0100
|
||||
|
||||
scripts/dso-ordering-test.py: Fix C&P error in * callrefs processing
|
||||
|
||||
The elf/dso-sort-tests-src subdirectory is not changed by this commit,
|
||||
so it seems that the cut-and-paste error was not material.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||||
index bde0406be9da14fc..ee476c810c76f1b0 100644
|
||||
--- a/scripts/dso-ordering-test.py
|
||||
+++ b/scripts/dso-ordering-test.py
|
||||
@@ -551,17 +551,17 @@ def process_testcase(t):
|
||||
if obj in t.deps:
|
||||
deps = t.deps[obj]
|
||||
if '*' in deps:
|
||||
- t.deps[obj].remove('*')
|
||||
+ deps.remove('*')
|
||||
t.add_deps([obj], non_dep_tgt_objs)
|
||||
if obj in t.callrefs:
|
||||
deps = t.callrefs[obj]
|
||||
if '*' in deps:
|
||||
- t.deps[obj].remove('*')
|
||||
+ deps.remove('*')
|
||||
t.add_callrefs([obj], non_dep_tgt_objs)
|
||||
if "#" in t.deps:
|
||||
deps = t.deps["#"]
|
||||
if '*' in deps:
|
||||
- t.deps["#"].remove('*')
|
||||
+ deps.remove('*')
|
||||
t.add_deps(["#"], non_dep_tgt_objs)
|
||||
|
||||
# If no main program was specified in dependency description, make a
|
37
SOURCES/glibc-rh1159809-9.patch
Normal file
37
SOURCES/glibc-rh1159809-9.patch
Normal file
@ -0,0 +1,37 @@
|
||||
commit 183d99737298bb3200f0610fdcd1c7549c8ed560
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Sep 6 07:38:10 2022 +0200
|
||||
|
||||
scripts/dso-ordering-test.py: Generate program run-time dependencies
|
||||
|
||||
The main program needs to depend on all shared objects, even objects
|
||||
that have link-time dependencies among shared objects. Filtering
|
||||
out shared objects that already have an link-time dependencies is not
|
||||
necessary here; make will do this automatically.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
|
||||
index ee476c810c76f1b0..43b5ec4d920ad6a3 100644
|
||||
--- a/scripts/dso-ordering-test.py
|
||||
+++ b/scripts/dso-ordering-test.py
|
||||
@@ -707,13 +707,12 @@ def process_testcase(t):
|
||||
"\t$(compile.c) $(OUTPUT_OPTION)\n")
|
||||
makefile.write (rule)
|
||||
|
||||
- not_depended_objs = find_objs_not_depended_on(test_descr)
|
||||
- if not_depended_objs:
|
||||
- depstr = ""
|
||||
- for dep in not_depended_objs:
|
||||
- depstr += (" $(objpfx)" + test_subdir + "/"
|
||||
- + test_name + "-" + dep + ".so")
|
||||
- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr))
|
||||
+ # Ensure that all shared objects are built before running the
|
||||
+ # test, whether there link-time dependencies or not.
|
||||
+ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep)
|
||||
+ for dep in test_descr.objs]
|
||||
+ makefile.write("$(objpfx){}.out: {}\n".format(
|
||||
+ base_test_name, " ".join(depobjs)))
|
||||
|
||||
# Add main executable to test-srcs
|
||||
makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name))
|
245
SOURCES/glibc-rh1871383-1.patch
Normal file
245
SOURCES/glibc-rh1871383-1.patch
Normal file
@ -0,0 +1,245 @@
|
||||
From a1a486d70ebcc47a686ff5846875eacad0940e41 Mon Sep 17 00:00:00 2001
|
||||
From: Eyal Itkin <eyalit@checkpoint.com>
|
||||
Date: Fri, 20 Mar 2020 21:19:17 +0200
|
||||
Subject: Add Safe-Linking to fastbins and tcache
|
||||
|
||||
Safe-Linking is a security mechanism that protects single-linked
|
||||
lists (such as the fastbin and tcache) from being tampered by attackers.
|
||||
The mechanism makes use of randomness from ASLR (mmap_base), and when
|
||||
combined with chunk alignment integrity checks, it protects the "next"
|
||||
pointers from being hijacked by an attacker.
|
||||
|
||||
While Safe-Unlinking protects double-linked lists (such as the small
|
||||
bins), there wasn't any similar protection for attacks against
|
||||
single-linked lists. This solution protects against 3 common attacks:
|
||||
* Partial pointer override: modifies the lower bytes (Little Endian)
|
||||
* Full pointer override: hijacks the pointer to an attacker's location
|
||||
* Unaligned chunks: pointing the list to an unaligned address
|
||||
|
||||
The design assumes an attacker doesn't know where the heap is located,
|
||||
and uses the ASLR randomness to "sign" the single-linked pointers. We
|
||||
mark the pointer as P and the location in which it is stored as L, and
|
||||
the calculation will be:
|
||||
* PROTECT(P) := (L >> PAGE_SHIFT) XOR (P)
|
||||
* *L = PROTECT(P)
|
||||
|
||||
This way, the random bits from the address L (which start at the bit
|
||||
in the PAGE_SHIFT position), will be merged with LSB of the stored
|
||||
protected pointer. This protection layer prevents an attacker from
|
||||
modifying the pointer into a controlled value.
|
||||
|
||||
An additional check that the chunks are MALLOC_ALIGNed adds an
|
||||
important layer:
|
||||
* Attackers can't point to illegal (unaligned) memory addresses
|
||||
* Attackers must guess correctly the alignment bits
|
||||
|
||||
On standard 32 bit Linux machines, an attack will directly fail 7
|
||||
out of 8 times, and on 64 bit machines it will fail 15 out of 16
|
||||
times.
|
||||
|
||||
This proposed patch was benchmarked and it's effect on the overall
|
||||
performance of the heap was negligible and couldn't be distinguished
|
||||
from the default variance between tests on the vanilla version. A
|
||||
similar protection was added to Chromium's version of TCMalloc
|
||||
in 2012, and according to their documentation it had an overhead of
|
||||
less than 2%.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Reviewed-by: Adhemerval Zacnella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index f7cd29bc2f..1282863681 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -327,6 +327,18 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line,
|
||||
# define MAX_TCACHE_COUNT UINT16_MAX
|
||||
#endif
|
||||
|
||||
+/* Safe-Linking:
|
||||
+ Use randomness from ASLR (mmap_base) to protect single-linked lists
|
||||
+ of Fast-Bins and TCache. That is, mask the "next" pointers of the
|
||||
+ lists' chunks, and also perform allocation alignment checks on them.
|
||||
+ This mechanism reduces the risk of pointer hijacking, as was done with
|
||||
+ Safe-Unlinking in the double-linked lists of Small-Bins.
|
||||
+ It assumes a minimum page size of 4096 bytes (12 bits). Systems with
|
||||
+ larger pages provide less entropy, although the pointer mangling
|
||||
+ still works. */
|
||||
+#define PROTECT_PTR(pos, ptr) \
|
||||
+ ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
|
||||
+#define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr)
|
||||
|
||||
/*
|
||||
REALLOC_ZERO_BYTES_FREES should be set if a call to
|
||||
@@ -2157,12 +2169,15 @@ do_check_malloc_state (mstate av)
|
||||
|
||||
while (p != 0)
|
||||
{
|
||||
+ if (__glibc_unlikely (!aligned_OK (p)))
|
||||
+ malloc_printerr ("do_check_malloc_state(): " \
|
||||
+ "unaligned fastbin chunk detected");
|
||||
/* each chunk claims to be inuse */
|
||||
do_check_inuse_chunk (av, p);
|
||||
total += chunksize (p);
|
||||
/* chunk belongs in this bin */
|
||||
assert (fastbin_index (chunksize (p)) == i);
|
||||
- p = p->fd;
|
||||
+ p = REVEAL_PTR (p->fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2923,7 +2938,7 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
|
||||
detect a double free. */
|
||||
e->key = tcache;
|
||||
|
||||
- e->next = tcache->entries[tc_idx];
|
||||
+ e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]);
|
||||
tcache->entries[tc_idx] = e;
|
||||
++(tcache->counts[tc_idx]);
|
||||
}
|
||||
@@ -2934,9 +2949,11 @@ static __always_inline void *
|
||||
tcache_get (size_t tc_idx)
|
||||
{
|
||||
tcache_entry *e = tcache->entries[tc_idx];
|
||||
- tcache->entries[tc_idx] = e->next;
|
||||
+ tcache->entries[tc_idx] = REVEAL_PTR (e->next);
|
||||
--(tcache->counts[tc_idx]);
|
||||
e->key = NULL;
|
||||
+ if (__glibc_unlikely (!aligned_OK (e)))
|
||||
+ malloc_printerr ("malloc(): unaligned tcache chunk detected");
|
||||
return (void *) e;
|
||||
}
|
||||
|
||||
@@ -2960,7 +2977,10 @@ tcache_thread_shutdown (void)
|
||||
while (tcache_tmp->entries[i])
|
||||
{
|
||||
tcache_entry *e = tcache_tmp->entries[i];
|
||||
- tcache_tmp->entries[i] = e->next;
|
||||
+ if (__glibc_unlikely (!aligned_OK (e)))
|
||||
+ malloc_printerr ("tcache_thread_shutdown(): " \
|
||||
+ "unaligned tcache chunk detected");
|
||||
+ tcache_tmp->entries[i] = REVEAL_PTR (e->next);
|
||||
__libc_free (e);
|
||||
}
|
||||
}
|
||||
@@ -3570,8 +3590,11 @@ _int_malloc (mstate av, size_t bytes)
|
||||
victim = pp; \
|
||||
if (victim == NULL) \
|
||||
break; \
|
||||
+ pp = REVEAL_PTR (victim->fd); \
|
||||
+ if (__glibc_unlikely (!aligned_OK (pp))) \
|
||||
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected"); \
|
||||
} \
|
||||
- while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) \
|
||||
+ while ((pp = catomic_compare_and_exchange_val_acq (fb, pp, victim)) \
|
||||
!= victim); \
|
||||
|
||||
if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
|
||||
@@ -3583,8 +3606,11 @@ _int_malloc (mstate av, size_t bytes)
|
||||
|
||||
if (victim != NULL)
|
||||
{
|
||||
+ if (__glibc_unlikely (!aligned_OK (victim)))
|
||||
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected");
|
||||
+
|
||||
if (SINGLE_THREAD_P)
|
||||
- *fb = victim->fd;
|
||||
+ *fb = REVEAL_PTR (victim->fd);
|
||||
else
|
||||
REMOVE_FB (fb, pp, victim);
|
||||
if (__glibc_likely (victim != NULL))
|
||||
@@ -3605,8 +3631,10 @@ _int_malloc (mstate av, size_t bytes)
|
||||
while (tcache->counts[tc_idx] < mp_.tcache_count
|
||||
&& (tc_victim = *fb) != NULL)
|
||||
{
|
||||
+ if (__glibc_unlikely (!aligned_OK (tc_victim)))
|
||||
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected");
|
||||
if (SINGLE_THREAD_P)
|
||||
- *fb = tc_victim->fd;
|
||||
+ *fb = REVEAL_PTR (tc_victim->fd);
|
||||
else
|
||||
{
|
||||
REMOVE_FB (fb, pp, tc_victim);
|
||||
@@ -4196,11 +4224,15 @@ _int_free (mstate av, mchunkptr p, int have_lock)
|
||||
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
|
||||
for (tmp = tcache->entries[tc_idx];
|
||||
tmp;
|
||||
- tmp = tmp->next)
|
||||
+ tmp = REVEAL_PTR (tmp->next))
|
||||
+ {
|
||||
+ if (__glibc_unlikely (!aligned_OK (tmp)))
|
||||
+ malloc_printerr ("free(): unaligned chunk detected in tcache 2");
|
||||
if (tmp == e)
|
||||
malloc_printerr ("free(): double free detected in tcache 2");
|
||||
/* If we get here, it was a coincidence. We've wasted a
|
||||
few cycles, but don't abort. */
|
||||
+ }
|
||||
}
|
||||
|
||||
if (tcache->counts[tc_idx] < mp_.tcache_count)
|
||||
@@ -4264,7 +4296,7 @@ _int_free (mstate av, mchunkptr p, int have_lock)
|
||||
add (i.e., double free). */
|
||||
if (__builtin_expect (old == p, 0))
|
||||
malloc_printerr ("double free or corruption (fasttop)");
|
||||
- p->fd = old;
|
||||
+ p->fd = PROTECT_PTR (&p->fd, old);
|
||||
*fb = p;
|
||||
}
|
||||
else
|
||||
@@ -4274,7 +4306,8 @@ _int_free (mstate av, mchunkptr p, int have_lock)
|
||||
add (i.e., double free). */
|
||||
if (__builtin_expect (old == p, 0))
|
||||
malloc_printerr ("double free or corruption (fasttop)");
|
||||
- p->fd = old2 = old;
|
||||
+ old2 = old;
|
||||
+ p->fd = PROTECT_PTR (&p->fd, old);
|
||||
}
|
||||
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))
|
||||
!= old2);
|
||||
@@ -4472,13 +4505,17 @@ static void malloc_consolidate(mstate av)
|
||||
if (p != 0) {
|
||||
do {
|
||||
{
|
||||
+ if (__glibc_unlikely (!aligned_OK (p)))
|
||||
+ malloc_printerr ("malloc_consolidate(): " \
|
||||
+ "unaligned fastbin chunk detected");
|
||||
+
|
||||
unsigned int idx = fastbin_index (chunksize (p));
|
||||
if ((&fastbin (av, idx)) != fb)
|
||||
malloc_printerr ("malloc_consolidate(): invalid chunk size");
|
||||
}
|
||||
|
||||
check_inuse_chunk(av, p);
|
||||
- nextp = p->fd;
|
||||
+ nextp = REVEAL_PTR (p->fd);
|
||||
|
||||
/* Slightly streamlined version of consolidation code in free() */
|
||||
size = chunksize (p);
|
||||
@@ -4896,8 +4933,13 @@ int_mallinfo (mstate av, struct mallinfo *m)
|
||||
|
||||
for (i = 0; i < NFASTBINS; ++i)
|
||||
{
|
||||
- for (p = fastbin (av, i); p != 0; p = p->fd)
|
||||
+ for (p = fastbin (av, i);
|
||||
+ p != 0;
|
||||
+ p = REVEAL_PTR (p->fd))
|
||||
{
|
||||
+ if (__glibc_unlikely (!aligned_OK (p)))
|
||||
+ malloc_printerr ("int_mallinfo(): " \
|
||||
+ "unaligned fastbin chunk detected");
|
||||
++nfastblocks;
|
||||
fastavail += chunksize (p);
|
||||
}
|
||||
@@ -5437,8 +5479,11 @@ __malloc_info (int options, FILE *fp)
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
+ if (__glibc_unlikely (!aligned_OK (p)))
|
||||
+ malloc_printerr ("__malloc_info(): " \
|
||||
+ "unaligned fastbin chunk detected");
|
||||
++nthissize;
|
||||
- p = p->fd;
|
||||
+ p = REVEAL_PTR (p->fd);
|
||||
}
|
||||
|
||||
fastavail += nthissize * thissize;
|
87
SOURCES/glibc-rh1871383-2.patch
Normal file
87
SOURCES/glibc-rh1871383-2.patch
Normal file
@ -0,0 +1,87 @@
|
||||
From 768358b6a80742f6be68ecd9f952f4b60614df96 Mon Sep 17 00:00:00 2001
|
||||
From: Eyal Itkin <eyalit@checkpoint.com>
|
||||
Date: Tue, 31 Mar 2020 01:55:13 -0400
|
||||
Subject: Typo fixes and CR cleanup in Safe-Linking
|
||||
|
||||
Removed unneeded '\' chars from end of lines and fixed some
|
||||
indentation issues that were introduced in the original
|
||||
Safe-Linking patch.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index 1282863681..0e4acb22f6 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -2170,7 +2170,7 @@ do_check_malloc_state (mstate av)
|
||||
while (p != 0)
|
||||
{
|
||||
if (__glibc_unlikely (!aligned_OK (p)))
|
||||
- malloc_printerr ("do_check_malloc_state(): " \
|
||||
+ malloc_printerr ("do_check_malloc_state(): "
|
||||
"unaligned fastbin chunk detected");
|
||||
/* each chunk claims to be inuse */
|
||||
do_check_inuse_chunk (av, p);
|
||||
@@ -2977,9 +2977,9 @@ tcache_thread_shutdown (void)
|
||||
while (tcache_tmp->entries[i])
|
||||
{
|
||||
tcache_entry *e = tcache_tmp->entries[i];
|
||||
- if (__glibc_unlikely (!aligned_OK (e)))
|
||||
- malloc_printerr ("tcache_thread_shutdown(): " \
|
||||
- "unaligned tcache chunk detected");
|
||||
+ if (__glibc_unlikely (!aligned_OK (e)))
|
||||
+ malloc_printerr ("tcache_thread_shutdown(): "
|
||||
+ "unaligned tcache chunk detected");
|
||||
tcache_tmp->entries[i] = REVEAL_PTR (e->next);
|
||||
__libc_free (e);
|
||||
}
|
||||
@@ -4225,14 +4225,14 @@ _int_free (mstate av, mchunkptr p, int have_lock)
|
||||
for (tmp = tcache->entries[tc_idx];
|
||||
tmp;
|
||||
tmp = REVEAL_PTR (tmp->next))
|
||||
- {
|
||||
- if (__glibc_unlikely (!aligned_OK (tmp)))
|
||||
- malloc_printerr ("free(): unaligned chunk detected in tcache 2");
|
||||
- if (tmp == e)
|
||||
- malloc_printerr ("free(): double free detected in tcache 2");
|
||||
- /* If we get here, it was a coincidence. We've wasted a
|
||||
- few cycles, but don't abort. */
|
||||
- }
|
||||
+ {
|
||||
+ if (__glibc_unlikely (!aligned_OK (tmp)))
|
||||
+ malloc_printerr ("free(): unaligned chunk detected in tcache 2");
|
||||
+ if (tmp == e)
|
||||
+ malloc_printerr ("free(): double free detected in tcache 2");
|
||||
+ /* If we get here, it was a coincidence. We've wasted a
|
||||
+ few cycles, but don't abort. */
|
||||
+ }
|
||||
}
|
||||
|
||||
if (tcache->counts[tc_idx] < mp_.tcache_count)
|
||||
@@ -4506,7 +4506,7 @@ static void malloc_consolidate(mstate av)
|
||||
do {
|
||||
{
|
||||
if (__glibc_unlikely (!aligned_OK (p)))
|
||||
- malloc_printerr ("malloc_consolidate(): " \
|
||||
+ malloc_printerr ("malloc_consolidate(): "
|
||||
"unaligned fastbin chunk detected");
|
||||
|
||||
unsigned int idx = fastbin_index (chunksize (p));
|
||||
@@ -4938,7 +4938,7 @@ int_mallinfo (mstate av, struct mallinfo *m)
|
||||
p = REVEAL_PTR (p->fd))
|
||||
{
|
||||
if (__glibc_unlikely (!aligned_OK (p)))
|
||||
- malloc_printerr ("int_mallinfo(): " \
|
||||
+ malloc_printerr ("int_mallinfo(): "
|
||||
"unaligned fastbin chunk detected");
|
||||
++nfastblocks;
|
||||
fastavail += chunksize (p);
|
||||
@@ -5480,7 +5480,7 @@ __malloc_info (int options, FILE *fp)
|
||||
while (p != NULL)
|
||||
{
|
||||
if (__glibc_unlikely (!aligned_OK (p)))
|
||||
- malloc_printerr ("__malloc_info(): " \
|
||||
+ malloc_printerr ("__malloc_info(): "
|
||||
"unaligned fastbin chunk detected");
|
||||
++nthissize;
|
||||
p = REVEAL_PTR (p->fd);
|
100
SOURCES/glibc-rh1871383-3.patch
Normal file
100
SOURCES/glibc-rh1871383-3.patch
Normal file
@ -0,0 +1,100 @@
|
||||
From 49c3c37651e2d2ec4ff8ce21252bbbc08a9d6639 Mon Sep 17 00:00:00 2001
|
||||
From: Eyal Itkin <eyalit@checkpoint.com>
|
||||
Date: Tue, 31 Mar 2020 02:00:14 -0400
|
||||
Subject: Fix alignment bug in Safe-Linking
|
||||
|
||||
Alignment checks should be performed on the user's buffer and NOT
|
||||
on the mchunkptr as was done before. This caused bugs in 32 bit
|
||||
versions, because: 2*sizeof(t) != MALLOC_ALIGNMENT.
|
||||
|
||||
As the tcache works on users' buffers it uses the aligned_OK()
|
||||
check, and the rest work on mchunkptr and therefore check using
|
||||
misaligned_chunk().
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index 0e4acb22f6..6acb5ad43a 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -2169,7 +2169,7 @@ do_check_malloc_state (mstate av)
|
||||
|
||||
while (p != 0)
|
||||
{
|
||||
- if (__glibc_unlikely (!aligned_OK (p)))
|
||||
+ if (__glibc_unlikely (misaligned_chunk (p)))
|
||||
malloc_printerr ("do_check_malloc_state(): "
|
||||
"unaligned fastbin chunk detected");
|
||||
/* each chunk claims to be inuse */
|
||||
@@ -2949,11 +2949,11 @@ static __always_inline void *
|
||||
tcache_get (size_t tc_idx)
|
||||
{
|
||||
tcache_entry *e = tcache->entries[tc_idx];
|
||||
+ if (__glibc_unlikely (!aligned_OK (e)))
|
||||
+ malloc_printerr ("malloc(): unaligned tcache chunk detected");
|
||||
tcache->entries[tc_idx] = REVEAL_PTR (e->next);
|
||||
--(tcache->counts[tc_idx]);
|
||||
e->key = NULL;
|
||||
- if (__glibc_unlikely (!aligned_OK (e)))
|
||||
- malloc_printerr ("malloc(): unaligned tcache chunk detected");
|
||||
return (void *) e;
|
||||
}
|
||||
|
||||
@@ -3591,7 +3591,7 @@ _int_malloc (mstate av, size_t bytes)
|
||||
if (victim == NULL) \
|
||||
break; \
|
||||
pp = REVEAL_PTR (victim->fd); \
|
||||
- if (__glibc_unlikely (!aligned_OK (pp))) \
|
||||
+ if (__glibc_unlikely (pp != NULL && misaligned_chunk (pp))) \
|
||||
malloc_printerr ("malloc(): unaligned fastbin chunk detected"); \
|
||||
} \
|
||||
while ((pp = catomic_compare_and_exchange_val_acq (fb, pp, victim)) \
|
||||
@@ -3606,8 +3606,8 @@ _int_malloc (mstate av, size_t bytes)
|
||||
|
||||
if (victim != NULL)
|
||||
{
|
||||
- if (__glibc_unlikely (!aligned_OK (victim)))
|
||||
- malloc_printerr ("malloc(): unaligned fastbin chunk detected");
|
||||
+ if (__glibc_unlikely (misaligned_chunk (victim)))
|
||||
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected 2");
|
||||
|
||||
if (SINGLE_THREAD_P)
|
||||
*fb = REVEAL_PTR (victim->fd);
|
||||
@@ -3631,8 +3631,8 @@ _int_malloc (mstate av, size_t bytes)
|
||||
while (tcache->counts[tc_idx] < mp_.tcache_count
|
||||
&& (tc_victim = *fb) != NULL)
|
||||
{
|
||||
- if (__glibc_unlikely (!aligned_OK (tc_victim)))
|
||||
- malloc_printerr ("malloc(): unaligned fastbin chunk detected");
|
||||
+ if (__glibc_unlikely (misaligned_chunk (tc_victim)))
|
||||
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected 3");
|
||||
if (SINGLE_THREAD_P)
|
||||
*fb = REVEAL_PTR (tc_victim->fd);
|
||||
else
|
||||
@@ -4505,7 +4505,7 @@ static void malloc_consolidate(mstate av)
|
||||
if (p != 0) {
|
||||
do {
|
||||
{
|
||||
- if (__glibc_unlikely (!aligned_OK (p)))
|
||||
+ if (__glibc_unlikely (misaligned_chunk (p)))
|
||||
malloc_printerr ("malloc_consolidate(): "
|
||||
"unaligned fastbin chunk detected");
|
||||
|
||||
@@ -4937,7 +4937,7 @@ int_mallinfo (mstate av, struct mallinfo *m)
|
||||
p != 0;
|
||||
p = REVEAL_PTR (p->fd))
|
||||
{
|
||||
- if (__glibc_unlikely (!aligned_OK (p)))
|
||||
+ if (__glibc_unlikely (misaligned_chunk (p)))
|
||||
malloc_printerr ("int_mallinfo(): "
|
||||
"unaligned fastbin chunk detected");
|
||||
++nfastblocks;
|
||||
@@ -5479,7 +5479,7 @@ __malloc_info (int options, FILE *fp)
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
- if (__glibc_unlikely (!aligned_OK (p)))
|
||||
+ if (__glibc_unlikely (misaligned_chunk (p)))
|
||||
malloc_printerr ("__malloc_info(): "
|
||||
"unaligned fastbin chunk detected");
|
||||
++nthissize;
|
215
SOURCES/glibc-rh1871383-4.patch
Normal file
215
SOURCES/glibc-rh1871383-4.patch
Normal file
@ -0,0 +1,215 @@
|
||||
From 6310d570bf20348135d09e1f9de84a9ae7d06f83 Mon Sep 17 00:00:00 2001
|
||||
From: Eyal Itkin <eyalit@checkpoint.com>
|
||||
Date: Thu, 2 Apr 2020 07:26:35 -0400
|
||||
Subject: Add tests for Safe-Linking
|
||||
|
||||
Adding the test "tst-safe-linking" for testing that Safe-Linking works
|
||||
as expected. The test checks these 3 main flows:
|
||||
* tcache protection
|
||||
* fastbin protection
|
||||
* malloc_consolidate() correctness
|
||||
|
||||
As there is a random chance of 1/16 that of the alignment will remain
|
||||
correct, the test checks each flow up to 10 times, using different random
|
||||
values for the pointer corruption. As a result, the chance for a false
|
||||
failure of a given tested flow is 2**(-40), thus highly unlikely.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/malloc/Makefile b/malloc/Makefile
|
||||
index 984045b5b9..e22cbde22d 100644
|
||||
--- a/malloc/Makefile
|
||||
+++ b/malloc/Makefile
|
||||
@@ -39,6 +39,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
|
||||
tst-malloc-too-large \
|
||||
tst-malloc-stats-cancellation \
|
||||
tst-tcfree1 tst-tcfree2 tst-tcfree3 \
|
||||
+ tst-safe-linking \
|
||||
|
||||
tests-static := \
|
||||
tst-interpose-static-nothread \
|
||||
diff --git a/malloc/tst-safe-linking.c b/malloc/tst-safe-linking.c
|
||||
new file mode 100644
|
||||
index 0000000000..067b6c09cf
|
||||
--- /dev/null
|
||||
+++ b/malloc/tst-safe-linking.c
|
||||
@@ -0,0 +1,179 @@
|
||||
+/* Test reporting of Safe-Linking caught errors.
|
||||
+ Copyright (C) 2020 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/>. */
|
||||
+
|
||||
+#include <signal.h>
|
||||
+#include <stdint.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <memory.h>
|
||||
+#include <string.h>
|
||||
+#include <time.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <support/capture_subprocess.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+/* Run CALLBACK and check that the data on standard error equals
|
||||
+ EXPECTED. */
|
||||
+static void
|
||||
+check (const char *test, void (*callback) (void *),
|
||||
+ const char *expected)
|
||||
+{
|
||||
+ int i, rand_mask;
|
||||
+ bool success = false;
|
||||
+ /* There is a chance of 1/16 that a corrupted pointer will be aligned.
|
||||
+ Try multiple times so that statistical failure will be improbable. */
|
||||
+ for (i = 0; i < 10 && !success; ++i)
|
||||
+ {
|
||||
+ rand_mask = rand () & 0xFF;
|
||||
+ struct support_capture_subprocess result
|
||||
+ = support_capture_subprocess (callback, &rand_mask);
|
||||
+ /* Did not crash, could happen. Try again. */
|
||||
+ if (strlen (result.err.buffer) == 0)
|
||||
+ continue;
|
||||
+ /* Crashed, must be the expected result. */
|
||||
+ if (strcmp (result.err.buffer, expected) != 0)
|
||||
+ {
|
||||
+ support_record_failure ();
|
||||
+ printf ("error: test %s unexpected standard error data\n"
|
||||
+ " expected: %s\n"
|
||||
+ " actual: %s\n",
|
||||
+ test, expected, result.err.buffer);
|
||||
+ }
|
||||
+ TEST_VERIFY (WIFSIGNALED (result.status));
|
||||
+ if (WIFSIGNALED (result.status))
|
||||
+ TEST_VERIFY (WTERMSIG (result.status) == SIGABRT);
|
||||
+ support_capture_subprocess_free (&result);
|
||||
+ success = true;
|
||||
+ }
|
||||
+ TEST_VERIFY (success);
|
||||
+}
|
||||
+
|
||||
+/* Implementation details must be kept in sync with malloc. */
|
||||
+#define TCACHE_FILL_COUNT 7
|
||||
+#define TCACHE_ALLOC_SIZE 0x20
|
||||
+#define MALLOC_CONSOLIDATE_SIZE 256*1024
|
||||
+
|
||||
+/* Try corrupting the tcache list. */
|
||||
+static void
|
||||
+test_tcache (void *closure)
|
||||
+{
|
||||
+ int mask = ((int *)closure)[0];
|
||||
+ size_t size = TCACHE_ALLOC_SIZE;
|
||||
+
|
||||
+ /* Populate the tcache list. */
|
||||
+ void * volatile a = malloc (size);
|
||||
+ void * volatile b = malloc (size);
|
||||
+ void * volatile c = malloc (size);
|
||||
+ free (a);
|
||||
+ free (b);
|
||||
+ free (c);
|
||||
+
|
||||
+ /* Corrupt the pointer with a random value, and avoid optimizations. */
|
||||
+ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
|
||||
+ memset (c, mask & 0xFF, size);
|
||||
+ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
|
||||
+
|
||||
+ c = malloc (size);
|
||||
+ /* This line will trigger the Safe-Linking check. */
|
||||
+ b = malloc (size);
|
||||
+ printf ("b=%p\n", b);
|
||||
+}
|
||||
+
|
||||
+/* Try corrupting the fastbin list. */
|
||||
+static void
|
||||
+test_fastbin (void *closure)
|
||||
+{
|
||||
+ int i;
|
||||
+ int mask = ((int *)closure)[0];
|
||||
+ size_t size = TCACHE_ALLOC_SIZE;
|
||||
+
|
||||
+ /* Take the tcache out of the game. */
|
||||
+ for (i = 0; i < TCACHE_FILL_COUNT; ++i)
|
||||
+ {
|
||||
+ void * volatile p = calloc (1, size);
|
||||
+ free (p);
|
||||
+ }
|
||||
+
|
||||
+ /* Populate the fastbin list. */
|
||||
+ void * volatile a = calloc (1, size);
|
||||
+ void * volatile b = calloc (1, size);
|
||||
+ void * volatile c = calloc (1, size);
|
||||
+ free (a);
|
||||
+ free (b);
|
||||
+ free (c);
|
||||
+
|
||||
+ /* Corrupt the pointer with a random value, and avoid optimizations. */
|
||||
+ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
|
||||
+ memset (c, mask & 0xFF, size);
|
||||
+ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
|
||||
+
|
||||
+ c = calloc (1, size);
|
||||
+ /* This line will trigger the Safe-Linking check. */
|
||||
+ b = calloc (1, size);
|
||||
+ printf ("b=%p\n", b);
|
||||
+}
|
||||
+
|
||||
+/* Try corrupting the fastbin list and trigger a consolidate. */
|
||||
+static void
|
||||
+test_fastbin_consolidate (void *closure)
|
||||
+{
|
||||
+ int i;
|
||||
+ int mask = ((int*)closure)[0];
|
||||
+ size_t size = TCACHE_ALLOC_SIZE;
|
||||
+
|
||||
+ /* Take the tcache out of the game. */
|
||||
+ for (i = 0; i < TCACHE_FILL_COUNT; ++i)
|
||||
+ {
|
||||
+ void * volatile p = calloc (1, size);
|
||||
+ free (p);
|
||||
+ }
|
||||
+
|
||||
+ /* Populate the fastbin list. */
|
||||
+ void * volatile a = calloc (1, size);
|
||||
+ void * volatile b = calloc (1, size);
|
||||
+ void * volatile c = calloc (1, size);
|
||||
+ free (a);
|
||||
+ free (b);
|
||||
+ free (c);
|
||||
+
|
||||
+ /* Corrupt the pointer with a random value, and avoid optimizations. */
|
||||
+ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
|
||||
+ memset (c, mask & 0xFF, size);
|
||||
+ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
|
||||
+
|
||||
+ /* This line will trigger the Safe-Linking check. */
|
||||
+ b = malloc (MALLOC_CONSOLIDATE_SIZE);
|
||||
+ printf ("b=%p\n", b);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* Seed the random for the test. */
|
||||
+ srand (time (NULL));
|
||||
+
|
||||
+ check ("test_tcache", test_tcache,
|
||||
+ "malloc(): unaligned tcache chunk detected\n");
|
||||
+ check ("test_fastbin", test_fastbin,
|
||||
+ "malloc(): unaligned fastbin chunk detected 2\n");
|
||||
+ check ("test_fastbin_consolidate", test_fastbin_consolidate,
|
||||
+ "malloc_consolidate(): unaligned fastbin chunk detected\n");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
35
SOURCES/glibc-rh1871383-5.patch
Normal file
35
SOURCES/glibc-rh1871383-5.patch
Normal file
@ -0,0 +1,35 @@
|
||||
From b9cde4e3aa1ff338da7064daf1386b2f4a7351ba Mon Sep 17 00:00:00 2001
|
||||
From: DJ Delorie <dj@redhat.com>
|
||||
Date: Sat, 4 Apr 2020 01:44:56 -0400
|
||||
Subject: malloc: ensure set_max_fast never stores zero [BZ #25733]
|
||||
|
||||
The code for set_max_fast() stores an "impossibly small value"
|
||||
instead of zero, when the parameter is zero. However, for
|
||||
small values of the parameter (ex: 1 or 2) the computation
|
||||
results in a zero being stored anyway.
|
||||
|
||||
This patch checks for the parameter being small enough for the
|
||||
computation to result in zero instead, so that a zero is never
|
||||
stored.
|
||||
|
||||
key values which result in zero being stored:
|
||||
|
||||
x86-64: 1..7 (or other 64-bit)
|
||||
i686: 1..11
|
||||
armhfp: 1..3 (or other 32-bit)
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index 6acb5ad43a..ee87ddbbf9 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -1632,7 +1632,7 @@ static INTERNAL_SIZE_T global_max_fast;
|
||||
*/
|
||||
|
||||
#define set_max_fast(s) \
|
||||
- global_max_fast = (((s) == 0) \
|
||||
+ global_max_fast = (((size_t) (s) <= MALLOC_ALIGN_MASK - SIZE_SZ) \
|
||||
? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
|
||||
|
||||
static inline INTERNAL_SIZE_T
|
35
SOURCES/glibc-rh1871383-6.patch
Normal file
35
SOURCES/glibc-rh1871383-6.patch
Normal file
@ -0,0 +1,35 @@
|
||||
From 0e00b35704e67c499c3abfbd5b6224a13d38b012 Mon Sep 17 00:00:00 2001
|
||||
From: "W. Hashimoto" <ssmallkirby@gmail.com>
|
||||
Date: Fri, 11 Dec 2020 16:59:10 -0500
|
||||
Subject: malloc: Detect infinite-loop in _int_free when freeing tcache
|
||||
[BZ#27052]
|
||||
|
||||
If linked-list of tcache contains a loop, it invokes infinite
|
||||
loop in _int_free when freeing tcache. The PoC which invokes
|
||||
such infinite loop is on the Bugzilla(#27052). This loop
|
||||
should terminate when the loop exceeds mp_.tcache_count and
|
||||
the program should abort. The affected glibc version is
|
||||
2.29 or later.
|
||||
|
||||
Reviewed-by: DJ Delorie <dj@redhat.com>
|
||||
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index 5b87bdb081..ec2d934595 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -4224,11 +4224,14 @@ _int_free (mstate av, mchunkptr p, int have_lock)
|
||||
if (__glibc_unlikely (e->key == tcache))
|
||||
{
|
||||
tcache_entry *tmp;
|
||||
+ size_t cnt = 0;
|
||||
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
|
||||
for (tmp = tcache->entries[tc_idx];
|
||||
tmp;
|
||||
- tmp = REVEAL_PTR (tmp->next))
|
||||
+ tmp = REVEAL_PTR (tmp->next), ++cnt)
|
||||
{
|
||||
+ if (cnt >= mp_.tcache_count)
|
||||
+ malloc_printerr ("free(): too many chunks detected in tcache");
|
||||
if (__glibc_unlikely (!aligned_OK (tmp)))
|
||||
malloc_printerr ("free(): unaligned chunk detected in tcache 2");
|
||||
if (tmp == e)
|
133
SOURCES/glibc-rh1871383-7.patch
Normal file
133
SOURCES/glibc-rh1871383-7.patch
Normal file
@ -0,0 +1,133 @@
|
||||
From fc859c304898a5ec72e0ba5269ed136ed0ea10e1 Mon Sep 17 00:00:00 2001
|
||||
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
Date: Wed, 7 Jul 2021 23:02:46 +0530
|
||||
Subject: Harden tcache double-free check
|
||||
|
||||
The tcache allocator layer uses the tcache pointer as a key to
|
||||
identify a block that may be freed twice. Since this is in the
|
||||
application data area, an attacker exploiting a use-after-free could
|
||||
potentially get access to the entire tcache structure through this
|
||||
key. A detailed write-up was provided by Awarau here:
|
||||
|
||||
https://awaraucom.wordpress.com/2020/07/19/house-of-io-remastered/
|
||||
|
||||
Replace this static pointer use for key checking with one that is
|
||||
generated at malloc initialization. The first attempt is through
|
||||
getrandom with a fallback to random_bits(), which is a simple
|
||||
pseudo-random number generator based on the clock. The fallback ought
|
||||
to be sufficient since the goal of the randomness is only to make the
|
||||
key arbitrary enough that it is very unlikely to collide with user
|
||||
data.
|
||||
|
||||
Co-authored-by: Eyal Itkin <eyalit@checkpoint.com>
|
||||
|
||||
[note: context for arena.c chunk #2 changed to accomodate missing
|
||||
tagging support code - DJ]
|
||||
|
||||
diff -rup a/malloc/arena.c b/malloc/arena.c
|
||||
--- a/malloc/arena.c 2022-09-16 01:09:02.003843024 -0400
|
||||
+++ b/malloc/arena.c 2022-09-16 01:25:51.879994057 -0400
|
||||
@@ -286,6 +286,10 @@ extern struct dl_open_hook *_dl_open_hoo
|
||||
libc_hidden_proto (_dl_open_hook);
|
||||
#endif
|
||||
|
||||
+#if USE_TCACHE
|
||||
+static void tcache_key_initialize (void);
|
||||
+#endif
|
||||
+
|
||||
static void
|
||||
ptmalloc_init (void)
|
||||
{
|
||||
@@ -294,6 +298,10 @@ ptmalloc_init (void)
|
||||
|
||||
__malloc_initialized = 0;
|
||||
|
||||
+#if USE_TCACHE
|
||||
+ tcache_key_initialize ();
|
||||
+#endif
|
||||
+
|
||||
#ifdef SHARED
|
||||
/* In case this libc copy is in a non-default namespace, never use brk.
|
||||
Likewise if dlopened from statically linked program. */
|
||||
diff -rup a/malloc/malloc.c b/malloc/malloc.c
|
||||
--- a/malloc/malloc.c 2022-09-16 01:09:05.491977387 -0400
|
||||
+++ b/malloc/malloc.c 2022-09-16 01:25:51.883994213 -0400
|
||||
@@ -247,6 +247,10 @@
|
||||
/* For SINGLE_THREAD_P. */
|
||||
#include <sysdep-cancel.h>
|
||||
|
||||
+/* For tcache double-free check. */
|
||||
+#include <random-bits.h>
|
||||
+#include <sys/random.h>
|
||||
+
|
||||
/*
|
||||
Debugging:
|
||||
|
||||
@@ -2924,7 +2928,7 @@ typedef struct tcache_entry
|
||||
{
|
||||
struct tcache_entry *next;
|
||||
/* This field exists to detect double frees. */
|
||||
- struct tcache_perthread_struct *key;
|
||||
+ uintptr_t key;
|
||||
} tcache_entry;
|
||||
|
||||
/* There is one of these for each thread, which contains the
|
||||
@@ -2941,6 +2945,31 @@ typedef struct tcache_perthread_struct
|
||||
static __thread bool tcache_shutting_down = false;
|
||||
static __thread tcache_perthread_struct *tcache = NULL;
|
||||
|
||||
+/* Process-wide key to try and catch a double-free in the same thread. */
|
||||
+static uintptr_t tcache_key;
|
||||
+
|
||||
+/* The value of tcache_key does not really have to be a cryptographically
|
||||
+ secure random number. It only needs to be arbitrary enough so that it does
|
||||
+ not collide with values present in applications. If a collision does happen
|
||||
+ consistently enough, it could cause a degradation in performance since the
|
||||
+ entire list is checked to check if the block indeed has been freed the
|
||||
+ second time. The odds of this happening are exceedingly low though, about 1
|
||||
+ in 2^wordsize. There is probably a higher chance of the performance
|
||||
+ degradation being due to a double free where the first free happened in a
|
||||
+ different thread; that's a case this check does not cover. */
|
||||
+static void
|
||||
+tcache_key_initialize (void)
|
||||
+{
|
||||
+ if (__getrandom (&tcache_key, sizeof(tcache_key), GRND_NONBLOCK)
|
||||
+ != sizeof (tcache_key))
|
||||
+ {
|
||||
+ tcache_key = random_bits ();
|
||||
+#if __WORDSIZE == 64
|
||||
+ tcache_key = (tcache_key << 32) | random_bits ();
|
||||
+#endif
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* Caller must ensure that we know tc_idx is valid and there's room
|
||||
for more chunks. */
|
||||
static __always_inline void
|
||||
@@ -2950,7 +2979,7 @@ tcache_put (mchunkptr chunk, size_t tc_i
|
||||
|
||||
/* Mark this chunk as "in the tcache" so the test in _int_free will
|
||||
detect a double free. */
|
||||
- e->key = tcache;
|
||||
+ e->key = tcache_key;
|
||||
|
||||
e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]);
|
||||
tcache->entries[tc_idx] = e;
|
||||
@@ -2967,7 +2996,7 @@ tcache_get (size_t tc_idx)
|
||||
malloc_printerr ("malloc(): unaligned tcache chunk detected");
|
||||
tcache->entries[tc_idx] = REVEAL_PTR (e->next);
|
||||
--(tcache->counts[tc_idx]);
|
||||
- e->key = NULL;
|
||||
+ e->key = 0;
|
||||
return (void *) e;
|
||||
}
|
||||
|
||||
@@ -4231,7 +4260,7 @@ _int_free (mstate av, mchunkptr p, int h
|
||||
trust it (it also matches random payload data at a 1 in
|
||||
2^<size_t> chance), so verify it's not an unlikely
|
||||
coincidence before aborting. */
|
||||
- if (__glibc_unlikely (e->key == tcache))
|
||||
+ if (__glibc_unlikely (e->key == tcache_key))
|
||||
{
|
||||
tcache_entry *tmp;
|
||||
size_t cnt = 0;
|
27
SOURCES/glibc-rh2109510-1.patch
Normal file
27
SOURCES/glibc-rh2109510-1.patch
Normal file
@ -0,0 +1,27 @@
|
||||
commit 97f8225d22ef727ae9935cc231643efdc430d530
|
||||
Author: Zack Weinberg <zackw@panix.com>
|
||||
Date: Thu Mar 14 09:44:22 2019 -0400
|
||||
|
||||
scripts/check-obsolete-constructs.py: Process all headers as UTF-8.
|
||||
|
||||
A few of our installed headers contain UTF-8 in comments.
|
||||
check-obsolete-constructs opened files without explicitly specifying
|
||||
their encoding, so it would barf on these headers if “make check” was
|
||||
run in a non-UTF-8 locale.
|
||||
|
||||
* scripts/check-obsolete-constructs.py (HeaderChecker.check):
|
||||
Specify encoding="utf-8" when opening headers to check.
|
||||
|
||||
diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py
|
||||
index ce5c72251f4d7cc0..89d21dea6e788783 100755
|
||||
--- a/scripts/check-obsolete-constructs.py
|
||||
+++ b/scripts/check-obsolete-constructs.py
|
||||
@@ -437,7 +437,7 @@ class HeaderChecker:
|
||||
def check(self, fname):
|
||||
self.fname = fname
|
||||
try:
|
||||
- with open(fname, "rt") as fp:
|
||||
+ with open(fname, "rt", encoding="utf-8") as fp:
|
||||
contents = fp.read()
|
||||
except OSError as e:
|
||||
sys.stderr.write("{}: {}\n".format(fname, e.strerror))
|
1449
SOURCES/glibc-rh2109510-10.patch
Normal file
1449
SOURCES/glibc-rh2109510-10.patch
Normal file
File diff suppressed because it is too large
Load Diff
409
SOURCES/glibc-rh2109510-11.patch
Normal file
409
SOURCES/glibc-rh2109510-11.patch
Normal file
@ -0,0 +1,409 @@
|
||||
commit 198abcbb94618730dae1b3f4393efaa49e0ec8c7
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Apr 11 11:30:31 2022 +0200
|
||||
|
||||
Default to --with-default-link=no (bug 25812)
|
||||
|
||||
This is necessary to place the libio vtables into the RELRO segment.
|
||||
New tests elf/tst-relro-ldso and elf/tst-relro-libc are added to
|
||||
verify that this is what actually happens.
|
||||
|
||||
The new tests fail on ia64 due to lack of (default) RELRO support
|
||||
inbutils, so they are XFAILed there.
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
(missing valgrind smoke test)
|
||||
|
||||
diff --git a/INSTALL b/INSTALL
|
||||
index b3a4370f592c5047..b69672b283c0b774 100644
|
||||
--- a/INSTALL
|
||||
+++ b/INSTALL
|
||||
@@ -90,6 +90,12 @@ if 'CFLAGS' is specified it must enable optimization. For example:
|
||||
library will still be usable, but functionality may be lost--for
|
||||
example, you can't build a shared libc with old binutils.
|
||||
|
||||
+'--with-default-link=FLAG'
|
||||
+ With '--with-default-link=yes', the build system does not use a
|
||||
+ custom linker script for linking shared objects. The default for
|
||||
+ FLAG is the opposite, 'no', because the custom linker script is
|
||||
+ needed for full RELRO protection.
|
||||
+
|
||||
'--with-nonshared-cflags=CFLAGS'
|
||||
Use additional compiler flags CFLAGS to build the parts of the
|
||||
library which are always statically linked into applications and
|
||||
diff --git a/configure b/configure
|
||||
index 8b3681d2e28310c8..c794cea4359b3da3 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -3339,7 +3339,7 @@ fi
|
||||
if test "${with_default_link+set}" = set; then :
|
||||
withval=$with_default_link; use_default_link=$withval
|
||||
else
|
||||
- use_default_link=default
|
||||
+ use_default_link=no
|
||||
fi
|
||||
|
||||
|
||||
@@ -5965,69 +5965,6 @@ fi
|
||||
$as_echo "$libc_cv_hashstyle" >&6; }
|
||||
|
||||
|
||||
-# The linker's default -shared behavior is good enough if it
|
||||
-# does these things that our custom linker scripts ensure that
|
||||
-# all allocated NOTE sections come first.
|
||||
-if test "$use_default_link" = default; then
|
||||
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sufficient default -shared layout" >&5
|
||||
-$as_echo_n "checking for sufficient default -shared layout... " >&6; }
|
||||
-if ${libc_cv_use_default_link+:} false; then :
|
||||
- $as_echo_n "(cached) " >&6
|
||||
-else
|
||||
- libc_cv_use_default_link=no
|
||||
- cat > conftest.s <<\EOF
|
||||
- .section .note.a,"a",%note
|
||||
- .balign 4
|
||||
- .long 4,4,9
|
||||
- .string "GNU"
|
||||
- .string "foo"
|
||||
- .section .note.b,"a",%note
|
||||
- .balign 4
|
||||
- .long 4,4,9
|
||||
- .string "GNU"
|
||||
- .string "bar"
|
||||
-EOF
|
||||
- if { ac_try=' ${CC-cc} $ASFLAGS -shared -o conftest.so conftest.s 1>&5'
|
||||
- { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||
- (eval $ac_try) 2>&5
|
||||
- ac_status=$?
|
||||
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||
- test $ac_status = 0; }; } &&
|
||||
- ac_try=`$READELF -S conftest.so | sed -n \
|
||||
- '${x;p;}
|
||||
- s/^ *\[ *[1-9][0-9]*\] *\([^ ][^ ]*\) *\([^ ][^ ]*\) .*$/\2 \1/
|
||||
- t a
|
||||
- b
|
||||
- : a
|
||||
- H'`
|
||||
- then
|
||||
- libc_seen_a=no libc_seen_b=no
|
||||
- set -- $ac_try
|
||||
- while test $# -ge 2 -a "$1" = NOTE; do
|
||||
- case "$2" in
|
||||
- .note.a) libc_seen_a=yes ;;
|
||||
- .note.b) libc_seen_b=yes ;;
|
||||
- esac
|
||||
- shift 2
|
||||
- done
|
||||
- case "$libc_seen_a$libc_seen_b" in
|
||||
- yesyes)
|
||||
- libc_cv_use_default_link=yes
|
||||
- ;;
|
||||
- *)
|
||||
- echo >&5 "\
|
||||
-$libc_seen_a$libc_seen_b from:
|
||||
-$ac_try"
|
||||
- ;;
|
||||
- esac
|
||||
- fi
|
||||
- rm -f conftest*
|
||||
-fi
|
||||
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_use_default_link" >&5
|
||||
-$as_echo "$libc_cv_use_default_link" >&6; }
|
||||
- use_default_link=$libc_cv_use_default_link
|
||||
-fi
|
||||
-
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLOB_DAT reloc" >&5
|
||||
$as_echo_n "checking for GLOB_DAT reloc... " >&6; }
|
||||
if ${libc_cv_has_glob_dat+:} false; then :
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 82d9ab2fb67145bb..52429d82344954b3 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -152,7 +152,7 @@ AC_ARG_WITH([default-link],
|
||||
AC_HELP_STRING([--with-default-link],
|
||||
[do not use explicit linker scripts]),
|
||||
[use_default_link=$withval],
|
||||
- [use_default_link=default])
|
||||
+ [use_default_link=no])
|
||||
|
||||
dnl Additional build flags injection.
|
||||
AC_ARG_WITH([nonshared-cflags],
|
||||
@@ -1352,59 +1352,6 @@ fi
|
||||
rm -f conftest*])
|
||||
AC_SUBST(libc_cv_hashstyle)
|
||||
|
||||
-# The linker's default -shared behavior is good enough if it
|
||||
-# does these things that our custom linker scripts ensure that
|
||||
-# all allocated NOTE sections come first.
|
||||
-if test "$use_default_link" = default; then
|
||||
- AC_CACHE_CHECK([for sufficient default -shared layout],
|
||||
- libc_cv_use_default_link, [dnl
|
||||
- libc_cv_use_default_link=no
|
||||
- cat > conftest.s <<\EOF
|
||||
- .section .note.a,"a",%note
|
||||
- .balign 4
|
||||
- .long 4,4,9
|
||||
- .string "GNU"
|
||||
- .string "foo"
|
||||
- .section .note.b,"a",%note
|
||||
- .balign 4
|
||||
- .long 4,4,9
|
||||
- .string "GNU"
|
||||
- .string "bar"
|
||||
-EOF
|
||||
- if AC_TRY_COMMAND([dnl
|
||||
- ${CC-cc} $ASFLAGS -shared -o conftest.so conftest.s 1>&AS_MESSAGE_LOG_FD]) &&
|
||||
- ac_try=`$READELF -S conftest.so | sed -n \
|
||||
- ['${x;p;}
|
||||
- s/^ *\[ *[1-9][0-9]*\] *\([^ ][^ ]*\) *\([^ ][^ ]*\) .*$/\2 \1/
|
||||
- t a
|
||||
- b
|
||||
- : a
|
||||
- H']`
|
||||
- then
|
||||
- libc_seen_a=no libc_seen_b=no
|
||||
- set -- $ac_try
|
||||
- while test $# -ge 2 -a "$1" = NOTE; do
|
||||
- case "$2" in
|
||||
- .note.a) libc_seen_a=yes ;;
|
||||
- .note.b) libc_seen_b=yes ;;
|
||||
- esac
|
||||
- shift 2
|
||||
- done
|
||||
- case "$libc_seen_a$libc_seen_b" in
|
||||
- yesyes)
|
||||
- libc_cv_use_default_link=yes
|
||||
- ;;
|
||||
- *)
|
||||
- echo >&AS_MESSAGE_LOG_FD "\
|
||||
-$libc_seen_a$libc_seen_b from:
|
||||
-$ac_try"
|
||||
- ;;
|
||||
- esac
|
||||
- fi
|
||||
- rm -f conftest*])
|
||||
- use_default_link=$libc_cv_use_default_link
|
||||
-fi
|
||||
-
|
||||
AC_CACHE_CHECK(for GLOB_DAT reloc,
|
||||
libc_cv_has_glob_dat, [dnl
|
||||
cat > conftest.c <<EOF
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 89ce4f5196e5eb39..1fdf40cbd49e233e 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -477,6 +477,40 @@ tests-execstack-yes = \
|
||||
# tests-execstack-yes
|
||||
endif
|
||||
endif
|
||||
+
|
||||
+tests-special += $(objpfx)tst-relro-ldso.out $(objpfx)tst-relro-libc.out
|
||||
+$(objpfx)tst-relro-ldso.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
|
||||
+ $(objpfx)ld.so
|
||||
+ $(PYTHON) tst-relro-symbols.py $(objpfx)ld.so \
|
||||
+ --required=_rtld_global_ro \
|
||||
+ > $@ 2>&1; $(evaluate-test)
|
||||
+# The optional symbols are present in libc only if the architecture has
|
||||
+# the GLIBC_2.0 symbol set in libc.
|
||||
+$(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
|
||||
+ $(common-objpfx)libc.so
|
||||
+ $(PYTHON) tst-relro-symbols.py $(common-objpfx)libc.so \
|
||||
+ --required=_IO_cookie_jumps \
|
||||
+ --required=_IO_file_jumps \
|
||||
+ --required=_IO_file_jumps_maybe_mmap \
|
||||
+ --required=_IO_file_jumps_mmap \
|
||||
+ --required=_IO_helper_jumps \
|
||||
+ --required=_IO_mem_jumps \
|
||||
+ --required=_IO_obstack_jumps \
|
||||
+ --required=_IO_proc_jumps \
|
||||
+ --required=_IO_str_chk_jumps \
|
||||
+ --required=_IO_str_jumps \
|
||||
+ --required=_IO_strn_jumps \
|
||||
+ --required=_IO_wfile_jumps \
|
||||
+ --required=_IO_wfile_jumps_maybe_mmap \
|
||||
+ --required=_IO_wfile_jumps_mmap \
|
||||
+ --required=_IO_wmem_jumps \
|
||||
+ --required=_IO_wstr_jumps \
|
||||
+ --required=_IO_wstrn_jumps \
|
||||
+ --optional=_IO_old_cookie_jumps \
|
||||
+ --optional=_IO_old_file_jumps \
|
||||
+ --optional=_IO_old_proc_jumps \
|
||||
+ > $@ 2>&1; $(evaluate-test)
|
||||
+
|
||||
tests += $(tests-execstack-$(have-z-execstack))
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += \
|
||||
diff --git a/elf/tst-relro-symbols.py b/elf/tst-relro-symbols.py
|
||||
new file mode 100644
|
||||
index 0000000000000000..368ea3349f86bd81
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-relro-symbols.py
|
||||
@@ -0,0 +1,137 @@
|
||||
+#!/usr/bin/python3
|
||||
+# Verify that certain symbols are covered by RELRO.
|
||||
+# Copyright (C) 2022 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/>.
|
||||
+
|
||||
+"""Analyze a (shared) object to verify that certain symbols are
|
||||
+present and covered by the PT_GNU_RELRO segment.
|
||||
+
|
||||
+"""
|
||||
+
|
||||
+import argparse
|
||||
+import os.path
|
||||
+import sys
|
||||
+
|
||||
+# Make available glibc Python modules.
|
||||
+sys.path.append(os.path.join(
|
||||
+ os.path.dirname(os.path.realpath(__file__)), os.path.pardir, 'scripts'))
|
||||
+
|
||||
+import glibcelf
|
||||
+
|
||||
+def find_relro(path: str, img: glibcelf.Image) -> (int, int):
|
||||
+ """Discover the address range of the PT_GNU_RELRO segment."""
|
||||
+ for phdr in img.phdrs():
|
||||
+ if phdr.p_type == glibcelf.Pt.PT_GNU_RELRO:
|
||||
+ # The computation is not entirely accurate because
|
||||
+ # _dl_protect_relro in elf/dl-reloc.c rounds both the
|
||||
+ # start end and downwards using the run-time page size.
|
||||
+ return phdr.p_vaddr, phdr.p_vaddr + phdr.p_memsz
|
||||
+ sys.stdout.write('{}: error: no PT_GNU_RELRO segment\n'.format(path))
|
||||
+ sys.exit(1)
|
||||
+
|
||||
+def check_in_relro(kind, relro_begin, relro_end, name, start, size, error):
|
||||
+ """Check if a section or symbol falls within in the RELRO segment."""
|
||||
+ end = start + size - 1
|
||||
+ if not (relro_begin <= start < end < relro_end):
|
||||
+ error(
|
||||
+ '{} {!r} of size {} at 0x{:x} is not in RELRO range [0x{:x}, 0x{:x})'.format(
|
||||
+ kind, name.decode('UTF-8'), start, size,
|
||||
+ relro_begin, relro_end))
|
||||
+
|
||||
+def get_parser():
|
||||
+ """Return an argument parser for this script."""
|
||||
+ parser = argparse.ArgumentParser(description=__doc__)
|
||||
+ parser.add_argument('object', help='path to object file to check')
|
||||
+ parser.add_argument('--required', metavar='NAME', default=(),
|
||||
+ help='required symbol names', nargs='*')
|
||||
+ parser.add_argument('--optional', metavar='NAME', default=(),
|
||||
+ help='required symbol names', nargs='*')
|
||||
+ return parser
|
||||
+
|
||||
+def main(argv):
|
||||
+ """The main entry point."""
|
||||
+ parser = get_parser()
|
||||
+ opts = parser.parse_args(argv)
|
||||
+ img = glibcelf.Image.readfile(opts.object)
|
||||
+
|
||||
+ required_symbols = frozenset([sym.encode('UTF-8')
|
||||
+ for sym in opts.required])
|
||||
+ optional_symbols = frozenset([sym.encode('UTF-8')
|
||||
+ for sym in opts.optional])
|
||||
+ check_symbols = required_symbols | optional_symbols
|
||||
+
|
||||
+ # Tracks the symbols in check_symbols that have been found.
|
||||
+ symbols_found = set()
|
||||
+
|
||||
+ # Discover the extent of the RELRO segment.
|
||||
+ relro_begin, relro_end = find_relro(opts.object, img)
|
||||
+ symbol_table_found = False
|
||||
+
|
||||
+ errors = False
|
||||
+ def error(msg: str) -> None:
|
||||
+ """Record an error condition and write a message to standard output."""
|
||||
+ nonlocal errors
|
||||
+ errors = True
|
||||
+ sys.stdout.write('{}: error: {}\n'.format(opts.object, msg))
|
||||
+
|
||||
+ # Iterate over section headers to find the symbol table.
|
||||
+ for shdr in img.shdrs():
|
||||
+ if shdr.sh_type == glibcelf.Sht.SHT_SYMTAB:
|
||||
+ symbol_table_found = True
|
||||
+ for sym in img.syms(shdr):
|
||||
+ if sym.st_name in check_symbols:
|
||||
+ symbols_found.add(sym.st_name)
|
||||
+
|
||||
+ # Validate symbol type, section, and size.
|
||||
+ if sym.st_info.type != glibcelf.Stt.STT_OBJECT:
|
||||
+ error('symbol {!r} has wrong type {}'.format(
|
||||
+ sym.st_name.decode('UTF-8'), sym.st_info.type))
|
||||
+ if sym.st_shndx in glibcelf.Shn:
|
||||
+ error('symbol {!r} has reserved section {}'.format(
|
||||
+ sym.st_name.decode('UTF-8'), sym.st_shndx))
|
||||
+ continue
|
||||
+ if sym.st_size == 0:
|
||||
+ error('symbol {!r} has size zero'.format(
|
||||
+ sym.st_name.decode('UTF-8')))
|
||||
+ continue
|
||||
+
|
||||
+ check_in_relro('symbol', relro_begin, relro_end,
|
||||
+ sym.st_name, sym.st_value, sym.st_size,
|
||||
+ error)
|
||||
+ continue # SHT_SYMTAB
|
||||
+ if shdr.sh_name == b'.data.rel.ro' \
|
||||
+ or shdr.sh_name.startswith(b'.data.rel.ro.'):
|
||||
+ check_in_relro('section', relro_begin, relro_end,
|
||||
+ shdr.sh_name, shdr.sh_addr, shdr.sh_size,
|
||||
+ error)
|
||||
+ continue
|
||||
+
|
||||
+ if required_symbols - symbols_found:
|
||||
+ for sym in sorted(required_symbols - symbols_found):
|
||||
+ error('symbol {!r} not found'.format(sym.decode('UTF-8')))
|
||||
+
|
||||
+ if errors:
|
||||
+ sys.exit(1)
|
||||
+
|
||||
+ if not symbol_table_found:
|
||||
+ sys.stdout.write(
|
||||
+ '{}: warning: no symbol table found (stripped object)\n'.format(
|
||||
+ opts.object))
|
||||
+ sys.exit(77)
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ main(sys.argv[1:])
|
||||
diff --git a/manual/install.texi b/manual/install.texi
|
||||
index c262fd56d0cef67b..a2c43bd692de7825 100644
|
||||
--- a/manual/install.texi
|
||||
+++ b/manual/install.texi
|
||||
@@ -117,6 +117,12 @@ problem and suppress these constructs, so that the library will still be
|
||||
usable, but functionality may be lost---for example, you can't build a
|
||||
shared libc with old binutils.
|
||||
|
||||
+@item --with-default-link=@var{FLAG}
|
||||
+With @code{--with-default-link=yes}, the build system does not use a
|
||||
+custom linker script for linking shared objects. The default for
|
||||
+@var{FLAG} is the opposite, @samp{no}, because the custom linker script
|
||||
+is needed for full RELRO protection.
|
||||
+
|
||||
@item --with-nonshared-cflags=@var{cflags}
|
||||
Use additional compiler flags @var{cflags} to build the parts of the
|
||||
library which are always statically linked into applications and
|
||||
diff --git a/sysdeps/unix/sysv/linux/ia64/Makefile b/sysdeps/unix/sysv/linux/ia64/Makefile
|
||||
index 97fc7df0b122d6a0..b1ad1ab7b1efa34c 100644
|
||||
--- a/sysdeps/unix/sysv/linux/ia64/Makefile
|
||||
+++ b/sysdeps/unix/sysv/linux/ia64/Makefile
|
||||
@@ -1,3 +1,9 @@
|
||||
+ifeq ($(subdir),elf)
|
||||
+# ia64 does not support PT_GNU_RELRO.
|
||||
+test-xfail-tst-relro-ldso = yes
|
||||
+test-xfail-tst-relro-libc = yes
|
||||
+endif
|
||||
+
|
||||
ifeq ($(subdir),misc)
|
||||
sysdep_headers += sys/rse.h
|
||||
endif
|
26
SOURCES/glibc-rh2109510-12.patch
Normal file
26
SOURCES/glibc-rh2109510-12.patch
Normal file
@ -0,0 +1,26 @@
|
||||
commit b571f3adffdcbed23f35ea39b0ca43809dbb4f5b
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Apr 22 19:34:52 2022 +0200
|
||||
|
||||
scripts/glibcelf.py: Mark as UNSUPPORTED on Python 3.5 and earlier
|
||||
|
||||
enum.IntFlag and enum.EnumMeta._missing_ support are not part of
|
||||
earlier Python versions.
|
||||
|
||||
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
|
||||
index 8f7d0ca184845714..da0d5380f33a195e 100644
|
||||
--- a/scripts/glibcelf.py
|
||||
+++ b/scripts/glibcelf.py
|
||||
@@ -28,6 +28,12 @@ import collections
|
||||
import enum
|
||||
import struct
|
||||
|
||||
+if not hasattr(enum, 'IntFlag'):
|
||||
+ import sys
|
||||
+ sys.stdout.write(
|
||||
+ 'warning: glibcelf.py needs Python 3.6 for enum support\n')
|
||||
+ sys.exit(77)
|
||||
+
|
||||
class _OpenIntEnum(enum.IntEnum):
|
||||
"""Integer enumeration that supports arbitrary int values."""
|
||||
@classmethod
|
30
SOURCES/glibc-rh2109510-13.patch
Normal file
30
SOURCES/glibc-rh2109510-13.patch
Normal file
@ -0,0 +1,30 @@
|
||||
Partial backport of the scripts/glibcelf.py part of:
|
||||
|
||||
commit 4610b24f5e4e6d2c4b769594efa6d460943163bb
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Tue Mar 29 14:08:54 2022 -0700
|
||||
|
||||
elf: Define DT_RELR related macros and types
|
||||
|
||||
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
|
||||
index da0d5380f33a195e..f847b36c55c15b8a 100644
|
||||
--- a/scripts/glibcelf.py
|
||||
+++ b/scripts/glibcelf.py
|
||||
@@ -304,6 +304,7 @@ class Sht(_OpenIntEnum):
|
||||
SHT_PREINIT_ARRAY = 16
|
||||
SHT_GROUP = 17
|
||||
SHT_SYMTAB_SHNDX = 18
|
||||
+ SHT_RELR = 19
|
||||
SHT_GNU_ATTRIBUTES = 0x6ffffff5
|
||||
SHT_GNU_HASH = 0x6ffffff6
|
||||
SHT_GNU_LIBLIST = 0x6ffffff7
|
||||
@@ -593,6 +594,9 @@ class Dt(_OpenIntEnum):
|
||||
DT_PREINIT_ARRAY = 32
|
||||
DT_PREINIT_ARRAYSZ = 33
|
||||
DT_SYMTAB_SHNDX = 34
|
||||
+ DT_RELRSZ = 35
|
||||
+ DT_RELR = 36
|
||||
+ DT_RELRENT = 37
|
||||
DT_GNU_PRELINKED = 0x6ffffdf5
|
||||
DT_GNU_CONFLICTSZ = 0x6ffffdf6
|
||||
DT_GNU_LIBLISTSZ = 0x6ffffdf7
|
50
SOURCES/glibc-rh2109510-14.patch
Normal file
50
SOURCES/glibc-rh2109510-14.patch
Normal file
@ -0,0 +1,50 @@
|
||||
commit d055481ce39d03652ac60de5078889e15b6917ff
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon May 16 21:59:24 2022 +0200
|
||||
|
||||
scripts/glibcelf.py: Add *T_RISCV_* constants
|
||||
|
||||
SHT_RISCV_ATTRIBUTES, PT_RISCV_ATTRIBUTES, DT_RISCV_VARIANT_CC were
|
||||
added in commit 0b6c6750732483b4d59c2fcb45484079cd84157d
|
||||
("Update RISC-V specific ELF definitions"). This caused the
|
||||
elf/tst-glibcelf consistency check to fail.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
|
||||
index f847b36c55c15b8a..07bef940433b4c99 100644
|
||||
--- a/scripts/glibcelf.py
|
||||
+++ b/scripts/glibcelf.py
|
||||
@@ -385,6 +385,10 @@ class ShtPARISC(enum.Enum):
|
||||
SHT_PARISC_UNWIND = 0x70000001
|
||||
SHT_PARISC_DOC = 0x70000002
|
||||
|
||||
+class ShtRISCV(enum.Enum):
|
||||
+ """Supplemental SHT_* constants for EM_RISCV."""
|
||||
+ SHT_RISCV_ATTRIBUTES = 0x70000003
|
||||
+
|
||||
class Pf(enum.IntFlag):
|
||||
"""Program header flags. Type of Phdr.p_flags values."""
|
||||
PF_X = 1
|
||||
@@ -558,6 +562,10 @@ class PtPARISC(enum.Enum):
|
||||
PT_PARISC_ARCHEXT = 0x70000000
|
||||
PT_PARISC_UNWIND = 0x70000001
|
||||
|
||||
+class PtRISCV(enum.Enum):
|
||||
+ """Supplemental PT_* constants for EM_RISCV."""
|
||||
+ PT_RISCV_ATTRIBUTES = 0x70000003
|
||||
+
|
||||
class Dt(_OpenIntEnum):
|
||||
"""ELF dynamic segment tags. Type of Dyn.d_val."""
|
||||
DT_NULL = 0
|
||||
@@ -710,6 +718,10 @@ class DtPPC64(enum.Enum):
|
||||
DT_PPC64_OPDSZ = 0x70000002
|
||||
DT_PPC64_OPT = 0x70000003
|
||||
|
||||
+class DtRISCV(enum.Enum):
|
||||
+ """Supplemental DT_* constants for EM_RISCV."""
|
||||
+ DT_RISCV_VARIANT_CC = 0x70000001
|
||||
+
|
||||
class DtSPARC(enum.Enum):
|
||||
"""Supplemental DT_* constants for EM_SPARC."""
|
||||
DT_SPARC_REGISTER = 0x70000001
|
26
SOURCES/glibc-rh2109510-15.patch
Normal file
26
SOURCES/glibc-rh2109510-15.patch
Normal file
@ -0,0 +1,26 @@
|
||||
commit 8521001731d6539382fa875f1cac9864c466ef27
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Mon Jun 6 14:41:24 2022 -0300
|
||||
|
||||
scripts/glibcelf.py: Add PT_AARCH64_MEMTAG_MTE constant
|
||||
|
||||
It was added in commit 603e5c8ba7257483c162cabb06eb6f79096429b6.
|
||||
This caused the elf/tst-glibcelf consistency check to fail.
|
||||
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
|
||||
index 07bef940433b4c99..47f95d07baefb4ae 100644
|
||||
--- a/scripts/glibcelf.py
|
||||
+++ b/scripts/glibcelf.py
|
||||
@@ -523,6 +523,10 @@ class Pt(_OpenIntEnum):
|
||||
PT_SUNWBSS = 0x6ffffffa
|
||||
PT_SUNWSTACK = 0x6ffffffb
|
||||
|
||||
+class PtAARCH64(enum.Enum):
|
||||
+ """Supplemental PT_* constants for EM_AARCH64."""
|
||||
+ PT_AARCH64_MEMTAG_MTE = 0x70000002
|
||||
+
|
||||
class PtARM(enum.Enum):
|
||||
"""Supplemental PT_* constants for EM_ARM."""
|
||||
PT_ARM_EXIDX = 0x70000001
|
22
SOURCES/glibc-rh2109510-16.patch
Normal file
22
SOURCES/glibc-rh2109510-16.patch
Normal file
@ -0,0 +1,22 @@
|
||||
Partial backport of the scripts/glibcelf.py part of:
|
||||
|
||||
commit 2d83247d90c9f0bfee7f3f2505bc1b13b6f36c04
|
||||
Author: caiyinyu <caiyinyu@loongson.cn>
|
||||
Date: Tue Jul 19 09:20:45 2022 +0800
|
||||
|
||||
LoongArch: Add relocations and ELF flags to elf.h and scripts/glibcelf.py
|
||||
|
||||
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
|
||||
index 47f95d07baefb4ae..de0509130ed9ad47 100644
|
||||
--- a/scripts/glibcelf.py
|
||||
+++ b/scripts/glibcelf.py
|
||||
@@ -252,7 +252,8 @@ class Machine(_OpenIntEnum):
|
||||
EM_RISCV = 243
|
||||
EM_BPF = 247
|
||||
EM_CSKY = 252
|
||||
- EM_NUM = 253
|
||||
+ EM_LOONGARCH = 258
|
||||
+ EM_NUM = 259
|
||||
EM_ALPHA = 0x9026
|
||||
|
||||
class Et(_OpenIntEnum):
|
78
SOURCES/glibc-rh2109510-17.patch
Normal file
78
SOURCES/glibc-rh2109510-17.patch
Normal file
@ -0,0 +1,78 @@
|
||||
commit bd13cb19f5e15e9e9a92a536e755fd93a97a67f6
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Aug 19 11:16:32 2022 +0200
|
||||
|
||||
scripts/glibcelf.py: Add hashing support
|
||||
|
||||
ELF and GNU hashes can now be computed using the elf_hash and
|
||||
gnu_hash functions.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Tested-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py
|
||||
index bf15a3bad4479e08..e5026e2289df206b 100644
|
||||
--- a/elf/tst-glibcelf.py
|
||||
+++ b/elf/tst-glibcelf.py
|
||||
@@ -240,6 +240,24 @@ def check_constant_values(cc):
|
||||
error('{}: glibcelf has {!r}, <elf.h> has {!r}'.format(
|
||||
name, glibcelf_value, elf_h_value))
|
||||
|
||||
+def check_hashes():
|
||||
+ for name, expected_elf, expected_gnu in (
|
||||
+ ('', 0, 0x1505),
|
||||
+ ('PPPPPPPPPPPP', 0, 0x9f105c45),
|
||||
+ ('GLIBC_2.0', 0xd696910, 0xf66c3dd5),
|
||||
+ ('GLIBC_2.34', 0x69691b4, 0xc3f3f90c),
|
||||
+ ('GLIBC_PRIVATE', 0x963cf85, 0x692a260)):
|
||||
+ for convert in (lambda x: x, lambda x: x.encode('UTF-8')):
|
||||
+ name = convert(name)
|
||||
+ actual_elf = glibcelf.elf_hash(name)
|
||||
+ if actual_elf != expected_elf:
|
||||
+ error('elf_hash({!r}): {:x} != 0x{:x}'.format(
|
||||
+ name, actual_elf, expected_elf))
|
||||
+ actual_gnu = glibcelf.gnu_hash(name)
|
||||
+ if actual_gnu != expected_gnu:
|
||||
+ error('gnu_hash({!r}): {:x} != 0x{:x}'.format(
|
||||
+ name, actual_gnu, expected_gnu))
|
||||
+
|
||||
def main():
|
||||
"""The main entry point."""
|
||||
parser = argparse.ArgumentParser(
|
||||
@@ -251,6 +269,7 @@ def main():
|
||||
check_duplicates()
|
||||
check_constant_prefixes()
|
||||
check_constant_values(cc=args.cc)
|
||||
+ check_hashes()
|
||||
|
||||
if errors_encountered > 0:
|
||||
print("note: errors encountered:", errors_encountered)
|
||||
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
|
||||
index de0509130ed9ad47..5c8f46f590722384 100644
|
||||
--- a/scripts/glibcelf.py
|
||||
+++ b/scripts/glibcelf.py
|
||||
@@ -1158,5 +1158,24 @@ class Image:
|
||||
self._stringtab[sh_link] = strtab
|
||||
return strtab
|
||||
|
||||
+def elf_hash(s):
|
||||
+ """Computes the ELF hash of the string."""
|
||||
+ acc = 0
|
||||
+ for ch in s:
|
||||
+ if type(ch) is not int:
|
||||
+ ch = ord(ch)
|
||||
+ acc = ((acc << 4) + ch) & 0xffffffff
|
||||
+ top = acc & 0xf0000000
|
||||
+ acc = (acc ^ (top >> 24)) & ~top
|
||||
+ return acc
|
||||
+
|
||||
+def gnu_hash(s):
|
||||
+ """Computes the GNU hash of the string."""
|
||||
+ h = 5381
|
||||
+ for ch in s:
|
||||
+ if type(ch) is not int:
|
||||
+ ch = ord(ch)
|
||||
+ h = (h * 33 + ch) & 0xffffffff
|
||||
+ return h
|
||||
|
||||
__all__ = [name for name in dir() if name[0].isupper()]
|
439
SOURCES/glibc-rh2109510-18.patch
Normal file
439
SOURCES/glibc-rh2109510-18.patch
Normal file
@ -0,0 +1,439 @@
|
||||
commit f40c7887d3cc9bb0b56576ed9edbe505ff8058c0
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Sep 22 12:10:41 2022 +0200
|
||||
|
||||
scripts: Extract glibcpp.py from check-obsolete-constructs.py
|
||||
|
||||
The C tokenizer is useful separately.
|
||||
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py
|
||||
index 89d21dea6e788783..7c7a092e440a3258 100755
|
||||
--- a/scripts/check-obsolete-constructs.py
|
||||
+++ b/scripts/check-obsolete-constructs.py
|
||||
@@ -24,193 +24,14 @@
|
||||
"""
|
||||
|
||||
import argparse
|
||||
-import collections
|
||||
+import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
-# Simplified lexical analyzer for C preprocessing tokens.
|
||||
-# Does not implement trigraphs.
|
||||
-# Does not implement backslash-newline in the middle of any lexical
|
||||
-# item other than a string literal.
|
||||
-# Does not implement universal-character-names in identifiers.
|
||||
-# Treats prefixed strings (e.g. L"...") as two tokens (L and "...")
|
||||
-# Accepts non-ASCII characters only within comments and strings.
|
||||
-
|
||||
-# Caution: The order of the outermost alternation matters.
|
||||
-# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
|
||||
-# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
|
||||
-# be last.
|
||||
-# Caution: There should be no capturing groups other than the named
|
||||
-# captures in the outermost alternation.
|
||||
-
|
||||
-# For reference, these are all of the C punctuators as of C11:
|
||||
-# [ ] ( ) { } , ; ? ~
|
||||
-# ! != * *= / /= ^ ^= = ==
|
||||
-# # ##
|
||||
-# % %= %> %: %:%:
|
||||
-# & &= &&
|
||||
-# | |= ||
|
||||
-# + += ++
|
||||
-# - -= -- ->
|
||||
-# . ...
|
||||
-# : :>
|
||||
-# < <% <: << <<= <=
|
||||
-# > >= >> >>=
|
||||
-
|
||||
-# The BAD_* tokens are not part of the official definition of pp-tokens;
|
||||
-# they match unclosed strings, character constants, and block comments,
|
||||
-# so that the regex engine doesn't have to backtrack all the way to the
|
||||
-# beginning of a broken construct and then emit dozens of junk tokens.
|
||||
-
|
||||
-PP_TOKEN_RE_ = re.compile(r"""
|
||||
- (?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
|
||||
- |(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*)
|
||||
- |(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
|
||||
- |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
|
||||
- |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
|
||||
- |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
|
||||
- |(?P<LINE_COMMENT> //[^\r\n]*)
|
||||
- |(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*)
|
||||
- |(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
|
||||
- |(?P<PUNCTUATOR>
|
||||
- [,;?~(){}\[\]]
|
||||
- | [!*/^=]=?
|
||||
- | \#\#?
|
||||
- | %(?:[=>]|:(?:%:)?)?
|
||||
- | &[=&]?
|
||||
- |\|[=|]?
|
||||
- |\+[=+]?
|
||||
- | -[=->]?
|
||||
- |\.(?:\.\.)?
|
||||
- | :>?
|
||||
- | <(?:[%:]|<(?:=|<=?)?)?
|
||||
- | >(?:=|>=?)?)
|
||||
- |(?P<ESCNL> \\(?:\r|\n|\r\n))
|
||||
- |(?P<WHITESPACE> [ \t\n\r\v\f]+)
|
||||
- |(?P<OTHER> .)
|
||||
-""", re.DOTALL | re.VERBOSE)
|
||||
-
|
||||
-HEADER_NAME_RE_ = re.compile(r"""
|
||||
- < [^>\r\n]+ >
|
||||
- | " [^"\r\n]+ "
|
||||
-""", re.DOTALL | re.VERBOSE)
|
||||
-
|
||||
-ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
|
||||
-
|
||||
-# based on the sample code in the Python re documentation
|
||||
-Token_ = collections.namedtuple("Token", (
|
||||
- "kind", "text", "line", "column", "context"))
|
||||
-Token_.__doc__ = """
|
||||
- One C preprocessing token, comment, or chunk of whitespace.
|
||||
- 'kind' identifies the token type, which will be one of:
|
||||
- STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
|
||||
- PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
|
||||
- or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are
|
||||
- handled within tokenize_c, below.
|
||||
-
|
||||
- 'text' is the sequence of source characters making up the token;
|
||||
- no decoding whatsoever is performed.
|
||||
-
|
||||
- 'line' and 'column' give the position of the first character of the
|
||||
- token within the source file. They are both 1-based.
|
||||
-
|
||||
- 'context' indicates whether or not this token occurred within a
|
||||
- preprocessing directive; it will be None for running text,
|
||||
- '<null>' for the leading '#' of a directive line (because '#'
|
||||
- all by itself on a line is a "null directive"), or the name of
|
||||
- the directive for tokens within a directive line, starting with
|
||||
- the IDENT for the name itself.
|
||||
-"""
|
||||
-
|
||||
-def tokenize_c(file_contents, reporter):
|
||||
- """Yield a series of Token objects, one for each preprocessing
|
||||
- token, comment, or chunk of whitespace within FILE_CONTENTS.
|
||||
- The REPORTER object is expected to have one method,
|
||||
- reporter.error(token, message), which will be called to
|
||||
- indicate a lexical error at the position of TOKEN.
|
||||
- If MESSAGE contains the four-character sequence '{!r}', that
|
||||
- is expected to be replaced by repr(token.text).
|
||||
- """
|
||||
+# Make available glibc Python modules.
|
||||
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
- Token = Token_
|
||||
- PP_TOKEN_RE = PP_TOKEN_RE_
|
||||
- ENDLINE_RE = ENDLINE_RE_
|
||||
- HEADER_NAME_RE = HEADER_NAME_RE_
|
||||
-
|
||||
- line_num = 1
|
||||
- line_start = 0
|
||||
- pos = 0
|
||||
- limit = len(file_contents)
|
||||
- directive = None
|
||||
- at_bol = True
|
||||
- while pos < limit:
|
||||
- if directive == "include":
|
||||
- mo = HEADER_NAME_RE.match(file_contents, pos)
|
||||
- if mo:
|
||||
- kind = "HEADER_NAME"
|
||||
- directive = "after_include"
|
||||
- else:
|
||||
- mo = PP_TOKEN_RE.match(file_contents, pos)
|
||||
- kind = mo.lastgroup
|
||||
- if kind != "WHITESPACE":
|
||||
- directive = "after_include"
|
||||
- else:
|
||||
- mo = PP_TOKEN_RE.match(file_contents, pos)
|
||||
- kind = mo.lastgroup
|
||||
-
|
||||
- text = mo.group()
|
||||
- line = line_num
|
||||
- column = mo.start() - line_start
|
||||
- adj_line_start = 0
|
||||
- # only these kinds can contain a newline
|
||||
- if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
|
||||
- "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
|
||||
- for tmo in ENDLINE_RE.finditer(text):
|
||||
- line_num += 1
|
||||
- adj_line_start = tmo.end()
|
||||
- if adj_line_start:
|
||||
- line_start = mo.start() + adj_line_start
|
||||
-
|
||||
- # Track whether or not we are scanning a preprocessing directive.
|
||||
- if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
|
||||
- at_bol = True
|
||||
- directive = None
|
||||
- else:
|
||||
- if kind == "PUNCTUATOR" and text == "#" and at_bol:
|
||||
- directive = "<null>"
|
||||
- elif kind == "IDENT" and directive == "<null>":
|
||||
- directive = text
|
||||
- at_bol = False
|
||||
-
|
||||
- # Report ill-formed tokens and rewrite them as their well-formed
|
||||
- # equivalents, so downstream processing doesn't have to know about them.
|
||||
- # (Rewriting instead of discarding provides better error recovery.)
|
||||
- if kind == "BAD_BLOCK_COM":
|
||||
- reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
|
||||
- "unclosed block comment")
|
||||
- text += "*/"
|
||||
- kind = "BLOCK_COMMENT"
|
||||
- elif kind == "BAD_STRING":
|
||||
- reporter.error(Token("BAD_STRING", "", line, column+1, ""),
|
||||
- "unclosed string")
|
||||
- text += "\""
|
||||
- kind = "STRING"
|
||||
- elif kind == "BAD_CHARCONST":
|
||||
- reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
|
||||
- "unclosed char constant")
|
||||
- text += "'"
|
||||
- kind = "CHARCONST"
|
||||
-
|
||||
- tok = Token(kind, text, line, column+1,
|
||||
- "include" if directive == "after_include" else directive)
|
||||
- # Do not complain about OTHER tokens inside macro definitions.
|
||||
- # $ and @ appear in macros defined by headers intended to be
|
||||
- # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
|
||||
- if kind == "OTHER" and directive != "define":
|
||||
- self.error(tok, "stray {!r} in program")
|
||||
-
|
||||
- yield tok
|
||||
- pos = mo.end()
|
||||
+import glibcpp
|
||||
|
||||
#
|
||||
# Base and generic classes for individual checks.
|
||||
@@ -446,7 +267,7 @@ class HeaderChecker:
|
||||
|
||||
typedef_checker = ObsoleteTypedefChecker(self, self.fname)
|
||||
|
||||
- for tok in tokenize_c(contents, self):
|
||||
+ for tok in glibcpp.tokenize_c(contents, self):
|
||||
typedef_checker.examine(tok)
|
||||
|
||||
def main():
|
||||
diff --git a/scripts/glibcpp.py b/scripts/glibcpp.py
|
||||
new file mode 100644
|
||||
index 0000000000000000..b44c6a4392dde8ce
|
||||
--- /dev/null
|
||||
+++ b/scripts/glibcpp.py
|
||||
@@ -0,0 +1,212 @@
|
||||
+#! /usr/bin/python3
|
||||
+# Approximation to C preprocessing.
|
||||
+# Copyright (C) 2019-2022 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/>.
|
||||
+
|
||||
+"""
|
||||
+Simplified lexical analyzer for C preprocessing tokens.
|
||||
+
|
||||
+Does not implement trigraphs.
|
||||
+
|
||||
+Does not implement backslash-newline in the middle of any lexical
|
||||
+item other than a string literal.
|
||||
+
|
||||
+Does not implement universal-character-names in identifiers.
|
||||
+
|
||||
+Treats prefixed strings (e.g. L"...") as two tokens (L and "...").
|
||||
+
|
||||
+Accepts non-ASCII characters only within comments and strings.
|
||||
+"""
|
||||
+
|
||||
+import collections
|
||||
+import re
|
||||
+
|
||||
+# Caution: The order of the outermost alternation matters.
|
||||
+# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
|
||||
+# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
|
||||
+# be last.
|
||||
+# Caution: There should be no capturing groups other than the named
|
||||
+# captures in the outermost alternation.
|
||||
+
|
||||
+# For reference, these are all of the C punctuators as of C11:
|
||||
+# [ ] ( ) { } , ; ? ~
|
||||
+# ! != * *= / /= ^ ^= = ==
|
||||
+# # ##
|
||||
+# % %= %> %: %:%:
|
||||
+# & &= &&
|
||||
+# | |= ||
|
||||
+# + += ++
|
||||
+# - -= -- ->
|
||||
+# . ...
|
||||
+# : :>
|
||||
+# < <% <: << <<= <=
|
||||
+# > >= >> >>=
|
||||
+
|
||||
+# The BAD_* tokens are not part of the official definition of pp-tokens;
|
||||
+# they match unclosed strings, character constants, and block comments,
|
||||
+# so that the regex engine doesn't have to backtrack all the way to the
|
||||
+# beginning of a broken construct and then emit dozens of junk tokens.
|
||||
+
|
||||
+PP_TOKEN_RE_ = re.compile(r"""
|
||||
+ (?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
|
||||
+ |(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*)
|
||||
+ |(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
|
||||
+ |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
|
||||
+ |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
|
||||
+ |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
|
||||
+ |(?P<LINE_COMMENT> //[^\r\n]*)
|
||||
+ |(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*)
|
||||
+ |(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
|
||||
+ |(?P<PUNCTUATOR>
|
||||
+ [,;?~(){}\[\]]
|
||||
+ | [!*/^=]=?
|
||||
+ | \#\#?
|
||||
+ | %(?:[=>]|:(?:%:)?)?
|
||||
+ | &[=&]?
|
||||
+ |\|[=|]?
|
||||
+ |\+[=+]?
|
||||
+ | -[=->]?
|
||||
+ |\.(?:\.\.)?
|
||||
+ | :>?
|
||||
+ | <(?:[%:]|<(?:=|<=?)?)?
|
||||
+ | >(?:=|>=?)?)
|
||||
+ |(?P<ESCNL> \\(?:\r|\n|\r\n))
|
||||
+ |(?P<WHITESPACE> [ \t\n\r\v\f]+)
|
||||
+ |(?P<OTHER> .)
|
||||
+""", re.DOTALL | re.VERBOSE)
|
||||
+
|
||||
+HEADER_NAME_RE_ = re.compile(r"""
|
||||
+ < [^>\r\n]+ >
|
||||
+ | " [^"\r\n]+ "
|
||||
+""", re.DOTALL | re.VERBOSE)
|
||||
+
|
||||
+ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
|
||||
+
|
||||
+# based on the sample code in the Python re documentation
|
||||
+Token_ = collections.namedtuple("Token", (
|
||||
+ "kind", "text", "line", "column", "context"))
|
||||
+Token_.__doc__ = """
|
||||
+ One C preprocessing token, comment, or chunk of whitespace.
|
||||
+ 'kind' identifies the token type, which will be one of:
|
||||
+ STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
|
||||
+ PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
|
||||
+ or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are
|
||||
+ handled within tokenize_c, below.
|
||||
+
|
||||
+ 'text' is the sequence of source characters making up the token;
|
||||
+ no decoding whatsoever is performed.
|
||||
+
|
||||
+ 'line' and 'column' give the position of the first character of the
|
||||
+ token within the source file. They are both 1-based.
|
||||
+
|
||||
+ 'context' indicates whether or not this token occurred within a
|
||||
+ preprocessing directive; it will be None for running text,
|
||||
+ '<null>' for the leading '#' of a directive line (because '#'
|
||||
+ all by itself on a line is a "null directive"), or the name of
|
||||
+ the directive for tokens within a directive line, starting with
|
||||
+ the IDENT for the name itself.
|
||||
+"""
|
||||
+
|
||||
+def tokenize_c(file_contents, reporter):
|
||||
+ """Yield a series of Token objects, one for each preprocessing
|
||||
+ token, comment, or chunk of whitespace within FILE_CONTENTS.
|
||||
+ The REPORTER object is expected to have one method,
|
||||
+ reporter.error(token, message), which will be called to
|
||||
+ indicate a lexical error at the position of TOKEN.
|
||||
+ If MESSAGE contains the four-character sequence '{!r}', that
|
||||
+ is expected to be replaced by repr(token.text).
|
||||
+ """
|
||||
+
|
||||
+ Token = Token_
|
||||
+ PP_TOKEN_RE = PP_TOKEN_RE_
|
||||
+ ENDLINE_RE = ENDLINE_RE_
|
||||
+ HEADER_NAME_RE = HEADER_NAME_RE_
|
||||
+
|
||||
+ line_num = 1
|
||||
+ line_start = 0
|
||||
+ pos = 0
|
||||
+ limit = len(file_contents)
|
||||
+ directive = None
|
||||
+ at_bol = True
|
||||
+ while pos < limit:
|
||||
+ if directive == "include":
|
||||
+ mo = HEADER_NAME_RE.match(file_contents, pos)
|
||||
+ if mo:
|
||||
+ kind = "HEADER_NAME"
|
||||
+ directive = "after_include"
|
||||
+ else:
|
||||
+ mo = PP_TOKEN_RE.match(file_contents, pos)
|
||||
+ kind = mo.lastgroup
|
||||
+ if kind != "WHITESPACE":
|
||||
+ directive = "after_include"
|
||||
+ else:
|
||||
+ mo = PP_TOKEN_RE.match(file_contents, pos)
|
||||
+ kind = mo.lastgroup
|
||||
+
|
||||
+ text = mo.group()
|
||||
+ line = line_num
|
||||
+ column = mo.start() - line_start
|
||||
+ adj_line_start = 0
|
||||
+ # only these kinds can contain a newline
|
||||
+ if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
|
||||
+ "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
|
||||
+ for tmo in ENDLINE_RE.finditer(text):
|
||||
+ line_num += 1
|
||||
+ adj_line_start = tmo.end()
|
||||
+ if adj_line_start:
|
||||
+ line_start = mo.start() + adj_line_start
|
||||
+
|
||||
+ # Track whether or not we are scanning a preprocessing directive.
|
||||
+ if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
|
||||
+ at_bol = True
|
||||
+ directive = None
|
||||
+ else:
|
||||
+ if kind == "PUNCTUATOR" and text == "#" and at_bol:
|
||||
+ directive = "<null>"
|
||||
+ elif kind == "IDENT" and directive == "<null>":
|
||||
+ directive = text
|
||||
+ at_bol = False
|
||||
+
|
||||
+ # Report ill-formed tokens and rewrite them as their well-formed
|
||||
+ # equivalents, so downstream processing doesn't have to know about them.
|
||||
+ # (Rewriting instead of discarding provides better error recovery.)
|
||||
+ if kind == "BAD_BLOCK_COM":
|
||||
+ reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
|
||||
+ "unclosed block comment")
|
||||
+ text += "*/"
|
||||
+ kind = "BLOCK_COMMENT"
|
||||
+ elif kind == "BAD_STRING":
|
||||
+ reporter.error(Token("BAD_STRING", "", line, column+1, ""),
|
||||
+ "unclosed string")
|
||||
+ text += "\""
|
||||
+ kind = "STRING"
|
||||
+ elif kind == "BAD_CHARCONST":
|
||||
+ reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
|
||||
+ "unclosed char constant")
|
||||
+ text += "'"
|
||||
+ kind = "CHARCONST"
|
||||
+
|
||||
+ tok = Token(kind, text, line, column+1,
|
||||
+ "include" if directive == "after_include" else directive)
|
||||
+ # Do not complain about OTHER tokens inside macro definitions.
|
||||
+ # $ and @ appear in macros defined by headers intended to be
|
||||
+ # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
|
||||
+ if kind == "OTHER" and directive != "define":
|
||||
+ self.error(tok, "stray {!r} in program")
|
||||
+
|
||||
+ yield tok
|
||||
+ pos = mo.end()
|
598
SOURCES/glibc-rh2109510-19.patch
Normal file
598
SOURCES/glibc-rh2109510-19.patch
Normal file
@ -0,0 +1,598 @@
|
||||
commit e6e6184bed490403811771fa527eb95b4ae53c7c
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Sep 22 12:10:41 2022 +0200
|
||||
|
||||
scripts: Enhance glibcpp to do basic macro processing
|
||||
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
support/Makefile
|
||||
(spurious tests sorting change upstream)
|
||||
|
||||
diff --git a/scripts/glibcpp.py b/scripts/glibcpp.py
|
||||
index b44c6a4392dde8ce..455459a609eab120 100644
|
||||
--- a/scripts/glibcpp.py
|
||||
+++ b/scripts/glibcpp.py
|
||||
@@ -33,7 +33,9 @@ Accepts non-ASCII characters only within comments and strings.
|
||||
"""
|
||||
|
||||
import collections
|
||||
+import operator
|
||||
import re
|
||||
+import sys
|
||||
|
||||
# Caution: The order of the outermost alternation matters.
|
||||
# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
|
||||
@@ -210,3 +212,318 @@ def tokenize_c(file_contents, reporter):
|
||||
|
||||
yield tok
|
||||
pos = mo.end()
|
||||
+
|
||||
+class MacroDefinition(collections.namedtuple('MacroDefinition',
|
||||
+ 'name_token args body error')):
|
||||
+ """A preprocessor macro definition.
|
||||
+
|
||||
+ name_token is the Token_ for the name.
|
||||
+
|
||||
+ args is None for a macro that is not function-like. Otherwise, it
|
||||
+ is a tuple that contains the macro argument name tokens.
|
||||
+
|
||||
+ body is a tuple that contains the tokens that constitue the body
|
||||
+ of the macro definition (excluding whitespace).
|
||||
+
|
||||
+ error is None if no error was detected, or otherwise a problem
|
||||
+ description associated with this macro definition.
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ @property
|
||||
+ def function(self):
|
||||
+ """Return true if the macro is function-like."""
|
||||
+ return self.args is not None
|
||||
+
|
||||
+ @property
|
||||
+ def name(self):
|
||||
+ """Return the name of the macro being defined."""
|
||||
+ return self.name_token.text
|
||||
+
|
||||
+ @property
|
||||
+ def line(self):
|
||||
+ """Return the line number of the macro defintion."""
|
||||
+ return self.name_token.line
|
||||
+
|
||||
+ @property
|
||||
+ def args_lowered(self):
|
||||
+ """Return the macro argument list as a list of strings"""
|
||||
+ if self.function:
|
||||
+ return [token.text for token in self.args]
|
||||
+ else:
|
||||
+ return None
|
||||
+
|
||||
+ @property
|
||||
+ def body_lowered(self):
|
||||
+ """Return the macro body as a list of strings."""
|
||||
+ return [token.text for token in self.body]
|
||||
+
|
||||
+def macro_definitions(tokens):
|
||||
+ """A generator for C macro definitions among tokens.
|
||||
+
|
||||
+ The generator yields MacroDefinition objects.
|
||||
+
|
||||
+ tokens must be iterable, yielding Token_ objects.
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ macro_name = None
|
||||
+ macro_start = False # Set to false after macro name and one otken.
|
||||
+ macro_args = None # Set to a list during the macro argument sequence.
|
||||
+ in_macro_args = False # True while processing macro identifier-list.
|
||||
+ error = None
|
||||
+ body = []
|
||||
+
|
||||
+ for token in tokens:
|
||||
+ if token.context == 'define' and macro_name is None \
|
||||
+ and token.kind == 'IDENT':
|
||||
+ # Starting up macro processing.
|
||||
+ if macro_start:
|
||||
+ # First identifier is the macro name.
|
||||
+ macro_name = token
|
||||
+ else:
|
||||
+ # Next token is the name.
|
||||
+ macro_start = True
|
||||
+ continue
|
||||
+
|
||||
+ if macro_name is None:
|
||||
+ # Drop tokens not in macro definitions.
|
||||
+ continue
|
||||
+
|
||||
+ if token.context != 'define':
|
||||
+ # End of the macro definition.
|
||||
+ if in_macro_args and error is None:
|
||||
+ error = 'macro definition ends in macro argument list'
|
||||
+ yield MacroDefinition(macro_name, macro_args, tuple(body), error)
|
||||
+ # No longer in a macro definition.
|
||||
+ macro_name = None
|
||||
+ macro_start = False
|
||||
+ macro_args = None
|
||||
+ in_macro_args = False
|
||||
+ error = None
|
||||
+ body.clear()
|
||||
+ continue
|
||||
+
|
||||
+ if macro_start:
|
||||
+ # First token after the macro name.
|
||||
+ macro_start = False
|
||||
+ if token.kind == 'PUNCTUATOR' and token.text == '(':
|
||||
+ macro_args = []
|
||||
+ in_macro_args = True
|
||||
+ continue
|
||||
+
|
||||
+ if in_macro_args:
|
||||
+ if token.kind == 'IDENT' \
|
||||
+ or (token.kind == 'PUNCTUATOR' and token.text == '...'):
|
||||
+ # Macro argument or ... placeholder.
|
||||
+ macro_args.append(token)
|
||||
+ if token.kind == 'PUNCTUATOR':
|
||||
+ if token.text == ')':
|
||||
+ macro_args = tuple(macro_args)
|
||||
+ in_macro_args = False
|
||||
+ elif token.text == ',':
|
||||
+ pass # Skip. Not a full syntax check.
|
||||
+ elif error is None:
|
||||
+ error = 'invalid punctuator in macro argument list: ' \
|
||||
+ + repr(token.text)
|
||||
+ elif error is None:
|
||||
+ error = 'invalid {} token in macro argument list'.format(
|
||||
+ token.kind)
|
||||
+ continue
|
||||
+
|
||||
+ if token.kind not in ('WHITESPACE', 'BLOCK_COMMENT'):
|
||||
+ body.append(token)
|
||||
+
|
||||
+ # Emit the macro in case the last line does not end with a newline.
|
||||
+ if macro_name is not None:
|
||||
+ if in_macro_args and error is None:
|
||||
+ error = 'macro definition ends in macro argument list'
|
||||
+ yield MacroDefinition(macro_name, macro_args, tuple(body), error)
|
||||
+
|
||||
+# Used to split UL etc. suffixes from numbers such as 123UL.
|
||||
+RE_SPLIT_INTEGER_SUFFIX = re.compile(r'([^ullULL]+)([ullULL]*)')
|
||||
+
|
||||
+BINARY_OPERATORS = {
|
||||
+ '+': operator.add,
|
||||
+ '<<': operator.lshift,
|
||||
+}
|
||||
+
|
||||
+# Use the general-purpose dict type if it is order-preserving.
|
||||
+if (sys.version_info[0], sys.version_info[1]) <= (3, 6):
|
||||
+ OrderedDict = collections.OrderedDict
|
||||
+else:
|
||||
+ OrderedDict = dict
|
||||
+
|
||||
+def macro_eval(macro_defs, reporter):
|
||||
+ """Compute macro values
|
||||
+
|
||||
+ macro_defs is the output from macro_definitions. reporter is an
|
||||
+ object that accepts reporter.error(line_number, message) and
|
||||
+ reporter.note(line_number, message) calls to report errors
|
||||
+ and error context invocations.
|
||||
+
|
||||
+ The returned dict contains the values of macros which are not
|
||||
+ function-like, pairing their names with their computed values.
|
||||
+
|
||||
+ The current implementation is incomplete. It is deliberately not
|
||||
+ entirely faithful to C, even in the implemented parts. It checks
|
||||
+ that macro replacements follow certain syntactic rules even if
|
||||
+ they are never evaluated.
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ # Unevaluated macro definitions by name.
|
||||
+ definitions = OrderedDict()
|
||||
+ for md in macro_defs:
|
||||
+ if md.name in definitions:
|
||||
+ reporter.error(md.line, 'macro {} redefined'.format(md.name))
|
||||
+ reporter.note(definitions[md.name].line,
|
||||
+ 'location of previous definition')
|
||||
+ else:
|
||||
+ definitions[md.name] = md
|
||||
+
|
||||
+ # String to value mappings for fully evaluated macros.
|
||||
+ evaluated = OrderedDict()
|
||||
+
|
||||
+ # String to macro definitions during evaluation. Nice error
|
||||
+ # reporting relies on determinstic iteration order.
|
||||
+ stack = OrderedDict()
|
||||
+
|
||||
+ def eval_token(current, token):
|
||||
+ """Evaluate one macro token.
|
||||
+
|
||||
+ Integers and strings are returned as such (the latter still
|
||||
+ quoted). Identifiers are expanded.
|
||||
+
|
||||
+ None indicates an empty expansion or an error.
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ if token.kind == 'PP_NUMBER':
|
||||
+ value = None
|
||||
+ m = RE_SPLIT_INTEGER_SUFFIX.match(token.text)
|
||||
+ if m:
|
||||
+ try:
|
||||
+ value = int(m.group(1), 0)
|
||||
+ except ValueError:
|
||||
+ pass
|
||||
+ if value is None:
|
||||
+ reporter.error(token.line,
|
||||
+ 'invalid number {!r} in definition of {}'.format(
|
||||
+ token.text, current.name))
|
||||
+ return value
|
||||
+
|
||||
+ if token.kind == 'STRING':
|
||||
+ return token.text
|
||||
+
|
||||
+ if token.kind == 'CHARCONST' and len(token.text) == 3:
|
||||
+ return ord(token.text[1])
|
||||
+
|
||||
+ if token.kind == 'IDENT':
|
||||
+ name = token.text
|
||||
+ result = eval1(current, name)
|
||||
+ if name not in evaluated:
|
||||
+ evaluated[name] = result
|
||||
+ return result
|
||||
+
|
||||
+ reporter.error(token.line,
|
||||
+ 'unrecognized {!r} in definition of {}'.format(
|
||||
+ token.text, current.name))
|
||||
+ return None
|
||||
+
|
||||
+
|
||||
+ def eval1(current, name):
|
||||
+ """Evaluate one name.
|
||||
+
|
||||
+ The name is looked up and the macro definition evaluated
|
||||
+ recursively if necessary. The current argument is the macro
|
||||
+ definition being evaluated.
|
||||
+
|
||||
+ None as a return value indicates an error.
|
||||
+
|
||||
+ """
|
||||
+
|
||||
+ # Fast path if the value has already been evaluated.
|
||||
+ if name in evaluated:
|
||||
+ return evaluated[name]
|
||||
+
|
||||
+ try:
|
||||
+ md = definitions[name]
|
||||
+ except KeyError:
|
||||
+ reporter.error(current.line,
|
||||
+ 'reference to undefined identifier {} in definition of {}'
|
||||
+ .format(name, current.name))
|
||||
+ return None
|
||||
+
|
||||
+ if md.name in stack:
|
||||
+ # Recursive macro definition.
|
||||
+ md = stack[name]
|
||||
+ reporter.error(md.line,
|
||||
+ 'macro definition {} refers to itself'.format(md.name))
|
||||
+ for md1 in reversed(list(stack.values())):
|
||||
+ if md1 is md:
|
||||
+ break
|
||||
+ reporter.note(md1.line,
|
||||
+ 'evaluated from {}'.format(md1.name))
|
||||
+ return None
|
||||
+
|
||||
+ stack[md.name] = md
|
||||
+ if md.function:
|
||||
+ reporter.error(current.line,
|
||||
+ 'attempt to evaluate function-like macro {}'.format(name))
|
||||
+ reporter.note(md.line, 'definition of {}'.format(md.name))
|
||||
+ return None
|
||||
+
|
||||
+ try:
|
||||
+ body = md.body
|
||||
+ if len(body) == 0:
|
||||
+ # Empty expansion.
|
||||
+ return None
|
||||
+
|
||||
+ # Remove surrounding ().
|
||||
+ if body[0].text == '(' and body[-1].text == ')':
|
||||
+ body = body[1:-1]
|
||||
+ had_parens = True
|
||||
+ else:
|
||||
+ had_parens = False
|
||||
+
|
||||
+ if len(body) == 1:
|
||||
+ return eval_token(md, body[0])
|
||||
+
|
||||
+ # Minimal expression evaluator for binary operators.
|
||||
+ op = body[1].text
|
||||
+ if len(body) == 3 and op in BINARY_OPERATORS:
|
||||
+ if not had_parens:
|
||||
+ reporter.error(body[1].line,
|
||||
+ 'missing parentheses around {} expression'.format(op))
|
||||
+ reporter.note(md.line,
|
||||
+ 'in definition of macro {}'.format(md.name))
|
||||
+
|
||||
+ left = eval_token(md, body[0])
|
||||
+ right = eval_token(md, body[2])
|
||||
+
|
||||
+ if type(left) != type(1):
|
||||
+ reporter.error(left.line,
|
||||
+ 'left operand of {} is not an integer'.format(op))
|
||||
+ reporter.note(md.line,
|
||||
+ 'in definition of macro {}'.format(md.name))
|
||||
+ if type(right) != type(1):
|
||||
+ reporter.error(left.line,
|
||||
+ 'right operand of {} is not an integer'.format(op))
|
||||
+ reporter.note(md.line,
|
||||
+ 'in definition of macro {}'.format(md.name))
|
||||
+ return BINARY_OPERATORS[op](left, right)
|
||||
+
|
||||
+ reporter.error(md.line,
|
||||
+ 'uninterpretable macro token sequence: {}'.format(
|
||||
+ ' '.join(md.body_lowered)))
|
||||
+ return None
|
||||
+ finally:
|
||||
+ del stack[md.name]
|
||||
+
|
||||
+ # Start of main body of macro_eval.
|
||||
+ for md in definitions.values():
|
||||
+ name = md.name
|
||||
+ if name not in evaluated and not md.function:
|
||||
+ evaluated[name] = eval1(md, name)
|
||||
+ return evaluated
|
||||
diff --git a/support/Makefile b/support/Makefile
|
||||
index 09b41b0d57e9239a..7749ac24f1ac3622 100644
|
||||
--- a/support/Makefile
|
||||
+++ b/support/Makefile
|
||||
@@ -223,11 +223,11 @@ $(objpfx)true-container : $(libsupport)
|
||||
tests = \
|
||||
README-testing \
|
||||
tst-support-namespace \
|
||||
+ tst-support-process_state \
|
||||
tst-support_blob_repeat \
|
||||
tst-support_capture_subprocess \
|
||||
tst-support_descriptors \
|
||||
tst-support_format_dns_packet \
|
||||
- tst-support-process_state \
|
||||
tst-support_quote_blob \
|
||||
tst-support_quote_string \
|
||||
tst-support_record_failure \
|
||||
@@ -248,6 +248,12 @@ $(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \
|
||||
$(evaluate-test)
|
||||
endif
|
||||
|
||||
+tests-special += $(objpfx)tst-glibcpp.out
|
||||
+
|
||||
+$(objpfx)tst-glibcpp.out: tst-glibcpp.py $(..)scripts/glibcpp.py
|
||||
+ PYTHONPATH=$(..)scripts $(PYTHON) tst-glibcpp.py > $@ 2>&1; \
|
||||
+ $(evaluate-test)
|
||||
+
|
||||
$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
|
||||
|
||||
tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd)
|
||||
diff --git a/support/tst-glibcpp.py b/support/tst-glibcpp.py
|
||||
new file mode 100644
|
||||
index 0000000000000000..a2db1916ccfce3c3
|
||||
--- /dev/null
|
||||
+++ b/support/tst-glibcpp.py
|
||||
@@ -0,0 +1,217 @@
|
||||
+#! /usr/bin/python3
|
||||
+# Tests for scripts/glibcpp.py
|
||||
+# Copyright (C) 2022 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 inspect
|
||||
+import sys
|
||||
+
|
||||
+import glibcpp
|
||||
+
|
||||
+# Error counter.
|
||||
+errors = 0
|
||||
+
|
||||
+class TokenizerErrors:
|
||||
+ """Used as the error reporter during tokenization."""
|
||||
+
|
||||
+ def __init__(self):
|
||||
+ self.errors = []
|
||||
+
|
||||
+ def error(self, token, message):
|
||||
+ self.errors.append((token, message))
|
||||
+
|
||||
+def check_macro_definitions(source, expected):
|
||||
+ reporter = TokenizerErrors()
|
||||
+ tokens = glibcpp.tokenize_c(source, reporter)
|
||||
+
|
||||
+ actual = []
|
||||
+ for md in glibcpp.macro_definitions(tokens):
|
||||
+ if md.function:
|
||||
+ md_name = '{}({})'.format(md.name, ','.join(md.args_lowered))
|
||||
+ else:
|
||||
+ md_name = md.name
|
||||
+ actual.append((md_name, md.body_lowered))
|
||||
+
|
||||
+ if actual != expected or reporter.errors:
|
||||
+ global errors
|
||||
+ errors += 1
|
||||
+ # Obtain python source line information.
|
||||
+ frame = inspect.stack(2)[1]
|
||||
+ print('{}:{}: error: macro definition mismatch, actual definitions:'
|
||||
+ .format(frame[1], frame[2]))
|
||||
+ for md in actual:
|
||||
+ print('note: {} {!r}'.format(md[0], md[1]))
|
||||
+
|
||||
+ if reporter.errors:
|
||||
+ for err in reporter.errors:
|
||||
+ print('note: tokenizer error: {}: {}'.format(
|
||||
+ err[0].line, err[1]))
|
||||
+
|
||||
+def check_macro_eval(source, expected, expected_errors=''):
|
||||
+ reporter = TokenizerErrors()
|
||||
+ tokens = list(glibcpp.tokenize_c(source, reporter))
|
||||
+
|
||||
+ if reporter.errors:
|
||||
+ # Obtain python source line information.
|
||||
+ frame = inspect.stack(2)[1]
|
||||
+ for err in reporter.errors:
|
||||
+ print('{}:{}: tokenizer error: {}: {}'.format(
|
||||
+ frame[1], frame[2], err[0].line, err[1]))
|
||||
+ return
|
||||
+
|
||||
+ class EvalReporter:
|
||||
+ """Used as the error reporter during evaluation."""
|
||||
+
|
||||
+ def __init__(self):
|
||||
+ self.lines = []
|
||||
+
|
||||
+ def error(self, line, message):
|
||||
+ self.lines.append('{}: error: {}\n'.format(line, message))
|
||||
+
|
||||
+ def note(self, line, message):
|
||||
+ self.lines.append('{}: note: {}\n'.format(line, message))
|
||||
+
|
||||
+ reporter = EvalReporter()
|
||||
+ actual = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter)
|
||||
+ actual_errors = ''.join(reporter.lines)
|
||||
+ if actual != expected or actual_errors != expected_errors:
|
||||
+ global errors
|
||||
+ errors += 1
|
||||
+ # Obtain python source line information.
|
||||
+ frame = inspect.stack(2)[1]
|
||||
+ print('{}:{}: error: macro evaluation mismatch, actual results:'
|
||||
+ .format(frame[1], frame[2]))
|
||||
+ for k, v in actual.items():
|
||||
+ print(' {}: {!r}'.format(k, v))
|
||||
+ for msg in reporter.lines:
|
||||
+ sys.stdout.write(' | ' + msg)
|
||||
+
|
||||
+# Individual test cases follow.
|
||||
+
|
||||
+check_macro_definitions('', [])
|
||||
+check_macro_definitions('int main()\n{\n{\n', [])
|
||||
+check_macro_definitions("""
|
||||
+#define A 1
|
||||
+#define B 2 /* ignored */
|
||||
+#define C 3 // also ignored
|
||||
+#define D \
|
||||
+ 4
|
||||
+#define STRING "string"
|
||||
+#define FUNCLIKE(a, b) (a + b)
|
||||
+#define FUNCLIKE2(a, b) (a + \
|
||||
+ b)
|
||||
+""", [('A', ['1']),
|
||||
+ ('B', ['2']),
|
||||
+ ('C', ['3']),
|
||||
+ ('D', ['4']),
|
||||
+ ('STRING', ['"string"']),
|
||||
+ ('FUNCLIKE(a,b)', list('(a+b)')),
|
||||
+ ('FUNCLIKE2(a,b)', list('(a+b)')),
|
||||
+ ])
|
||||
+check_macro_definitions('#define MACRO', [('MACRO', [])])
|
||||
+check_macro_definitions('#define MACRO\n', [('MACRO', [])])
|
||||
+check_macro_definitions('#define MACRO()', [('MACRO()', [])])
|
||||
+check_macro_definitions('#define MACRO()\n', [('MACRO()', [])])
|
||||
+
|
||||
+check_macro_eval('#define A 1', {'A': 1})
|
||||
+check_macro_eval('#define A (1)', {'A': 1})
|
||||
+check_macro_eval('#define A (1 + 1)', {'A': 2})
|
||||
+check_macro_eval('#define A (1U << 31)', {'A': 1 << 31})
|
||||
+check_macro_eval('''\
|
||||
+#define A (B + 1)
|
||||
+#define B 10
|
||||
+#define F(x) ignored
|
||||
+#define C "not ignored"
|
||||
+''', {
|
||||
+ 'A': 11,
|
||||
+ 'B': 10,
|
||||
+ 'C': '"not ignored"',
|
||||
+})
|
||||
+
|
||||
+# Checking for evaluation errors.
|
||||
+check_macro_eval('''\
|
||||
+#define A 1
|
||||
+#define A 2
|
||||
+''', {
|
||||
+ 'A': 1,
|
||||
+}, '''\
|
||||
+2: error: macro A redefined
|
||||
+1: note: location of previous definition
|
||||
+''')
|
||||
+
|
||||
+check_macro_eval('''\
|
||||
+#define A A
|
||||
+#define B 1
|
||||
+''', {
|
||||
+ 'A': None,
|
||||
+ 'B': 1,
|
||||
+}, '''\
|
||||
+1: error: macro definition A refers to itself
|
||||
+''')
|
||||
+
|
||||
+check_macro_eval('''\
|
||||
+#define A B
|
||||
+#define B A
|
||||
+''', {
|
||||
+ 'A': None,
|
||||
+ 'B': None,
|
||||
+}, '''\
|
||||
+1: error: macro definition A refers to itself
|
||||
+2: note: evaluated from B
|
||||
+''')
|
||||
+
|
||||
+check_macro_eval('''\
|
||||
+#define A B
|
||||
+#define B C
|
||||
+#define C A
|
||||
+''', {
|
||||
+ 'A': None,
|
||||
+ 'B': None,
|
||||
+ 'C': None,
|
||||
+}, '''\
|
||||
+1: error: macro definition A refers to itself
|
||||
+3: note: evaluated from C
|
||||
+2: note: evaluated from B
|
||||
+''')
|
||||
+
|
||||
+check_macro_eval('''\
|
||||
+#define A 1 +
|
||||
+''', {
|
||||
+ 'A': None,
|
||||
+}, '''\
|
||||
+1: error: uninterpretable macro token sequence: 1 +
|
||||
+''')
|
||||
+
|
||||
+check_macro_eval('''\
|
||||
+#define A 3*5
|
||||
+''', {
|
||||
+ 'A': None,
|
||||
+}, '''\
|
||||
+1: error: uninterpretable macro token sequence: 3 * 5
|
||||
+''')
|
||||
+
|
||||
+check_macro_eval('''\
|
||||
+#define A 3 + 5
|
||||
+''', {
|
||||
+ 'A': 8,
|
||||
+}, '''\
|
||||
+1: error: missing parentheses around + expression
|
||||
+1: note: in definition of macro A
|
||||
+''')
|
||||
+
|
||||
+if errors:
|
||||
+ sys.exit(1)
|
208
SOURCES/glibc-rh2109510-2.patch
Normal file
208
SOURCES/glibc-rh2109510-2.patch
Normal file
@ -0,0 +1,208 @@
|
||||
Partial backport of:
|
||||
|
||||
commit 7e1d42400c1b8f03316fe14176133c8853cd3bbe
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Fri Nov 30 15:20:41 2018 +0000
|
||||
|
||||
Replace gen-as-const.awk by gen-as-const.py.
|
||||
|
||||
This patch replaces gen-as-const.awk, and some fragments of the
|
||||
Makefile code that used it, by a Python script. The point is not such
|
||||
much that awk is problematic for this particular script, as that I'd
|
||||
like to build up a general Python infrastructure for extracting
|
||||
information from C headers, for use in writing tests of such headers.
|
||||
Thus, although this patch does not set up such infrastructure, the
|
||||
compute_c_consts function in gen-as-const.py might be moved to a
|
||||
separate Python module in a subsequent patch as a starting point for
|
||||
such infrastructure.
|
||||
|
||||
The general idea of the code is the same as in the awk version, but no
|
||||
attempt is made to make the output files textually identical. When
|
||||
generating a header, a dict of constant names and values is generated
|
||||
internally then defines are printed in sorted order (rather than the
|
||||
order in the .sym file, which would have been used before). When
|
||||
generating a test that the values computed match those from a normal
|
||||
header inclusion, the test code is made into a compilation test using
|
||||
_Static_assert, where previously the comparisons were done only when
|
||||
the test was executed. One fragment of test generation (converting
|
||||
the previously generated header to use asconst_* prefixes on its macro
|
||||
names) is still in awk code in the makefiles; only the .sym processing
|
||||
and subsequent execution of the compiler to extract constants have
|
||||
moved to the Python script.
|
||||
|
||||
Tested for x86_64, and with build-many-glibcs.py.
|
||||
|
||||
* scripts/gen-as-const.py: New file.
|
||||
* scripts/gen-as-const.awk: Remove.
|
||||
* Makerules ($(common-objpfx)%.h $(common-objpfx)%.h.d): Use
|
||||
gen-as-const.py.
|
||||
($(objpfx)test-as-const-%.c): Likewise.
|
||||
|
||||
In the downstream version, scripts/gen-as-const.awk is not removed and
|
||||
still used in Makerules.
|
||||
|
||||
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
|
||||
new file mode 100644
|
||||
index 0000000000000000..b7a5744bb192dd67
|
||||
--- /dev/null
|
||||
+++ b/scripts/gen-as-const.py
|
||||
@@ -0,0 +1,159 @@
|
||||
+#!/usr/bin/python3
|
||||
+# Produce headers of assembly constants from C expressions.
|
||||
+# Copyright (C) 2018 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
|
||||
+# <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+# The input to this script looks like:
|
||||
+# #cpp-directive ...
|
||||
+# NAME1
|
||||
+# NAME2 expression ...
|
||||
+# A line giving just a name implies an expression consisting of just that name.
|
||||
+
|
||||
+import argparse
|
||||
+import os.path
|
||||
+import re
|
||||
+import subprocess
|
||||
+import tempfile
|
||||
+
|
||||
+
|
||||
+def compute_c_consts(sym_data, cc):
|
||||
+ """Compute the values of some C constants.
|
||||
+
|
||||
+ The first argument is a list whose elements are either strings
|
||||
+ (preprocessor directives) or pairs of strings (a name and a C
|
||||
+ expression for the corresponding value). Preprocessor directives
|
||||
+ in the middle of the list may be used to select which constants
|
||||
+ end up being evaluated using which expressions.
|
||||
+
|
||||
+ """
|
||||
+ out_lines = []
|
||||
+ started = False
|
||||
+ for arg in sym_data:
|
||||
+ if isinstance(arg, str):
|
||||
+ out_lines.append(arg)
|
||||
+ continue
|
||||
+ name = arg[0]
|
||||
+ value = arg[1]
|
||||
+ if not started:
|
||||
+ out_lines.append('void\ndummy (void)\n{')
|
||||
+ started = True
|
||||
+ out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
|
||||
+ ': : \"i\" ((long int) (%s)));'
|
||||
+ % (name, value))
|
||||
+ if started:
|
||||
+ out_lines.append('}')
|
||||
+ out_lines.append('')
|
||||
+ out_text = '\n'.join(out_lines)
|
||||
+ with tempfile.TemporaryDirectory() as temp_dir:
|
||||
+ c_file_name = os.path.join(temp_dir, 'test.c')
|
||||
+ s_file_name = os.path.join(temp_dir, 'test.s')
|
||||
+ with open(c_file_name, 'w') as c_file:
|
||||
+ c_file.write(out_text)
|
||||
+ # Compilation has to be from stdin to avoid the temporary file
|
||||
+ # name being written into the generated dependencies.
|
||||
+ cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name))
|
||||
+ subprocess.check_call(cmd, shell=True)
|
||||
+ consts = {}
|
||||
+ with open(s_file_name, 'r') as s_file:
|
||||
+ for line in s_file:
|
||||
+ match = re.search('@@@name@@@([^@]*)'
|
||||
+ '@@@value@@@[^0-9Xxa-fA-F-]*'
|
||||
+ '([0-9Xxa-fA-F-]+).*@@@end@@@', line)
|
||||
+ if match:
|
||||
+ if (match.group(1) in consts
|
||||
+ and match.group(2) != consts[match.group(1)]):
|
||||
+ raise ValueError('duplicate constant %s'
|
||||
+ % match.group(1))
|
||||
+ consts[match.group(1)] = match.group(2)
|
||||
+ return consts
|
||||
+
|
||||
+
|
||||
+def gen_test(sym_data):
|
||||
+ """Generate a test for the values of some C constants.
|
||||
+
|
||||
+ The first argument is as for compute_c_consts.
|
||||
+
|
||||
+ """
|
||||
+ out_lines = []
|
||||
+ started = False
|
||||
+ for arg in sym_data:
|
||||
+ if isinstance(arg, str):
|
||||
+ out_lines.append(arg)
|
||||
+ continue
|
||||
+ name = arg[0]
|
||||
+ value = arg[1]
|
||||
+ if not started:
|
||||
+ out_lines.append('#include <stdint.h>\n'
|
||||
+ '#include <stdio.h>\n'
|
||||
+ '#include <bits/wordsize.h>\n'
|
||||
+ '#if __WORDSIZE == 64\n'
|
||||
+ 'typedef uint64_t c_t;\n'
|
||||
+ '# define U(n) UINT64_C (n)\n'
|
||||
+ '#else\n'
|
||||
+ 'typedef uint32_t c_t;\n'
|
||||
+ '# define U(n) UINT32_C (n)\n'
|
||||
+ '#endif\n'
|
||||
+ 'static int\n'
|
||||
+ 'do_test (void)\n'
|
||||
+ '{\n'
|
||||
+ # Compilation test only, using static assertions.
|
||||
+ ' return 0;\n'
|
||||
+ '}\n'
|
||||
+ '#include <support/test-driver.c>')
|
||||
+ started = True
|
||||
+ out_lines.append('_Static_assert (U (asconst_%s) == (c_t) (%s), '
|
||||
+ '"value of %s");'
|
||||
+ % (name, value, name))
|
||||
+ return '\n'.join(out_lines)
|
||||
+
|
||||
+
|
||||
+def main():
|
||||
+ """The main entry point."""
|
||||
+ parser = argparse.ArgumentParser(
|
||||
+ description='Produce headers of assembly constants.')
|
||||
+ parser.add_argument('--cc', metavar='CC',
|
||||
+ help='C compiler (including options) to use')
|
||||
+ parser.add_argument('--test', action='store_true',
|
||||
+ help='Generate test case instead of header')
|
||||
+ parser.add_argument('sym_file',
|
||||
+ help='.sym file to process')
|
||||
+ args = parser.parse_args()
|
||||
+ sym_data = []
|
||||
+ with open(args.sym_file, 'r') as sym_file:
|
||||
+ for line in sym_file:
|
||||
+ line = line.strip()
|
||||
+ if line == '':
|
||||
+ continue
|
||||
+ # Pass preprocessor directives through.
|
||||
+ if line.startswith('#'):
|
||||
+ sym_data.append(line)
|
||||
+ continue
|
||||
+ words = line.split(maxsplit=1)
|
||||
+ # Separator.
|
||||
+ if words[0] == '--':
|
||||
+ continue
|
||||
+ name = words[0]
|
||||
+ value = words[1] if len(words) > 1 else words[0]
|
||||
+ sym_data.append((name, value))
|
||||
+ if args.test:
|
||||
+ print(gen_test(sym_data))
|
||||
+ else:
|
||||
+ consts = compute_c_consts(sym_data, args.cc)
|
||||
+ print('\n'.join('#define %s %s' % c for c in sorted(consts.items())))
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ main()
|
36
SOURCES/glibc-rh2109510-20.patch
Normal file
36
SOURCES/glibc-rh2109510-20.patch
Normal file
@ -0,0 +1,36 @@
|
||||
commit 29eb7961197bee68470730aecfdda4d0e206812e
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Sep 5 12:11:19 2022 +0200
|
||||
|
||||
elf.h: Remove duplicate definition of VER_FLG_WEAK
|
||||
|
||||
This did not cause a warning before because the token sequence for
|
||||
the two definitions was identical.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/elf/elf.h b/elf/elf.h
|
||||
index d6506ea1c7160dea..ec09040be639a52a 100644
|
||||
--- a/elf/elf.h
|
||||
+++ b/elf/elf.h
|
||||
@@ -1027,7 +1027,8 @@ typedef struct
|
||||
|
||||
/* Legal values for vd_flags (version information flags). */
|
||||
#define VER_FLG_BASE 0x1 /* Version definition of file itself */
|
||||
-#define VER_FLG_WEAK 0x2 /* Weak version identifier */
|
||||
+#define VER_FLG_WEAK 0x2 /* Weak version identifier. Also
|
||||
+ used by vna_flags below. */
|
||||
|
||||
/* Versym symbol index values. */
|
||||
#define VER_NDX_LOCAL 0 /* Symbol is local. */
|
||||
@@ -1105,10 +1106,6 @@ typedef struct
|
||||
} Elf64_Vernaux;
|
||||
|
||||
|
||||
-/* Legal values for vna_flags. */
|
||||
-#define VER_FLG_WEAK 0x2 /* Weak version identifier */
|
||||
-
|
||||
-
|
||||
/* Auxiliary vector. */
|
||||
|
||||
/* This vector is normally only used by the program interpreter. The
|
1295
SOURCES/glibc-rh2109510-21.patch
Normal file
1295
SOURCES/glibc-rh2109510-21.patch
Normal file
File diff suppressed because it is too large
Load Diff
34
SOURCES/glibc-rh2109510-22.patch
Normal file
34
SOURCES/glibc-rh2109510-22.patch
Normal file
@ -0,0 +1,34 @@
|
||||
commit d33705c0b020632274318323931695a99753b5be
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Nov 3 12:24:17 2022 +0100
|
||||
|
||||
scripts/glibcelf.py: Properly report <elf.h> parsing failures
|
||||
|
||||
Without this change, parse failures result in an exception:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "tst-glibcelf.py", line 23, in <module>
|
||||
import glibcelf
|
||||
File "/path/to/git/scripts/glibcelf.py", line 226, in <module>
|
||||
_elf_h = _parse_elf_h()
|
||||
File "/path/to/git/scripts/glibcelf.py", line 221, in _parse_elf_h
|
||||
result = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter)
|
||||
File "/path/to/git/scripts/glibcpp.py", line 379, in macro_eval
|
||||
reporter.error(md.line, 'macro {} redefined'.format(md.name))
|
||||
File "/path/to/git/scripts/glibcelf.py", line 214, in error
|
||||
errors += 1
|
||||
UnboundLocalError: local variable 'errors' referenced before assignment
|
||||
|
||||
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
|
||||
index 420cb21943b28bba..59aab56ecf9deb3e 100644
|
||||
--- a/scripts/glibcelf.py
|
||||
+++ b/scripts/glibcelf.py
|
||||
@@ -211,7 +211,7 @@ def _parse_elf_h():
|
||||
self.errors = 0
|
||||
|
||||
def error(self, line, message):
|
||||
- errors += 1
|
||||
+ self.errors += 1
|
||||
print('{}:{}: error: {}'.format(path, line, message))
|
||||
|
||||
def note(self, line, message):
|
108
SOURCES/glibc-rh2109510-23.patch
Normal file
108
SOURCES/glibc-rh2109510-23.patch
Normal file
@ -0,0 +1,108 @@
|
||||
Downstream-only adjustments to scripts/glibcelf.py. We do not have
|
||||
CSKY nor RISC-V constants in <elf.h>, so glibcelf cannot extract
|
||||
those. PT_AARCH64_* constants are missing as well.
|
||||
|
||||
Adjust elf/tst-glibcelf.py to use PT_MIPS_OPTIONS instead of
|
||||
PT_AARCH64_MEMTAG_MTE for testing. It has the same numeric value
|
||||
(0x70000002).
|
||||
|
||||
diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py
|
||||
index a5bff45eae55edea..9cb0861589d6ae2e 100644
|
||||
--- a/elf/tst-glibcelf.py
|
||||
+++ b/elf/tst-glibcelf.py
|
||||
@@ -75,15 +75,17 @@ def check_basic():
|
||||
if repr(glibcelf.Pt(17609)) != 'Pt(17609)':
|
||||
error('repr(Pt(17609))')
|
||||
|
||||
- if glibcelf.Pt('PT_AARCH64_MEMTAG_MTE') \
|
||||
- is not glibcelf.Pt.PT_AARCH64_MEMTAG_MTE:
|
||||
- error('PT_AARCH64_MEMTAG_MTE identity')
|
||||
- if glibcelf.Pt(0x70000002) is glibcelf.Pt.PT_AARCH64_MEMTAG_MTE:
|
||||
+ # Note: Upstream uses PT_AARCH64_MEMTAG_MTE instead of PT_MIPS_OPTIONS.
|
||||
+ # PT_AARCH64_MEMTAG_MTE is not yet available downstream.
|
||||
+ if glibcelf.Pt('PT_MIPS_OPTIONS') \
|
||||
+ is not glibcelf.Pt.PT_MIPS_OPTIONS:
|
||||
+ error('PT_MIPS_OPTIONS identity')
|
||||
+ if glibcelf.Pt(0x70000002) is glibcelf.Pt.PT_MIPS_OPTIONS:
|
||||
error('Pt(0x70000002) identity')
|
||||
- if glibcelf.PtAARCH64(0x70000002) is not glibcelf.Pt.PT_AARCH64_MEMTAG_MTE:
|
||||
- error('PtAARCH64(0x70000002) identity')
|
||||
- if glibcelf.Pt.PT_AARCH64_MEMTAG_MTE.short_name != 'AARCH64_MEMTAG_MTE':
|
||||
- error('PT_AARCH64_MEMTAG_MTE short name')
|
||||
+ if glibcelf.PtMIPS(0x70000002) is not glibcelf.Pt.PT_MIPS_OPTIONS:
|
||||
+ error('PtMIPS(0x70000002) identity')
|
||||
+ if glibcelf.Pt.PT_MIPS_OPTIONS.short_name != 'MIPS_OPTIONS':
|
||||
+ error('PT_MIPS_OPTIONS short name')
|
||||
|
||||
# Special cases for int-like Shn.
|
||||
if glibcelf.Shn(32) == glibcelf.Shn.SHN_XINDEX:
|
||||
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
|
||||
index 59aab56ecf9deb3e..5980d7cc906005e2 100644
|
||||
--- a/scripts/glibcelf.py
|
||||
+++ b/scripts/glibcelf.py
|
||||
@@ -306,23 +306,17 @@ class ShtALPHA(Sht):
|
||||
"""Supplemental SHT_* constants for EM_ALPHA."""
|
||||
class ShtARM(Sht):
|
||||
"""Supplemental SHT_* constants for EM_ARM."""
|
||||
-class ShtCSKY(Sht):
|
||||
- """Supplemental SHT_* constants for EM_CSKY."""
|
||||
class ShtIA_64(Sht):
|
||||
"""Supplemental SHT_* constants for EM_IA_64."""
|
||||
class ShtMIPS(Sht):
|
||||
"""Supplemental SHT_* constants for EM_MIPS."""
|
||||
class ShtPARISC(Sht):
|
||||
"""Supplemental SHT_* constants for EM_PARISC."""
|
||||
-class ShtRISCV(Sht):
|
||||
- """Supplemental SHT_* constants for EM_RISCV."""
|
||||
_register_elf_h(ShtALPHA, prefix='SHT_ALPHA_', parent=Sht)
|
||||
_register_elf_h(ShtARM, prefix='SHT_ARM_', parent=Sht)
|
||||
-_register_elf_h(ShtCSKY, prefix='SHT_CSKY_', parent=Sht)
|
||||
_register_elf_h(ShtIA_64, prefix='SHT_IA_64_', parent=Sht)
|
||||
_register_elf_h(ShtMIPS, prefix='SHT_MIPS_', parent=Sht)
|
||||
_register_elf_h(ShtPARISC, prefix='SHT_PARISC_', parent=Sht)
|
||||
-_register_elf_h(ShtRISCV, prefix='SHT_RISCV_', parent=Sht)
|
||||
_register_elf_h(Sht, ranges=True,
|
||||
skip='SHT_LOSUNW SHT_HISUNW SHT_LOUSER SHT_HIUSER'.split())
|
||||
|
||||
@@ -392,8 +386,6 @@ _register_elf_h(Stt, ranges=True)
|
||||
class Pt(_TypedConstant):
|
||||
"""ELF program header types. Type of Phdr.p_type."""
|
||||
prefix = 'PT_'
|
||||
-class PtAARCH64(Pt):
|
||||
- """Supplemental PT_* constants for EM_AARCH64."""
|
||||
class PtARM(Pt):
|
||||
"""Supplemental PT_* constants for EM_ARM."""
|
||||
class PtHP(Pt):
|
||||
@@ -404,15 +396,11 @@ class PtMIPS(Pt):
|
||||
"""Supplemental PT_* constants for EM_MIPS."""
|
||||
class PtPARISC(Pt):
|
||||
"""Supplemental PT_* constants for EM_PARISC."""
|
||||
-class PtRISCV(Pt):
|
||||
- """Supplemental PT_* constants for EM_RISCV."""
|
||||
-_register_elf_h(PtAARCH64, prefix='PT_AARCH64_', parent=Pt)
|
||||
_register_elf_h(PtARM, prefix='PT_ARM_', parent=Pt)
|
||||
_register_elf_h(PtHP, prefix='PT_HP_', parent=Pt)
|
||||
_register_elf_h(PtIA_64, prefix='PT_IA_64_', parent=Pt)
|
||||
_register_elf_h(PtMIPS, prefix='PT_MIPS_', parent=Pt)
|
||||
_register_elf_h(PtPARISC, prefix='PT_PARISC_', parent=Pt)
|
||||
-_register_elf_h(PtRISCV, prefix='PT_RISCV_', parent=Pt)
|
||||
_register_elf_h(Pt, skip='PT_LOSUNW PT_HISUNW'.split(), ranges=True)
|
||||
|
||||
class Dt(_TypedConstant):
|
||||
@@ -432,8 +420,6 @@ class DtPPC(Dt):
|
||||
"""Supplemental DT_* constants for EM_PPC."""
|
||||
class DtPPC64(Dt):
|
||||
"""Supplemental DT_* constants for EM_PPC64."""
|
||||
-class DtRISCV(Dt):
|
||||
- """Supplemental DT_* constants for EM_RISCV."""
|
||||
class DtSPARC(Dt):
|
||||
"""Supplemental DT_* constants for EM_SPARC."""
|
||||
_dt_skip = '''
|
||||
@@ -456,7 +442,6 @@ _register_elf_h(DtIA_64, prefix='DT_IA_64_', skip=_dt_skip, parent=Dt)
|
||||
_register_elf_h(DtMIPS, prefix='DT_MIPS_', skip=_dt_skip, parent=Dt)
|
||||
_register_elf_h(DtPPC, prefix='DT_PPC_', skip=_dt_skip, parent=Dt)
|
||||
_register_elf_h(DtPPC64, prefix='DT_PPC64_', skip=_dt_skip, parent=Dt)
|
||||
-_register_elf_h(DtRISCV, prefix='DT_RISCV_', skip=_dt_skip, parent=Dt)
|
||||
_register_elf_h(DtSPARC, prefix='DT_SPARC_', skip=_dt_skip, parent=Dt)
|
||||
_register_elf_h(Dt, skip=_dt_skip, ranges=True)
|
||||
del _dt_skip
|
32
SOURCES/glibc-rh2109510-3.patch
Normal file
32
SOURCES/glibc-rh2109510-3.patch
Normal file
@ -0,0 +1,32 @@
|
||||
commit 7b36d26b22d147ffc347f427f9fd584700578a94
|
||||
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
Date: Mon Dec 3 14:40:48 2018 +0100
|
||||
|
||||
Fix test-as-const-jmp_buf-ssp.c generation on gnu-i386
|
||||
|
||||
hurd's jmp_buf-ssp.sym does not define any symbol.
|
||||
scripts/gen-as-const.py currently was emitting an empty line in that
|
||||
case, and the gawk invocation was prepending "asconst_" to it, ending up
|
||||
with:
|
||||
|
||||
.../build/glibc/setjmp/test-as-const-jmp_buf-ssp.c:1:2: error: expected « = », « , », « ; », « asm » or
|
||||
« __attribute__ » at end of input
|
||||
1 | asconst_
|
||||
| ^~~~~~~~
|
||||
|
||||
* scripts/gen-as-const.py (main): Avoid emitting empty line when
|
||||
there is no element in `consts'.
|
||||
|
||||
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
|
||||
index b7a5744bb192dd67..cabf401ed15e8367 100644
|
||||
--- a/scripts/gen-as-const.py
|
||||
+++ b/scripts/gen-as-const.py
|
||||
@@ -153,7 +153,7 @@ def main():
|
||||
print(gen_test(sym_data))
|
||||
else:
|
||||
consts = compute_c_consts(sym_data, args.cc)
|
||||
- print('\n'.join('#define %s %s' % c for c in sorted(consts.items())))
|
||||
+ print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
157
SOURCES/glibc-rh2109510-4.patch
Normal file
157
SOURCES/glibc-rh2109510-4.patch
Normal file
@ -0,0 +1,157 @@
|
||||
commit 477a02f63751c4b759ddd9454d17f2a7ad120ee3
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Dec 3 22:08:50 2018 +0000
|
||||
|
||||
Make gen-as-const.py handle '--' consistently with awk script.
|
||||
|
||||
It was reported in
|
||||
<https://sourceware.org/ml/libc-alpha/2018-12/msg00045.html> that
|
||||
gen-as-const.py fails to generate test code in the case where a .sym
|
||||
file has no symbols in it, so resulting in a test failing to link for
|
||||
Hurd.
|
||||
|
||||
The relevant difference from the old awk script is that the old script
|
||||
treated '--' lines as indicating that the text to do at the start of
|
||||
the test (or file used to compute constants) should be output at that
|
||||
point if not already output, as well as treating lines with actual
|
||||
entries for constants like that. This patch changes gen-as-const.py
|
||||
accordingly, making it the sole responsibility of the code parsing
|
||||
.sym files to determine when such text should be output and ensuring
|
||||
it's always output at some point even if there are no symbols and no
|
||||
'--' lines, since not outputting it means the test fails to link.
|
||||
Handling '--' like that also avoids any problems that would arise if
|
||||
the first entry for a symbol were inside #ifdef (since the text in
|
||||
question must not be output inside #ifdef).
|
||||
|
||||
Tested for x86_64, and with build-many-glibcs.py for i686-gnu. Note
|
||||
that there are still compilation test failures for i686-gnu
|
||||
(linknamespace tests, possibly arising from recent posix_spawn-related
|
||||
changes).
|
||||
|
||||
* scripts/gen-as-const.py (compute_c_consts): Take an argument
|
||||
'START' to indicate that start text should be output.
|
||||
(gen_test): Likewise.
|
||||
(main): Generate 'START' for first symbol or '--' line, or at end
|
||||
of input if not previously generated.
|
||||
|
||||
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
|
||||
index cabf401ed15e8367..eb85ef1aa0f4934d 100644
|
||||
--- a/scripts/gen-as-const.py
|
||||
+++ b/scripts/gen-as-const.py
|
||||
@@ -34,28 +34,28 @@ def compute_c_consts(sym_data, cc):
|
||||
"""Compute the values of some C constants.
|
||||
|
||||
The first argument is a list whose elements are either strings
|
||||
- (preprocessor directives) or pairs of strings (a name and a C
|
||||
+ (preprocessor directives, or the special string 'START' to
|
||||
+ indicate this function should insert its initial boilerplate text
|
||||
+ in the output there) or pairs of strings (a name and a C
|
||||
expression for the corresponding value). Preprocessor directives
|
||||
in the middle of the list may be used to select which constants
|
||||
end up being evaluated using which expressions.
|
||||
|
||||
"""
|
||||
out_lines = []
|
||||
- started = False
|
||||
for arg in sym_data:
|
||||
if isinstance(arg, str):
|
||||
- out_lines.append(arg)
|
||||
+ if arg == 'START':
|
||||
+ out_lines.append('void\ndummy (void)\n{')
|
||||
+ else:
|
||||
+ out_lines.append(arg)
|
||||
continue
|
||||
name = arg[0]
|
||||
value = arg[1]
|
||||
- if not started:
|
||||
- out_lines.append('void\ndummy (void)\n{')
|
||||
- started = True
|
||||
out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
|
||||
': : \"i\" ((long int) (%s)));'
|
||||
% (name, value))
|
||||
- if started:
|
||||
- out_lines.append('}')
|
||||
+ out_lines.append('}')
|
||||
out_lines.append('')
|
||||
out_text = '\n'.join(out_lines)
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
@@ -89,32 +89,32 @@ def gen_test(sym_data):
|
||||
|
||||
"""
|
||||
out_lines = []
|
||||
- started = False
|
||||
for arg in sym_data:
|
||||
if isinstance(arg, str):
|
||||
- out_lines.append(arg)
|
||||
+ if arg == 'START':
|
||||
+ out_lines.append('#include <stdint.h>\n'
|
||||
+ '#include <stdio.h>\n'
|
||||
+ '#include <bits/wordsize.h>\n'
|
||||
+ '#if __WORDSIZE == 64\n'
|
||||
+ 'typedef uint64_t c_t;\n'
|
||||
+ '# define U(n) UINT64_C (n)\n'
|
||||
+ '#else\n'
|
||||
+ 'typedef uint32_t c_t;\n'
|
||||
+ '# define U(n) UINT32_C (n)\n'
|
||||
+ '#endif\n'
|
||||
+ 'static int\n'
|
||||
+ 'do_test (void)\n'
|
||||
+ '{\n'
|
||||
+ # Compilation test only, using static
|
||||
+ # assertions.
|
||||
+ ' return 0;\n'
|
||||
+ '}\n'
|
||||
+ '#include <support/test-driver.c>')
|
||||
+ else:
|
||||
+ out_lines.append(arg)
|
||||
continue
|
||||
name = arg[0]
|
||||
value = arg[1]
|
||||
- if not started:
|
||||
- out_lines.append('#include <stdint.h>\n'
|
||||
- '#include <stdio.h>\n'
|
||||
- '#include <bits/wordsize.h>\n'
|
||||
- '#if __WORDSIZE == 64\n'
|
||||
- 'typedef uint64_t c_t;\n'
|
||||
- '# define U(n) UINT64_C (n)\n'
|
||||
- '#else\n'
|
||||
- 'typedef uint32_t c_t;\n'
|
||||
- '# define U(n) UINT32_C (n)\n'
|
||||
- '#endif\n'
|
||||
- 'static int\n'
|
||||
- 'do_test (void)\n'
|
||||
- '{\n'
|
||||
- # Compilation test only, using static assertions.
|
||||
- ' return 0;\n'
|
||||
- '}\n'
|
||||
- '#include <support/test-driver.c>')
|
||||
- started = True
|
||||
out_lines.append('_Static_assert (U (asconst_%s) == (c_t) (%s), '
|
||||
'"value of %s");'
|
||||
% (name, value, name))
|
||||
@@ -134,6 +134,7 @@ def main():
|
||||
args = parser.parse_args()
|
||||
sym_data = []
|
||||
with open(args.sym_file, 'r') as sym_file:
|
||||
+ started = False
|
||||
for line in sym_file:
|
||||
line = line.strip()
|
||||
if line == '':
|
||||
@@ -143,12 +144,17 @@ def main():
|
||||
sym_data.append(line)
|
||||
continue
|
||||
words = line.split(maxsplit=1)
|
||||
+ if not started:
|
||||
+ sym_data.append('START')
|
||||
+ started = True
|
||||
# Separator.
|
||||
if words[0] == '--':
|
||||
continue
|
||||
name = words[0]
|
||||
value = words[1] if len(words) > 1 else words[0]
|
||||
sym_data.append((name, value))
|
||||
+ if not started:
|
||||
+ sym_data.append('START')
|
||||
if args.test:
|
||||
print(gen_test(sym_data))
|
||||
else:
|
483
SOURCES/glibc-rh2109510-5.patch
Normal file
483
SOURCES/glibc-rh2109510-5.patch
Normal file
@ -0,0 +1,483 @@
|
||||
commit a8110b727e508f7ddf34f940af622e6f95435201
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Dec 10 22:27:13 2018 +0000
|
||||
|
||||
Move tst-signal-numbers to Python.
|
||||
|
||||
This patch converts the tst-signal-numbers test from shell + awk to
|
||||
Python.
|
||||
|
||||
As with gen-as-const, the point is not so much that shell and awk are
|
||||
problematic for this code, as that it's useful to build up general
|
||||
infrastructure in Python for use of a range of code involving
|
||||
extracting values from C headers. This patch moves some code from
|
||||
gen-as-const.py to a new glibcextract.py, which also gains functions
|
||||
relating to listing macros, and comparing the values of a set of
|
||||
macros from compiling two different pieces of code.
|
||||
|
||||
It's not just signal numbers that should have such tests; pretty much
|
||||
any case where glibc copies constants from Linux kernel headers should
|
||||
have such tests that the values and sets of constants agree except
|
||||
where differences are known to be OK. Much the same also applies to
|
||||
structure layouts (although testing those without hardcoding lists of
|
||||
fields to test will be more complicated).
|
||||
|
||||
Given this patch, another test for a set of macros would essentially
|
||||
be just a call to glibcextract.compare_macro_consts (plus boilerplate
|
||||
code - and we could move to having separate text files defining such
|
||||
tests, like the .sym inputs to gen-as-const, so that only a single
|
||||
Python script is needed for most such tests). Some such tests would
|
||||
of course need new features, e.g. where the set of macros changes in
|
||||
new kernel versions (so you need to allow new macro names on the
|
||||
kernel side if the kernel headers are newer than the version known to
|
||||
glibc, and extra macros on the glibc side if the kernel headers are
|
||||
older). tst-syscall-list.sh could become a Python script that uses
|
||||
common code to generate lists of macros but does other things with its
|
||||
own custom logic.
|
||||
|
||||
There are a few differences from the existing shell + awk test.
|
||||
Because the new test evaluates constants using the compiler, no
|
||||
special handling is needed any more for one signal name being defined
|
||||
to another. Because asm/signal.h now needs to pass through the
|
||||
compiler, not just the preprocessor, stddef.h is included as well
|
||||
(given the asm/signal.h issue that it requires an externally provided
|
||||
definition of size_t). The previous code defined __ASSEMBLER__ with
|
||||
asm/signal.h; this is removed (__ASSEMBLY__, a different macro,
|
||||
eliminates the requirement for stddef.h on some but not all
|
||||
architectures).
|
||||
|
||||
Tested for x86_64, and with build-many-glibcs.py.
|
||||
|
||||
* scripts/glibcextract.py: New file.
|
||||
* scripts/gen-as-const.py: Do not import os.path, re, subprocess
|
||||
or tempfile. Import glibcexctract.
|
||||
(compute_c_consts): Remove. Moved to glibcextract.py.
|
||||
(gen_test): Update reference to compute_c_consts.
|
||||
(main): Likewise.
|
||||
* sysdeps/unix/sysv/linux/tst-signal-numbers.py: New file.
|
||||
* sysdeps/unix/sysv/linux/tst-signal-numbers.sh: Remove.
|
||||
* sysdeps/unix/sysv/linux/Makefile
|
||||
($(objpfx)tst-signal-numbers.out): Use tst-signal-numbers.py.
|
||||
Redirect stderr as well as stdout.
|
||||
|
||||
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
|
||||
index eb85ef1aa0f4934d..f85e359394acb1a4 100644
|
||||
--- a/scripts/gen-as-const.py
|
||||
+++ b/scripts/gen-as-const.py
|
||||
@@ -24,68 +24,14 @@
|
||||
# A line giving just a name implies an expression consisting of just that name.
|
||||
|
||||
import argparse
|
||||
-import os.path
|
||||
-import re
|
||||
-import subprocess
|
||||
-import tempfile
|
||||
|
||||
-
|
||||
-def compute_c_consts(sym_data, cc):
|
||||
- """Compute the values of some C constants.
|
||||
-
|
||||
- The first argument is a list whose elements are either strings
|
||||
- (preprocessor directives, or the special string 'START' to
|
||||
- indicate this function should insert its initial boilerplate text
|
||||
- in the output there) or pairs of strings (a name and a C
|
||||
- expression for the corresponding value). Preprocessor directives
|
||||
- in the middle of the list may be used to select which constants
|
||||
- end up being evaluated using which expressions.
|
||||
-
|
||||
- """
|
||||
- out_lines = []
|
||||
- for arg in sym_data:
|
||||
- if isinstance(arg, str):
|
||||
- if arg == 'START':
|
||||
- out_lines.append('void\ndummy (void)\n{')
|
||||
- else:
|
||||
- out_lines.append(arg)
|
||||
- continue
|
||||
- name = arg[0]
|
||||
- value = arg[1]
|
||||
- out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
|
||||
- ': : \"i\" ((long int) (%s)));'
|
||||
- % (name, value))
|
||||
- out_lines.append('}')
|
||||
- out_lines.append('')
|
||||
- out_text = '\n'.join(out_lines)
|
||||
- with tempfile.TemporaryDirectory() as temp_dir:
|
||||
- c_file_name = os.path.join(temp_dir, 'test.c')
|
||||
- s_file_name = os.path.join(temp_dir, 'test.s')
|
||||
- with open(c_file_name, 'w') as c_file:
|
||||
- c_file.write(out_text)
|
||||
- # Compilation has to be from stdin to avoid the temporary file
|
||||
- # name being written into the generated dependencies.
|
||||
- cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name))
|
||||
- subprocess.check_call(cmd, shell=True)
|
||||
- consts = {}
|
||||
- with open(s_file_name, 'r') as s_file:
|
||||
- for line in s_file:
|
||||
- match = re.search('@@@name@@@([^@]*)'
|
||||
- '@@@value@@@[^0-9Xxa-fA-F-]*'
|
||||
- '([0-9Xxa-fA-F-]+).*@@@end@@@', line)
|
||||
- if match:
|
||||
- if (match.group(1) in consts
|
||||
- and match.group(2) != consts[match.group(1)]):
|
||||
- raise ValueError('duplicate constant %s'
|
||||
- % match.group(1))
|
||||
- consts[match.group(1)] = match.group(2)
|
||||
- return consts
|
||||
+import glibcextract
|
||||
|
||||
|
||||
def gen_test(sym_data):
|
||||
"""Generate a test for the values of some C constants.
|
||||
|
||||
- The first argument is as for compute_c_consts.
|
||||
+ The first argument is as for glibcextract.compute_c_consts.
|
||||
|
||||
"""
|
||||
out_lines = []
|
||||
@@ -158,7 +104,7 @@ def main():
|
||||
if args.test:
|
||||
print(gen_test(sym_data))
|
||||
else:
|
||||
- consts = compute_c_consts(sym_data, args.cc)
|
||||
+ consts = glibcextract.compute_c_consts(sym_data, args.cc)
|
||||
print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='')
|
||||
|
||||
if __name__ == '__main__':
|
||||
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
|
||||
new file mode 100644
|
||||
index 0000000000000000..ecc4d5b6cc387c7d
|
||||
--- /dev/null
|
||||
+++ b/scripts/glibcextract.py
|
||||
@@ -0,0 +1,162 @@
|
||||
+#!/usr/bin/python3
|
||||
+# Extract information from C headers.
|
||||
+# Copyright (C) 2018 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
|
||||
+# <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+import os.path
|
||||
+import re
|
||||
+import subprocess
|
||||
+import tempfile
|
||||
+
|
||||
+
|
||||
+def compute_c_consts(sym_data, cc):
|
||||
+ """Compute the values of some C constants.
|
||||
+
|
||||
+ The first argument is a list whose elements are either strings
|
||||
+ (preprocessor directives, or the special string 'START' to
|
||||
+ indicate this function should insert its initial boilerplate text
|
||||
+ in the output there) or pairs of strings (a name and a C
|
||||
+ expression for the corresponding value). Preprocessor directives
|
||||
+ in the middle of the list may be used to select which constants
|
||||
+ end up being evaluated using which expressions.
|
||||
+
|
||||
+ """
|
||||
+ out_lines = []
|
||||
+ for arg in sym_data:
|
||||
+ if isinstance(arg, str):
|
||||
+ if arg == 'START':
|
||||
+ out_lines.append('void\ndummy (void)\n{')
|
||||
+ else:
|
||||
+ out_lines.append(arg)
|
||||
+ continue
|
||||
+ name = arg[0]
|
||||
+ value = arg[1]
|
||||
+ out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
|
||||
+ ': : \"i\" ((long int) (%s)));'
|
||||
+ % (name, value))
|
||||
+ out_lines.append('}')
|
||||
+ out_lines.append('')
|
||||
+ out_text = '\n'.join(out_lines)
|
||||
+ with tempfile.TemporaryDirectory() as temp_dir:
|
||||
+ c_file_name = os.path.join(temp_dir, 'test.c')
|
||||
+ s_file_name = os.path.join(temp_dir, 'test.s')
|
||||
+ with open(c_file_name, 'w') as c_file:
|
||||
+ c_file.write(out_text)
|
||||
+ # Compilation has to be from stdin to avoid the temporary file
|
||||
+ # name being written into the generated dependencies.
|
||||
+ cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name))
|
||||
+ subprocess.check_call(cmd, shell=True)
|
||||
+ consts = {}
|
||||
+ with open(s_file_name, 'r') as s_file:
|
||||
+ for line in s_file:
|
||||
+ match = re.search('@@@name@@@([^@]*)'
|
||||
+ '@@@value@@@[^0-9Xxa-fA-F-]*'
|
||||
+ '([0-9Xxa-fA-F-]+).*@@@end@@@', line)
|
||||
+ if match:
|
||||
+ if (match.group(1) in consts
|
||||
+ and match.group(2) != consts[match.group(1)]):
|
||||
+ raise ValueError('duplicate constant %s'
|
||||
+ % match.group(1))
|
||||
+ consts[match.group(1)] = match.group(2)
|
||||
+ return consts
|
||||
+
|
||||
+
|
||||
+def list_macros(source_text, cc):
|
||||
+ """List the preprocessor macros defined by the given source code.
|
||||
+
|
||||
+ The return value is a pair of dicts, the first one mapping macro
|
||||
+ names to their expansions and the second one mapping macro names
|
||||
+ to lists of their arguments, or to None for object-like macros.
|
||||
+
|
||||
+ """
|
||||
+ with tempfile.TemporaryDirectory() as temp_dir:
|
||||
+ c_file_name = os.path.join(temp_dir, 'test.c')
|
||||
+ i_file_name = os.path.join(temp_dir, 'test.i')
|
||||
+ with open(c_file_name, 'w') as c_file:
|
||||
+ c_file.write(source_text)
|
||||
+ cmd = ('%s -E -dM -o %s %s' % (cc, i_file_name, c_file_name))
|
||||
+ subprocess.check_call(cmd, shell=True)
|
||||
+ macros_exp = {}
|
||||
+ macros_args = {}
|
||||
+ with open(i_file_name, 'r') as i_file:
|
||||
+ for line in i_file:
|
||||
+ match = re.fullmatch('#define ([0-9A-Za-z_]+)(.*)\n', line)
|
||||
+ if not match:
|
||||
+ raise ValueError('bad -dM output line: %s' % line)
|
||||
+ name = match.group(1)
|
||||
+ value = match.group(2)
|
||||
+ if value.startswith(' '):
|
||||
+ value = value[1:]
|
||||
+ args = None
|
||||
+ elif value.startswith('('):
|
||||
+ match = re.fullmatch(r'\((.*?)\) (.*)', value)
|
||||
+ if not match:
|
||||
+ raise ValueError('bad -dM output line: %s' % line)
|
||||
+ args = match.group(1).split(',')
|
||||
+ value = match.group(2)
|
||||
+ else:
|
||||
+ raise ValueError('bad -dM output line: %s' % line)
|
||||
+ if name in macros_exp:
|
||||
+ raise ValueError('duplicate macro: %s' % line)
|
||||
+ macros_exp[name] = value
|
||||
+ macros_args[name] = args
|
||||
+ return macros_exp, macros_args
|
||||
+
|
||||
+
|
||||
+def compute_macro_consts(source_text, cc, macro_re, exclude_re=None):
|
||||
+ """Compute the integer constant values of macros defined by source_text.
|
||||
+
|
||||
+ Macros must match the regular expression macro_re, and if
|
||||
+ exclude_re is defined they must not match exclude_re. Values are
|
||||
+ computed with compute_c_consts.
|
||||
+
|
||||
+ """
|
||||
+ macros_exp, macros_args = list_macros(source_text, cc)
|
||||
+ macros_set = {m for m in macros_exp
|
||||
+ if (macros_args[m] is None
|
||||
+ and re.fullmatch(macro_re, m)
|
||||
+ and (exclude_re is None
|
||||
+ or not re.fullmatch(exclude_re, m)))}
|
||||
+ sym_data = [source_text, 'START']
|
||||
+ sym_data.extend(sorted((m, m) for m in macros_set))
|
||||
+ return compute_c_consts(sym_data, cc)
|
||||
+
|
||||
+
|
||||
+def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None):
|
||||
+ """Compare the values of macros defined by two different sources.
|
||||
+
|
||||
+ The sources would typically be includes of a glibc header and a
|
||||
+ kernel header. Return 1 if there were any differences, 0 if the
|
||||
+ macro values were the same.
|
||||
+
|
||||
+ """
|
||||
+ macros_1 = compute_macro_consts(source_1, cc, macro_re, exclude_re)
|
||||
+ macros_2 = compute_macro_consts(source_2, cc, macro_re, exclude_re)
|
||||
+ if macros_1 == macros_2:
|
||||
+ return 0
|
||||
+ print('First source:\n%s\n' % source_1)
|
||||
+ print('Second source:\n%s\n' % source_2)
|
||||
+ for name, value in sorted(macros_1.items()):
|
||||
+ if name not in macros_2:
|
||||
+ print('Only in first source: %s' % name)
|
||||
+ elif macros_1[name] != macros_2[name]:
|
||||
+ print('Different values for %s: %s != %s'
|
||||
+ % (name, macros_1[name], macros_2[name]))
|
||||
+ for name in sorted(macros_2.keys()):
|
||||
+ if name not in macros_1:
|
||||
+ print('Only in second source: %s' % name)
|
||||
+ return 1
|
||||
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
||||
index bb055f9d6b841ff5..9c10ee53b26e1b1b 100644
|
||||
--- a/sysdeps/unix/sysv/linux/Makefile
|
||||
+++ b/sysdeps/unix/sysv/linux/Makefile
|
||||
@@ -113,11 +113,14 @@ tests-special += $(objpfx)tst-signal-numbers.out
|
||||
# in this context, but signal.c includes signal.h and not much else so it'll
|
||||
# be conservatively correct.
|
||||
$(objpfx)tst-signal-numbers.out: \
|
||||
- ../sysdeps/unix/sysv/linux/tst-signal-numbers.sh \
|
||||
+ ../sysdeps/unix/sysv/linux/tst-signal-numbers.py \
|
||||
$(objpfx)signal.o*
|
||||
- AWK=$(AWK) $(SHELL) ../sysdeps/unix/sysv/linux/tst-signal-numbers.sh \
|
||||
- $(CC) $(patsubst -DMODULE_NAME=%,-DMODULE_NAME=testsuite,$(CPPFLAGS)) \
|
||||
- < /dev/null > $@; $(evaluate-test)
|
||||
+ PYTHONPATH=../scripts \
|
||||
+ $(PYTHON) ../sysdeps/unix/sysv/linux/tst-signal-numbers.py \
|
||||
+ --cc="$(CC) $(patsubst -DMODULE_NAME=%, \
|
||||
+ -DMODULE_NAME=testsuite, \
|
||||
+ $(CPPFLAGS))" \
|
||||
+ < /dev/null > $@ 2>&1; $(evaluate-test)
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),socket)
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-signal-numbers.py b/sysdeps/unix/sysv/linux/tst-signal-numbers.py
|
||||
new file mode 100644
|
||||
index 0000000000000000..48c63d1218e8303d
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-signal-numbers.py
|
||||
@@ -0,0 +1,48 @@
|
||||
+#!/usr/bin/python3
|
||||
+# Test that glibc's signal numbers match the kernel's.
|
||||
+# Copyright (C) 2018 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
|
||||
+# <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+import argparse
|
||||
+import sys
|
||||
+
|
||||
+import glibcextract
|
||||
+
|
||||
+
|
||||
+def main():
|
||||
+ """The main entry point."""
|
||||
+ parser = argparse.ArgumentParser(
|
||||
+ description="Test that glibc's signal numbers match the kernel's.")
|
||||
+ parser.add_argument('--cc', metavar='CC',
|
||||
+ help='C compiler (including options) to use')
|
||||
+ args = parser.parse_args()
|
||||
+ sys.exit(glibcextract.compare_macro_consts(
|
||||
+ '#define _GNU_SOURCE 1\n'
|
||||
+ '#include <signal.h>\n',
|
||||
+ '#define _GNU_SOURCE 1\n'
|
||||
+ '#include <stddef.h>\n'
|
||||
+ '#include <asm/signal.h>\n',
|
||||
+ args.cc,
|
||||
+ # Filter out constants that aren't signal numbers.
|
||||
+ 'SIG[A-Z]+',
|
||||
+ # Discard obsolete signal numbers and unrelated constants:
|
||||
+ # SIGCLD, SIGIOT, SIGSWI, SIGUNUSED.
|
||||
+ # SIGSTKSZ, SIGRTMIN, SIGRTMAX.
|
||||
+ 'SIG(CLD|IOT|RT(MIN|MAX)|STKSZ|SWI|UNUSED)'))
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ main()
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-signal-numbers.sh b/sysdeps/unix/sysv/linux/tst-signal-numbers.sh
|
||||
deleted file mode 100644
|
||||
index e1f7be0337c720a6..0000000000000000
|
||||
--- a/sysdeps/unix/sysv/linux/tst-signal-numbers.sh
|
||||
+++ /dev/null
|
||||
@@ -1,86 +0,0 @@
|
||||
-#! /bin/sh
|
||||
-# Test that glibc's signal numbers match the kernel's.
|
||||
-# Copyright (C) 2017-2018 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
|
||||
-# <http://www.gnu.org/licenses/>.
|
||||
-
|
||||
-set -e
|
||||
-if [ -n "$BASH_VERSION" ]; then set -o pipefail; fi
|
||||
-LC_ALL=C; export LC_ALL
|
||||
-
|
||||
-# We cannot use Linux's asm/signal.h to define signal numbers, because
|
||||
-# it isn't sufficiently namespace-clean. Instead, this test checks
|
||||
-# that our signal numbers match the kernel's. This script expects
|
||||
-# "$@" to be $(CC) $(CPPFLAGS) as set by glibc's Makefiles, and $AWK
|
||||
-# to be set in the environment.
|
||||
-
|
||||
-# Before doing anything else, fail if the compiler doesn't work.
|
||||
-"$@" -E -xc -dM - < /dev/null > /dev/null
|
||||
-
|
||||
-tmpG=`mktemp -t signums_glibc.XXXXXXXXX`
|
||||
-tmpK=`mktemp -t signums_kernel.XXXXXXXXX`
|
||||
-trap "rm -f '$tmpG' '$tmpK'" 0
|
||||
-
|
||||
-# Filter out constants that aren't signal numbers.
|
||||
-# If SIGPOLL is defined as SIGIO, swap it around so SIGIO is defined as
|
||||
-# SIGPOLL. Similarly for SIGABRT and SIGIOT.
|
||||
-# Discard obsolete signal numbers and unrelated constants:
|
||||
-# SIGCLD, SIGIOT, SIGSWI, SIGUNUSED.
|
||||
-# SIGSTKSZ, SIGRTMIN, SIGRTMAX.
|
||||
-# Then sort the list.
|
||||
-filter_defines ()
|
||||
-{
|
||||
- $AWK '
|
||||
-/^#define SIG[A-Z]+ ([0-9]+|SIG[A-Z0-9]+)$/ { signals[$2] = $3 }
|
||||
-END {
|
||||
- if ("SIGPOLL" in signals && "SIGIO" in signals &&
|
||||
- signals["SIGPOLL"] == "SIGIO") {
|
||||
- signals["SIGPOLL"] = signals["SIGIO"]
|
||||
- signals["SIGIO"] = "SIGPOLL"
|
||||
- }
|
||||
- if ("SIGABRT" in signals && "SIGIOT" in signals &&
|
||||
- signals["SIGABRT"] == "SIGIOT") {
|
||||
- signals["SIGABRT"] = signals["SIGIOT"]
|
||||
- signals["SIGIOT"] = "SIGABRT"
|
||||
- }
|
||||
- for (sig in signals) {
|
||||
- if (sig !~ /^SIG(CLD|IOT|RT(MIN|MAX)|STKSZ|SWI|UNUSED)$/) {
|
||||
- printf("#define %s %s\n", sig, signals[sig])
|
||||
- }
|
||||
- }
|
||||
-}' | sort
|
||||
-}
|
||||
-
|
||||
-# $CC may contain command-line switches, so it should be word-split.
|
||||
-printf '%s' '#define _GNU_SOURCE 1
|
||||
-#include <signal.h>
|
||||
-' |
|
||||
- "$@" -E -xc -dM - |
|
||||
- filter_defines > "$tmpG"
|
||||
-
|
||||
-printf '%s' '#define _GNU_SOURCE 1
|
||||
-#define __ASSEMBLER__ 1
|
||||
-#include <asm/signal.h>
|
||||
-' |
|
||||
- "$@" -E -xc -dM - |
|
||||
- filter_defines > "$tmpK"
|
||||
-
|
||||
-if cmp -s "$tmpG" "$tmpK"; then
|
||||
- exit 0
|
||||
-else
|
||||
- diff -u "$tmpG" "$tmpK"
|
||||
- exit 1
|
||||
-fi
|
98
SOURCES/glibc-rh2109510-6.patch
Normal file
98
SOURCES/glibc-rh2109510-6.patch
Normal file
@ -0,0 +1,98 @@
|
||||
Partial backport of:
|
||||
|
||||
commit cb7be1590e9b18e272e72eb4e910a7ad06a53bd0
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Dec 10 22:56:59 2018 +0000
|
||||
|
||||
Use gen-as-const.py to process .pysym files.
|
||||
|
||||
This patch eliminates the gen-py-const.awk variant of gen-as-const,
|
||||
switching to use of gnu-as-const.py (with a new --python option) to
|
||||
process .pysym files (i.e., to generate nptl_lock_constants.py), as
|
||||
the syntax of those files is identical to that of .sym files.
|
||||
|
||||
Note that the generated nptl_lock_constants.py is *not* identical to
|
||||
the version generated by the awk script. Apart from the trivial
|
||||
changes (comment referencing the new script, and output being sorted),
|
||||
the constant FUTEX_WAITERS, PTHREAD_MUTEXATTR_FLAG_BITS,
|
||||
PTHREAD_MUTEXATTR_FLAG_PSHARED and PTHREAD_MUTEX_PRIO_CEILING_MASK are
|
||||
now output as positive rather than negative constants (on x86_64
|
||||
anyway; maybe not necessarily on 32-bit systems):
|
||||
|
||||
< FUTEX_WAITERS = -2147483648
|
||||
---
|
||||
> FUTEX_WAITERS = 2147483648
|
||||
|
||||
< PTHREAD_MUTEXATTR_FLAG_BITS = -251662336
|
||||
< PTHREAD_MUTEXATTR_FLAG_PSHARED = -2147483648
|
||||
---
|
||||
> PTHREAD_MUTEXATTR_FLAG_BITS = 4043304960
|
||||
> PTHREAD_MUTEXATTR_FLAG_PSHARED = 2147483648
|
||||
|
||||
< PTHREAD_MUTEX_PRIO_CEILING_MASK = -524288
|
||||
---
|
||||
> PTHREAD_MUTEX_PRIO_CEILING_MASK = 4294443008
|
||||
|
||||
This is because gen-as-const has a cast of the constant value to long
|
||||
int, which gen-py-const lacks.
|
||||
|
||||
I think the positive values are more logically correct, since the
|
||||
constants in question are in fact unsigned in C. But to reliably
|
||||
produce gen-as-const.py output for constants that always (in C and
|
||||
Python) reflects the signedness of values with the high bit of "long
|
||||
int" set would mean more complicated logic needs to be used in
|
||||
computing values.
|
||||
|
||||
The more correct positive values by themselves produce a failure of
|
||||
nptl/test-mutexattr-printers, because masking with
|
||||
~PTHREAD_MUTEXATTR_FLAG_BITS & ~PTHREAD_MUTEX_NO_ELISION_NP now leaves
|
||||
a bit -1 << 32 in the Python value, resulting in a KeyError exception.
|
||||
To avoid that, places masking with ~ of one of the constants in
|
||||
question are changed to mask with 0xffffffff as well (this reflects
|
||||
how ~ in Python applies to an infinite-precision integer whereas ~ in
|
||||
C does not do any promotions beyond the width of int).
|
||||
|
||||
Tested for x86_64.
|
||||
|
||||
* scripts/gen-as-const.py (main): Handle --python option.
|
||||
* scripts/gen-py-const.awk: Remove.
|
||||
* Makerules (py-const-script): Use gen-as-const.py.
|
||||
($(py-const)): Likewise.
|
||||
* nptl/nptl-printers.py (MutexPrinter.read_status_no_robust): Mask
|
||||
with 0xffffffff together with ~(PTHREAD_MUTEX_PRIO_CEILING_MASK).
|
||||
(MutexAttributesPrinter.read_values): Mask with 0xffffffff
|
||||
together with ~PTHREAD_MUTEXATTR_FLAG_BITS and
|
||||
~PTHREAD_MUTEX_NO_ELISION_NP.
|
||||
* manual/README.pretty-printers: Update reference to
|
||||
gen-py-const.awk.
|
||||
|
||||
Only the gen-as-const.py changes are included downstream. We keep using
|
||||
gen-py-const.awk for the build.
|
||||
|
||||
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
|
||||
index f85e359394acb1a4..2f1dff092b98e044 100644
|
||||
--- a/scripts/gen-as-const.py
|
||||
+++ b/scripts/gen-as-const.py
|
||||
@@ -75,6 +75,8 @@ def main():
|
||||
help='C compiler (including options) to use')
|
||||
parser.add_argument('--test', action='store_true',
|
||||
help='Generate test case instead of header')
|
||||
+ parser.add_argument('--python', action='store_true',
|
||||
+ help='Generate Python file instead of header')
|
||||
parser.add_argument('sym_file',
|
||||
help='.sym file to process')
|
||||
args = parser.parse_args()
|
||||
@@ -103,6 +105,13 @@ def main():
|
||||
sym_data.append('START')
|
||||
if args.test:
|
||||
print(gen_test(sym_data))
|
||||
+ elif args.python:
|
||||
+ consts = glibcextract.compute_c_consts(sym_data, args.cc)
|
||||
+ print('# GENERATED FILE\n'
|
||||
+ '\n'
|
||||
+ '# Constant definitions.\n'
|
||||
+ '# See gen-as-const.py for details.\n')
|
||||
+ print(''.join('%s = %s\n' % c for c in sorted(consts.items())), end='')
|
||||
else:
|
||||
consts = glibcextract.compute_c_consts(sym_data, args.cc)
|
||||
print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='')
|
178
SOURCES/glibc-rh2109510-7.patch
Normal file
178
SOURCES/glibc-rh2109510-7.patch
Normal file
@ -0,0 +1,178 @@
|
||||
commit df648905e7d8340bb3e78813fd25e2077b9685d9
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Dec 17 18:29:36 2018 +0000
|
||||
|
||||
Add test that MAP_* constants agree with kernel.
|
||||
|
||||
Continuing the process of building up and using Python infrastructure
|
||||
for extracting and using values in headers, this patch adds a test
|
||||
that MAP_* constants from sys/mman.h agree with those in the Linux
|
||||
kernel headers. (Other sys/mman.h constants could be added to the
|
||||
test separately.)
|
||||
|
||||
This set of constants has grown over time, so the generic code is
|
||||
enhanced to allow saying extra constants are OK on either side of the
|
||||
comparison (where the caller sets those parameters based on the Linux
|
||||
kernel headers version, compared with the version the headers were
|
||||
last updated from). Although the test is a custom Python file, my
|
||||
intention is to move in future to a single Python script for such
|
||||
tests and text files it takes as inputs, once there are enough
|
||||
examples to provide a guide to the common cases in such tests (I'd
|
||||
like to end up with most or all such sets of constants copied from
|
||||
kernel headers having such tests, and likewise for structure layouts
|
||||
from the kernel).
|
||||
|
||||
The Makefile code is essentially the same as for tst-signal-numbers,
|
||||
but I didn't try to find an object file to depend on to represent the
|
||||
dependency on the headers used by the test (the conform/ tests don't
|
||||
try to represent such header dependencies at all, for example).
|
||||
|
||||
Tested with build-many-glibcs.py, and also for x86_64 with older
|
||||
kernel headers.
|
||||
|
||||
* scripts/glibcextract.py (compare_macro_consts): Take parameters
|
||||
to allow extra macros from first or second sources.
|
||||
* sysdeps/unix/sysv/linux/tst-mman-consts.py: New file.
|
||||
* sysdeps/unix/sysv/linux/Makefile [$(subdir) = misc]
|
||||
(tests-special): Add $(objpfx)tst-mman-consts.out.
|
||||
($(objpfx)tst-mman-consts.out): New makefile target.
|
||||
|
||||
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
|
||||
index ecc4d5b6cc387c7d..06f712ad115e0f9e 100644
|
||||
--- a/scripts/glibcextract.py
|
||||
+++ b/scripts/glibcextract.py
|
||||
@@ -136,12 +136,19 @@ def compute_macro_consts(source_text, cc, macro_re, exclude_re=None):
|
||||
return compute_c_consts(sym_data, cc)
|
||||
|
||||
|
||||
-def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None):
|
||||
+def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
|
||||
+ allow_extra_1=False, allow_extra_2=False):
|
||||
"""Compare the values of macros defined by two different sources.
|
||||
|
||||
The sources would typically be includes of a glibc header and a
|
||||
- kernel header. Return 1 if there were any differences, 0 if the
|
||||
- macro values were the same.
|
||||
+ kernel header. If allow_extra_1, the first source may define
|
||||
+ extra macros (typically if the kernel headers are older than the
|
||||
+ version glibc has taken definitions from); if allow_extra_2, the
|
||||
+ second source may define extra macros (typically if the kernel
|
||||
+ headers are newer than the version glibc has taken definitions
|
||||
+ from). Return 1 if there were any differences other than those
|
||||
+ allowed, 0 if the macro values were the same apart from any
|
||||
+ allowed differences.
|
||||
|
||||
"""
|
||||
macros_1 = compute_macro_consts(source_1, cc, macro_re, exclude_re)
|
||||
@@ -150,13 +157,19 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None):
|
||||
return 0
|
||||
print('First source:\n%s\n' % source_1)
|
||||
print('Second source:\n%s\n' % source_2)
|
||||
+ ret = 0
|
||||
for name, value in sorted(macros_1.items()):
|
||||
if name not in macros_2:
|
||||
print('Only in first source: %s' % name)
|
||||
+ if not allow_extra_1:
|
||||
+ ret = 1
|
||||
elif macros_1[name] != macros_2[name]:
|
||||
print('Different values for %s: %s != %s'
|
||||
% (name, macros_1[name], macros_2[name]))
|
||||
+ ret = 1
|
||||
for name in sorted(macros_2.keys()):
|
||||
if name not in macros_1:
|
||||
print('Only in second source: %s' % name)
|
||||
- return 1
|
||||
+ if not allow_extra_2:
|
||||
+ ret = 1
|
||||
+ return ret
|
||||
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
|
||||
index 9c10ee53b26e1b1b..863ed80c2a2713d3 100644
|
||||
--- a/sysdeps/unix/sysv/linux/Makefile
|
||||
+++ b/sysdeps/unix/sysv/linux/Makefile
|
||||
@@ -98,6 +98,15 @@ $(objpfx)tst-sysconf-iov_max: $(objpfx)tst-sysconf-iov_max-uapi.o
|
||||
|
||||
$(objpfx)tst-pkey: $(shared-thread-library)
|
||||
|
||||
+tests-special += $(objpfx)tst-mman-consts.out
|
||||
+$(objpfx)tst-mman-consts.out: ../sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
+ PYTHONPATH=../scripts \
|
||||
+ $(PYTHON) ../sysdeps/unix/sysv/linux/tst-mman-consts.py \
|
||||
+ --cc="$(CC) $(patsubst -DMODULE_NAME=%, \
|
||||
+ -DMODULE_NAME=testsuite, \
|
||||
+ $(CPPFLAGS))" \
|
||||
+ < /dev/null > $@ 2>&1; $(evaluate-test)
|
||||
+
|
||||
endif # $(subdir) == misc
|
||||
|
||||
ifeq ($(subdir),time)
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
new file mode 100644
|
||||
index 0000000000000000..1a613beec0da16fb
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
@@ -0,0 +1,65 @@
|
||||
+#!/usr/bin/python3
|
||||
+# Test that glibc's sys/mman.h constants match the kernel's.
|
||||
+# Copyright (C) 2018 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
|
||||
+# <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+import argparse
|
||||
+import sys
|
||||
+
|
||||
+import glibcextract
|
||||
+
|
||||
+
|
||||
+def linux_kernel_version(cc):
|
||||
+ """Return the (major, minor) version of the Linux kernel headers."""
|
||||
+ sym_data = ['#include <linux/version.h>', 'START',
|
||||
+ ('LINUX_VERSION_CODE', 'LINUX_VERSION_CODE')]
|
||||
+ val = glibcextract.compute_c_consts(sym_data, cc)['LINUX_VERSION_CODE']
|
||||
+ val = int(val)
|
||||
+ return ((val & 0xff0000) >> 16, (val & 0xff00) >> 8)
|
||||
+
|
||||
+
|
||||
+def main():
|
||||
+ """The main entry point."""
|
||||
+ parser = argparse.ArgumentParser(
|
||||
+ description="Test that glibc's sys/mman.h constants "
|
||||
+ "match the kernel's.")
|
||||
+ parser.add_argument('--cc', metavar='CC',
|
||||
+ help='C compiler (including options) to use')
|
||||
+ args = parser.parse_args()
|
||||
+ linux_version_headers = linux_kernel_version(args.cc)
|
||||
+ linux_version_glibc = (4, 19)
|
||||
+ sys.exit(glibcextract.compare_macro_consts(
|
||||
+ '#define _GNU_SOURCE 1\n'
|
||||
+ '#include <sys/mman.h>\n',
|
||||
+ '#define _GNU_SOURCE 1\n'
|
||||
+ '#include <linux/mman.h>\n',
|
||||
+ args.cc,
|
||||
+ 'MAP_.*',
|
||||
+ # A series of MAP_HUGE_<size> macros are defined by the kernel
|
||||
+ # but not by glibc. MAP_UNINITIALIZED is kernel-only.
|
||||
+ # MAP_FAILED is not a MAP_* flag and is glibc-only, as is the
|
||||
+ # MAP_ANON alias for MAP_ANONYMOUS. MAP_RENAME, MAP_AUTOGROW,
|
||||
+ # MAP_LOCAL and MAP_AUTORSRV are in the kernel header for
|
||||
+ # MIPS, marked as "not used by linux"; SPARC has MAP_INHERIT
|
||||
+ # in the kernel header, but does not use it.
|
||||
+ 'MAP_HUGE_[0-9].*|MAP_UNINITIALIZED|MAP_FAILED|MAP_ANON'
|
||||
+ '|MAP_RENAME|MAP_AUTOGROW|MAP_LOCAL|MAP_AUTORSRV|MAP_INHERIT',
|
||||
+ linux_version_glibc > linux_version_headers,
|
||||
+ linux_version_headers > linux_version_glibc))
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ main()
|
23
SOURCES/glibc-rh2109510-8.patch
Normal file
23
SOURCES/glibc-rh2109510-8.patch
Normal file
@ -0,0 +1,23 @@
|
||||
commit 46baeb61e16511f26db1b255e19dc9163f590367
|
||||
Author: Fangrui Song <maskray@google.com>
|
||||
Date: Tue Oct 19 09:58:16 2021 -0700
|
||||
|
||||
glibcextract.py: Place un-assemblable @@@ in a comment
|
||||
|
||||
Unlike GCC, Clang parses asm statements and verifies they are valid
|
||||
instructions/directives. Place the magic @@@ into a comment to avoid
|
||||
a parse error.
|
||||
|
||||
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
|
||||
index 06f712ad115e0f9e..8f2246aae6a9dfb7 100644
|
||||
--- a/scripts/glibcextract.py
|
||||
+++ b/scripts/glibcextract.py
|
||||
@@ -45,7 +45,7 @@ def compute_c_consts(sym_data, cc):
|
||||
continue
|
||||
name = arg[0]
|
||||
value = arg[1]
|
||||
- out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
|
||||
+ out_lines.append('asm ("/* @@@name@@@%s@@@value@@@%%0@@@end@@@ */" '
|
||||
': : \"i\" ((long int) (%s)));'
|
||||
% (name, value))
|
||||
out_lines.append('}')
|
45
SOURCES/glibc-rh2109510-9.patch
Normal file
45
SOURCES/glibc-rh2109510-9.patch
Normal file
@ -0,0 +1,45 @@
|
||||
commit 841afa116e32b3c7195475769c26bf46fd870d32
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Wed Aug 10 16:24:06 2022 -0300
|
||||
|
||||
glibcextract.py: Add compile_c_snippet
|
||||
|
||||
It might be used on tests to check if a snippet build with the provided
|
||||
compiler and flags.
|
||||
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
|
||||
index 8f2246aae6a9dfb7..0fb50dc8f9c4f7f9 100644
|
||||
--- a/scripts/glibcextract.py
|
||||
+++ b/scripts/glibcextract.py
|
||||
@@ -17,6 +17,7 @@
|
||||
# License along with the GNU C Library; if not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
+import collections
|
||||
import os.path
|
||||
import re
|
||||
import subprocess
|
||||
@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
|
||||
if not allow_extra_2:
|
||||
ret = 1
|
||||
return ret
|
||||
+
|
||||
+CompileResult = collections.namedtuple("CompileResult", "returncode output")
|
||||
+
|
||||
+def compile_c_snippet(snippet, cc, extra_cc_args=''):
|
||||
+ """Compile and return whether the SNIPPET can be build with CC along
|
||||
+ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE
|
||||
+ being 0 for success, or the failure value and the compiler output.
|
||||
+ """
|
||||
+ with tempfile.TemporaryDirectory() as temp_dir:
|
||||
+ c_file_name = os.path.join(temp_dir, 'test.c')
|
||||
+ obj_file_name = os.path.join(temp_dir, 'test.o')
|
||||
+ with open(c_file_name, 'w') as c_file:
|
||||
+ c_file.write(snippet + '\n')
|
||||
+ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name,
|
||||
+ c_file_name]
|
||||
+ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE,
|
||||
+ stderr=subprocess.STDOUT)
|
||||
+ return CompileResult(r.returncode, r.stdout)
|
449
SOURCES/glibc-rh2116938.patch
Normal file
449
SOURCES/glibc-rh2116938.patch
Normal file
@ -0,0 +1,449 @@
|
||||
1. Added "$(objpfx)tst-cmsghdr: $(libdl)" to socket/Makefile since we still
|
||||
need $(libdl) in RHEL8.
|
||||
|
||||
2. Included stddef.h in socket/tst-cmsghdr-skeleton.c because it uses NULL.
|
||||
|
||||
commit 9c443ac4559a47ed99859bd80d14dc4b6dd220a1
|
||||
Author: Arjun Shankar <arjun@redhat.com>
|
||||
Date: Tue Aug 2 11:10:25 2022 +0200
|
||||
|
||||
socket: Check lengths before advancing pointer in CMSG_NXTHDR
|
||||
|
||||
The inline and library functions that the CMSG_NXTHDR macro may expand
|
||||
to increment the pointer to the header before checking the stride of
|
||||
the increment against available space. Since C only allows incrementing
|
||||
pointers to one past the end of an array, the increment must be done
|
||||
after a length check. This commit fixes that and includes a regression
|
||||
test for CMSG_FIRSTHDR and CMSG_NXTHDR.
|
||||
|
||||
The Linux, Hurd, and generic headers are all changed.
|
||||
|
||||
Tested on Linux on armv7hl, i686, x86_64, aarch64, ppc64le, and s390x.
|
||||
|
||||
[BZ #28846]
|
||||
|
||||
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||
|
||||
Conflicts:
|
||||
socket/Makefile
|
||||
(usual test backport differences)
|
||||
|
||||
diff --git a/bits/socket.h b/bits/socket.h
|
||||
index 725798882e4b803b..0474613a9c003eeb 100644
|
||||
--- a/bits/socket.h
|
||||
+++ b/bits/socket.h
|
||||
@@ -245,6 +245,12 @@ struct cmsghdr
|
||||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||||
|
||||
+/* Given a length, return the additional padding necessary such that
|
||||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||||
+ & (sizeof (size_t) - 1))
|
||||
+
|
||||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
struct cmsghdr *__cmsg) __THROW;
|
||||
#ifdef __USE_EXTERN_INLINES
|
||||
@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
_EXTERN_INLINE struct cmsghdr *
|
||||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||||
{
|
||||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||||
+ pointer arithmetic until we check its value. */
|
||||
+
|
||||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||||
+
|
||||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||||
+
|
||||
+ /* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
- /* The kernel header does this so there may be a reason. */
|
||||
return (struct cmsghdr *) 0;
|
||||
|
||||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||||
+ hold the current cmsg *and* the next one. */
|
||||
+ if (((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||||
+ < __size_needed)
|
||||
+ || ((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||||
+ - __size_needed)
|
||||
+ < __cmsg->cmsg_len))
|
||||
+
|
||||
+ return (struct cmsghdr *) 0;
|
||||
+
|
||||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||||
- + __mhdr->msg_controllen)
|
||||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||||
- /* No more entries. */
|
||||
- return (struct cmsghdr *) 0;
|
||||
return __cmsg;
|
||||
}
|
||||
#endif /* Use `extern inline'. */
|
||||
diff --git a/socket/Makefile b/socket/Makefile
|
||||
index 8975a65c2aabbfbc..a445383f8739351e 100644
|
||||
--- a/socket/Makefile
|
||||
+++ b/socket/Makefile
|
||||
@@ -31,7 +31,12 @@ routines := accept bind connect getpeername getsockname getsockopt \
|
||||
setsockopt shutdown socket socketpair isfdtype opensock \
|
||||
sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set
|
||||
|
||||
-tests := tst-accept4
|
||||
+tests := \
|
||||
+ tst-accept4 \
|
||||
+ tst-cmsghdr \
|
||||
+ # tests
|
||||
+
|
||||
+$(objpfx)tst-cmsghdr: $(libdl)
|
||||
|
||||
tests-internal := \
|
||||
tst-sockaddr_un_set \
|
||||
diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..7accfa6e54708e2a
|
||||
--- /dev/null
|
||||
+++ b/socket/tst-cmsghdr-skeleton.c
|
||||
@@ -0,0 +1,93 @@
|
||||
+/* Test ancillary data header creation.
|
||||
+ Copyright (C) 2022 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/>. */
|
||||
+
|
||||
+/* We use the preprocessor to generate the function/macro tests instead of
|
||||
+ using indirection because having all the macro expansions alongside
|
||||
+ each other lets the compiler warn us about suspicious pointer
|
||||
+ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+#include <stddef.h>
|
||||
+
|
||||
+#define RUN_TEST_CONCAT(suffix) run_test_##suffix
|
||||
+#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix)
|
||||
+
|
||||
+static void
|
||||
+RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void)
|
||||
+{
|
||||
+ struct msghdr m = {0};
|
||||
+ struct cmsghdr *cmsg;
|
||||
+ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0};
|
||||
+
|
||||
+ m.msg_control = cmsgbuf;
|
||||
+ m.msg_controllen = sizeof (cmsgbuf);
|
||||
+
|
||||
+ /* First header should point to the start of the buffer. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+
|
||||
+ /* If the first header length consumes the entire buffer, there is no
|
||||
+ space remaining for additional headers. */
|
||||
+ cmsg->cmsg_len = sizeof (cmsgbuf);
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||||
+
|
||||
+ /* The first header length is so big, using it would cause an overflow. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg->cmsg_len = SIZE_MAX;
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||||
+
|
||||
+ /* The first header leaves just enough space to hold another header. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr);
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||||
+
|
||||
+ /* The first header leaves space but not enough for another header. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg->cmsg_len ++;
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||||
+
|
||||
+ /* The second header leaves just enough space to hold another header. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD));
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||||
+ cmsg->cmsg_len = sizeof (cmsgbuf)
|
||||
+ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */
|
||||
+ - sizeof (struct cmsghdr);
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||||
+
|
||||
+ /* The second header leaves space but not enough for another header. */
|
||||
+ cmsg = CMSG_FIRSTHDR (&m);
|
||||
+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf);
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg != NULL);
|
||||
+ cmsg->cmsg_len ++;
|
||||
+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg);
|
||||
+ TEST_VERIFY_EXIT (cmsg == NULL);
|
||||
+
|
||||
+ return;
|
||||
+}
|
||||
diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..68c96d3c9dd2bce8
|
||||
--- /dev/null
|
||||
+++ b/socket/tst-cmsghdr.c
|
||||
@@ -0,0 +1,56 @@
|
||||
+/* Test ancillary data header creation.
|
||||
+ Copyright (C) 2022 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/>. */
|
||||
+
|
||||
+#include <sys/socket.h>
|
||||
+#include <gnu/lib-names.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+#define PAYLOAD "Hello, World!"
|
||||
+
|
||||
+/* CMSG_NXTHDR is a macro that calls an inline function defined in
|
||||
+ bits/socket.h. In case the function cannot be inlined, libc.so carries
|
||||
+ a copy. Both versions need to be tested. */
|
||||
+
|
||||
+#define CMSG_NXTHDR_IMPL CMSG_NXTHDR
|
||||
+#include "tst-cmsghdr-skeleton.c"
|
||||
+#undef CMSG_NXTHDR_IMPL
|
||||
+
|
||||
+static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *);
|
||||
+
|
||||
+#define CMSG_NXTHDR_IMPL cmsg_nxthdr
|
||||
+#include "tst-cmsghdr-skeleton.c"
|
||||
+#undef CMSG_NXTHDR_IMPL
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ static void *handle;
|
||||
+
|
||||
+ run_test_CMSG_NXTHDR ();
|
||||
+
|
||||
+ handle = xdlopen (LIBC_SO, RTLD_LAZY);
|
||||
+ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *))
|
||||
+ xdlsym (handle, "__cmsg_nxthdr");
|
||||
+
|
||||
+ run_test_cmsg_nxthdr ();
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h
|
||||
index 18959139dc7d325b..cc66684061e3e179 100644
|
||||
--- a/sysdeps/mach/hurd/bits/socket.h
|
||||
+++ b/sysdeps/mach/hurd/bits/socket.h
|
||||
@@ -249,6 +249,12 @@ struct cmsghdr
|
||||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||||
|
||||
+/* Given a length, return the additional padding necessary such that
|
||||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||||
+ & (sizeof (size_t) - 1))
|
||||
+
|
||||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
struct cmsghdr *__cmsg) __THROW;
|
||||
#ifdef __USE_EXTERN_INLINES
|
||||
@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
_EXTERN_INLINE struct cmsghdr *
|
||||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||||
{
|
||||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||||
+ pointer arithmetic until we check its value. */
|
||||
+
|
||||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||||
+
|
||||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||||
+
|
||||
+ /* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
- /* The kernel header does this so there may be a reason. */
|
||||
return (struct cmsghdr *) 0;
|
||||
|
||||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||||
+ hold the current cmsg *and* the next one. */
|
||||
+ if (((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||||
+ < __size_needed)
|
||||
+ || ((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||||
+ - __size_needed)
|
||||
+ < __cmsg->cmsg_len))
|
||||
+
|
||||
+ return (struct cmsghdr *) 0;
|
||||
+
|
||||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||||
- + __mhdr->msg_controllen)
|
||||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||||
- /* No more entries. */
|
||||
- return (struct cmsghdr *) 0;
|
||||
return __cmsg;
|
||||
}
|
||||
#endif /* Use `extern inline'. */
|
||||
diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
|
||||
index c3fbb2110296273c..6b895b89831d2cb5 100644
|
||||
--- a/sysdeps/unix/sysv/linux/bits/socket.h
|
||||
+++ b/sysdeps/unix/sysv/linux/bits/socket.h
|
||||
@@ -302,6 +302,12 @@ struct cmsghdr
|
||||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||||
|
||||
+/* Given a length, return the additional padding necessary such that
|
||||
+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||||
+#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||||
+ - ((len) & (sizeof (size_t) - 1))) \
|
||||
+ & (sizeof (size_t) - 1))
|
||||
+
|
||||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
struct cmsghdr *__cmsg) __THROW;
|
||||
#ifdef __USE_EXTERN_INLINES
|
||||
@@ -311,18 +317,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
_EXTERN_INLINE struct cmsghdr *
|
||||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||||
{
|
||||
+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||||
+ __mhdr->msg_controllen because the user is required to obtain the first
|
||||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
+ trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||||
+ pointer arithmetic until we check its value. */
|
||||
+
|
||||
+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||||
+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||||
+
|
||||
+ size_t __size_needed = sizeof (struct cmsghdr)
|
||||
+ + __CMSG_PADDING (__cmsg->cmsg_len);
|
||||
+
|
||||
+ /* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
- /* The kernel header does this so there may be a reason. */
|
||||
return (struct cmsghdr *) 0;
|
||||
|
||||
+ /* There isn't enough space between __cmsg and the end of the buffer to
|
||||
+ hold the current cmsg *and* the next one. */
|
||||
+ if (((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||||
+ < __size_needed)
|
||||
+ || ((size_t)
|
||||
+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||||
+ - __size_needed)
|
||||
+ < __cmsg->cmsg_len))
|
||||
+
|
||||
+ return (struct cmsghdr *) 0;
|
||||
+
|
||||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||||
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||||
- + __mhdr->msg_controllen)
|
||||
- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||||
- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||||
- /* No more entries. */
|
||||
- return (struct cmsghdr *) 0;
|
||||
return __cmsg;
|
||||
}
|
||||
#endif /* Use `extern inline'. */
|
||||
diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||||
index bab0be6884d9da1c..16594622211c1c8b 100644
|
||||
--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||||
+++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c
|
||||
@@ -23,18 +23,38 @@
|
||||
struct cmsghdr *
|
||||
__cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg)
|
||||
{
|
||||
+ /* We may safely assume that cmsg lies between mhdr->msg_control and
|
||||
+ mhdr->msg_controllen because the user is required to obtain the first
|
||||
+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
+ trust the value of cmsg->cmsg_len and therefore do not use it in any
|
||||
+ pointer arithmetic until we check its value. */
|
||||
+
|
||||
+ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control;
|
||||
+ unsigned char * cmsg_ptr = (unsigned char *) cmsg;
|
||||
+
|
||||
+ size_t size_needed = sizeof (struct cmsghdr)
|
||||
+ + __CMSG_PADDING (cmsg->cmsg_len);
|
||||
+
|
||||
+ /* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
- /* The kernel header does this so there may be a reason. */
|
||||
- return NULL;
|
||||
+ return (struct cmsghdr *) 0;
|
||||
+
|
||||
+ /* There isn't enough space between cmsg and the end of the buffer to
|
||||
+ hold the current cmsg *and* the next one. */
|
||||
+ if (((size_t)
|
||||
+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr)
|
||||
+ < size_needed)
|
||||
+ || ((size_t)
|
||||
+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr
|
||||
+ - size_needed)
|
||||
+ < cmsg->cmsg_len))
|
||||
+
|
||||
+ return (struct cmsghdr *) 0;
|
||||
|
||||
+ /* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
|
||||
+ CMSG_ALIGN (cmsg->cmsg_len));
|
||||
- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control
|
||||
- + mhdr->msg_controllen)
|
||||
- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len)
|
||||
- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen)))
|
||||
- /* No more entries. */
|
||||
- return NULL;
|
||||
return cmsg;
|
||||
}
|
||||
libc_hidden_def (__cmsg_nxthdr)
|
96
SOURCES/glibc-rh2118667.patch
Normal file
96
SOURCES/glibc-rh2118667.patch
Normal file
@ -0,0 +1,96 @@
|
||||
commit dd2315a866a4ac2b838ea1cb10c5ea1c35d51a2f
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Aug 16 08:27:50 2022 +0200
|
||||
|
||||
elf: Run tst-audit-tlsdesc, tst-audit-tlsdesc-dlopen everywhere
|
||||
|
||||
The test is valid for all TLS models, but we want to make a reasonable
|
||||
effort to test the GNU2 model specifically. For example, aarch64
|
||||
defaults to GNU2, but does not have -mtls-dialect=gnu2, and the test
|
||||
was not run there.
|
||||
|
||||
Suggested-by: Martin Coufal <mcoufal@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile
|
||||
(missing tst-align3 backport, missing libdl integration)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 9e721d5d4e0a1cd9..1dd36ba0486e56a0 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -331,6 +331,8 @@ tests += \
|
||||
tst-addr1 \
|
||||
tst-align \
|
||||
tst-align2 \
|
||||
+ tst-audit-tlsdesc \
|
||||
+ tst-audit-tlsdesc-dlopen \
|
||||
tst-audit1 \
|
||||
tst-audit11 \
|
||||
tst-audit12 \
|
||||
@@ -607,6 +609,8 @@ modules-names = \
|
||||
tst-alignmod2 \
|
||||
tst-array2dep \
|
||||
tst-array5dep \
|
||||
+ tst-audit-tlsdesc-mod1 \
|
||||
+ tst-audit-tlsdesc-mod2 \
|
||||
tst-audit11mod1 \
|
||||
tst-audit11mod2 \
|
||||
tst-audit12mod1 \
|
||||
@@ -640,6 +644,7 @@ modules-names = \
|
||||
tst-auditmanymod7 \
|
||||
tst-auditmanymod8 \
|
||||
tst-auditmanymod9 \
|
||||
+ tst-auditmod-tlsdesc \
|
||||
tst-auditmod1 \
|
||||
tst-auditmod9a \
|
||||
tst-auditmod9b \
|
||||
@@ -809,23 +814,8 @@ modules-names += tst-gnu2-tls1mod
|
||||
$(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
|
||||
tst-gnu2-tls1mod.so-no-z-defs = yes
|
||||
CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
|
||||
+endif # $(have-mtls-dialect-gnu2)
|
||||
|
||||
-tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen
|
||||
-modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc
|
||||
-$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
- $(objpfx)tst-audit-tlsdesc-mod2.so \
|
||||
- $(shared-thread-library)
|
||||
-CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
|
||||
-CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
|
||||
-$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) $(libdl)
|
||||
-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
- $(objpfx)tst-audit-tlsdesc-mod2.so
|
||||
-$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
|
||||
-$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
-tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
-$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
-tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
-endif
|
||||
ifeq (yes,$(have-protected-data))
|
||||
modules-names += tst-protected1moda tst-protected1modb
|
||||
tests += tst-protected1a tst-protected1b
|
||||
@@ -2559,5 +2549,23 @@ $(objpfx)tst-tls21.out: $(objpfx)tst-tls21mod.so
|
||||
$(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so)
|
||||
|
||||
$(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig
|
||||
+
|
||||
$(objpfx)tst-dlmopen-gethostbyname: $(libdl)
|
||||
$(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so
|
||||
+$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
+ $(objpfx)tst-audit-tlsdesc-mod2.so \
|
||||
+ $(shared-thread-library)
|
||||
+ifeq (yes,$(have-mtls-dialect-gnu2))
|
||||
+# The test is valid for all TLS types, but we want to exercise GNU2
|
||||
+# TLS if possible.
|
||||
+CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
|
||||
+CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
|
||||
+endif
|
||||
+$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) $(libdl)
|
||||
+$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
+ $(objpfx)tst-audit-tlsdesc-mod2.so
|
||||
+$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
|
||||
+$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
+tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
+$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
+tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
202
SOURCES/glibc-rh2121746-1.patch
Normal file
202
SOURCES/glibc-rh2121746-1.patch
Normal file
@ -0,0 +1,202 @@
|
||||
From d0e357ff45a75553dee3b17ed7d303bfa544f6fe Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri, 26 Aug 2022 21:15:43 +0200
|
||||
Subject: elf: Call __libc_early_init for reused namespaces (bug 29528)
|
||||
|
||||
libc_map is never reset to NULL, neither during dlclose nor on a
|
||||
dlopen call which reuses the namespace structure. As a result, if a
|
||||
namespace is reused, its libc is not initialized properly. The most
|
||||
visible result is a crash in the <ctype.h> functions.
|
||||
|
||||
To prevent similar bugs on namespace reuse from surfacing,
|
||||
unconditionally initialize the chosen namespace to zero using memset.
|
||||
|
||||
[Note from DJ: Regenerated for new line numbers and context, added
|
||||
link dependency on libdl]]
|
||||
|
||||
diff -rupN a/elf/Makefile b/elf/Makefile
|
||||
--- a/elf/Makefile 2022-10-05 15:04:11.814901849 -0400
|
||||
+++ b/elf/Makefile 2022-10-05 17:02:19.858635958 -0400
|
||||
@@ -367,6 +367,7 @@ tests += \
|
||||
tst-dlmopen3 \
|
||||
tst-dlmopen-dlerror \
|
||||
tst-dlmopen-gethostbyname \
|
||||
+ tst-dlmopen-twice \
|
||||
tst-dlopenfail \
|
||||
tst-dlopenfail-2 \
|
||||
tst-dlopenrpath \
|
||||
@@ -671,6 +672,8 @@ modules-names = \
|
||||
tst-dlmopen1mod \
|
||||
tst-dlmopen-dlerror-mod \
|
||||
tst-dlmopen-gethostbyname-mod \
|
||||
+ tst-dlmopen-twice-mod1 \
|
||||
+ tst-dlmopen-twice-mod2 \
|
||||
tst-dlopenfaillinkmod \
|
||||
tst-dlopenfailmod1 \
|
||||
tst-dlopenfailmod2 \
|
||||
@@ -2569,3 +2572,9 @@ $(objpfx)tst-audit-tlsdesc.out: $(objpfx
|
||||
tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
+
|
||||
+
|
||||
+$(objpfx)tst-dlmopen-twice: $(libdl)
|
||||
+$(objpfx)tst-dlmopen-twice.out: \
|
||||
+ $(objpfx)tst-dlmopen-twice-mod1.so \
|
||||
+ $(objpfx)tst-dlmopen-twice-mod2.so
|
||||
diff -rupN a/elf/dl-open.c b/elf/dl-open.c
|
||||
--- a/elf/dl-open.c 2022-10-05 15:04:11.635894932 -0400
|
||||
+++ b/elf/dl-open.c 2022-10-05 15:10:31.667638060 -0400
|
||||
@@ -836,11 +836,14 @@ _dl_open (const char *file, int mode, co
|
||||
_dl_signal_error (EINVAL, file, NULL, N_("\
|
||||
no more namespaces available for dlmopen()"));
|
||||
}
|
||||
- else if (nsid == GL(dl_nns))
|
||||
- {
|
||||
- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
|
||||
- ++GL(dl_nns);
|
||||
- }
|
||||
+
|
||||
+ if (nsid == GL(dl_nns))
|
||||
+ ++GL(dl_nns);
|
||||
+
|
||||
+ /* Initialize the new namespace. Most members are
|
||||
+ zero-initialized, only the lock needs special treatment. */
|
||||
+ memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid]));
|
||||
+ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
|
||||
|
||||
_dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
|
||||
}
|
||||
diff -rupN a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c
|
||||
--- a/elf/tst-dlmopen-twice-mod1.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/elf/tst-dlmopen-twice-mod1.c 2022-10-05 15:10:31.671638216 -0400
|
||||
@@ -0,0 +1,37 @@
|
||||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1.
|
||||
+ Copyright (C) 2022 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/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlmopen-twice-mod1.so loaded");
|
||||
+ fflush (stdout);
|
||||
+}
|
||||
+
|
||||
+static void __attribute__ ((destructor))
|
||||
+fini (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded");
|
||||
+ fflush (stdout);
|
||||
+}
|
||||
+
|
||||
+/* Large allocation. The second module does not have this, so it
|
||||
+ should load libc at a different address. */
|
||||
+char large_allocate[16 * 1024 * 1024];
|
||||
diff -rupN a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c
|
||||
--- a/elf/tst-dlmopen-twice-mod2.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/elf/tst-dlmopen-twice-mod2.c 2022-10-05 15:10:31.676638411 -0400
|
||||
@@ -0,0 +1,50 @@
|
||||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2.
|
||||
+ Copyright (C) 2022 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/>. */
|
||||
+
|
||||
+#include <ctype.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlmopen-twice-mod2.so loaded");
|
||||
+ fflush (stdout);
|
||||
+}
|
||||
+
|
||||
+static void __attribute__ ((destructor))
|
||||
+fini (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded");
|
||||
+ fflush (stdout);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+run_check (void)
|
||||
+{
|
||||
+ puts ("info: about to call isalpha");
|
||||
+ fflush (stdout);
|
||||
+
|
||||
+ volatile char ch = 'a';
|
||||
+ if (!isalpha (ch))
|
||||
+ {
|
||||
+ puts ("error: isalpha ('a') is not true");
|
||||
+ fflush (stdout);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
diff -rupN a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
|
||||
--- a/elf/tst-dlmopen-twice.c 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ b/elf/tst-dlmopen-twice.c 2022-10-05 15:10:31.679638528 -0400
|
||||
@@ -0,0 +1,34 @@
|
||||
+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main.
|
||||
+ Copyright (C) 2022 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/>. */
|
||||
+
|
||||
+#include <support/xdlfcn.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW);
|
||||
+ xdlclose (handle);
|
||||
+ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
|
||||
+ int (*run_check) (void) = xdlsym (handle, "run_check");
|
||||
+ TEST_COMPARE (run_check (), 0);
|
||||
+ xdlclose (handle);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
98
SOURCES/glibc-rh2121746-2.patch
Normal file
98
SOURCES/glibc-rh2121746-2.patch
Normal file
@ -0,0 +1,98 @@
|
||||
From 2c42257314536b94cc8d52edede86e94e98c1436 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri, 14 Oct 2022 11:02:25 +0200
|
||||
Subject: [PATCH] elf: Do not completely clear reused namespace in dlmopen (bug
|
||||
29600)
|
||||
Content-type: text/plain; charset=UTF-8
|
||||
|
||||
The data in the _ns_debug member must be preserved, otherwise
|
||||
_dl_debug_initialize enters an infinite loop. To be conservative,
|
||||
only clear the libc_map member for now, to fix bug 29528.
|
||||
|
||||
Fixes commit d0e357ff45a75553dee3b17ed7d303bfa544f6fe
|
||||
("elf: Call __libc_early_init for reused namespaces (bug 29528)"),
|
||||
by reverting most of it.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Tested-by: Carlos O'Donell <carlos@redhat.com>
|
||||
---
|
||||
elf/dl-open.c | 14 ++++++--------
|
||||
elf/tst-dlmopen-twice.c | 28 ++++++++++++++++++++++++----
|
||||
2 files changed, 30 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 46e8066fd8..e7db5e9642 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -836,15 +836,13 @@ _dl_open (const char *file, int mode, co
|
||||
_dl_signal_error (EINVAL, file, NULL, N_("\
|
||||
no more namespaces available for dlmopen()"));
|
||||
}
|
||||
+ else if (nsid == GL(dl_nns))
|
||||
+ {
|
||||
+ __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
|
||||
+ ++GL(dl_nns);
|
||||
+ }
|
||||
|
||||
- if (nsid == GL(dl_nns))
|
||||
- ++GL(dl_nns);
|
||||
-
|
||||
- /* Initialize the new namespace. Most members are
|
||||
- zero-initialized, only the lock needs special treatment. */
|
||||
- memset (&GL(dl_ns)[nsid], 0, sizeof (GL(dl_ns)[nsid]));
|
||||
- __rtld_lock_initialize (GL(dl_ns)[nsid]._ns_unique_sym_table.lock);
|
||||
-
|
||||
+ GL(dl_ns)[nsid].libc_map = NULL;
|
||||
_dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
|
||||
}
|
||||
/* Never allow loading a DSO in a namespace which is empty. Such
|
||||
diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c
|
||||
index 449f3c8fa9..70c71fe19c 100644
|
||||
--- a/elf/tst-dlmopen-twice.c
|
||||
+++ b/elf/tst-dlmopen-twice.c
|
||||
@@ -16,18 +16,38 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
-#include <support/xdlfcn.h>
|
||||
+#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
|
||||
-static int
|
||||
-do_test (void)
|
||||
+/* Run the test multiple times, to check finding a new namespace while
|
||||
+ another namespace is already in use. This used to trigger bug 29600. */
|
||||
+static void
|
||||
+recurse (int depth)
|
||||
{
|
||||
- void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", RTLD_NOW);
|
||||
+ if (depth == 0)
|
||||
+ return;
|
||||
+
|
||||
+ printf ("info: running at depth %d\n", depth);
|
||||
+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so",
|
||||
+ RTLD_NOW);
|
||||
xdlclose (handle);
|
||||
handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
|
||||
int (*run_check) (void) = xdlsym (handle, "run_check");
|
||||
TEST_COMPARE (run_check (), 0);
|
||||
+ recurse (depth - 1);
|
||||
xdlclose (handle);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* First run the test without nesting. */
|
||||
+ recurse (1);
|
||||
+
|
||||
+ /* Then with nesting. The constant needs to be less than the
|
||||
+ internal DL_NNS namespace constant. */
|
||||
+ recurse (10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
39
SOURCES/glibc-rh2122498.patch
Normal file
39
SOURCES/glibc-rh2122498.patch
Normal file
@ -0,0 +1,39 @@
|
||||
commit 02ca25fef2785974011e9c5beecc99b900b69fd7
|
||||
Author: Fabian Vogt <fvogt@suse.de>
|
||||
Date: Wed Jul 27 11:44:07 2022 +0200
|
||||
|
||||
nscd: Fix netlink cache invalidation if epoll is used [BZ #29415]
|
||||
|
||||
Processes cache network interface information such as whether IPv4 or IPv6
|
||||
are enabled. This is only checked again if the "netlink timestamp" provided
|
||||
by nscd changed, which is triggered by netlink socket activity.
|
||||
|
||||
However, in the epoll handler for the netlink socket, it was missed to
|
||||
assign the new timestamp to the nscd database. The handler for plain poll
|
||||
did that properly, copy that over.
|
||||
|
||||
This bug caused that e.g. processes which started before network
|
||||
configuration got unusuable addresses from getaddrinfo, like IPv6 only even
|
||||
though only IPv4 is available:
|
||||
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1041
|
||||
|
||||
It's a bit hard to reproduce, so I verified this by checking the timestamp
|
||||
on calls to __check_pf manually. Without this patch it's stuck at 1, now
|
||||
it's increasing on network changes as expected.
|
||||
|
||||
Signed-off-by: Fabian Vogt <fvogt@suse.de>
|
||||
|
||||
diff --git a/nscd/connections.c b/nscd/connections.c
|
||||
index 98182007646a33d5..19039bdbb210466a 100644
|
||||
--- a/nscd/connections.c
|
||||
+++ b/nscd/connections.c
|
||||
@@ -2286,7 +2286,8 @@ main_loop_epoll (int efd)
|
||||
sizeof (buf))) != -1)
|
||||
;
|
||||
|
||||
- __bump_nl_timestamp ();
|
||||
+ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
|
||||
+ = __bump_nl_timestamp ();
|
||||
}
|
||||
# endif
|
||||
else
|
472
SOURCES/glibc-rh2122501-1.patch
Normal file
472
SOURCES/glibc-rh2122501-1.patch
Normal file
@ -0,0 +1,472 @@
|
||||
commit c6fad4fa149485a307207f707e5851216f190fc8
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Mar 19 18:32:28 2020 -0300
|
||||
|
||||
stdio: Remove memory leak from multibyte convertion [BZ#25691]
|
||||
|
||||
This is an updated version of a previous patch [1] with the
|
||||
following changes:
|
||||
|
||||
- Use compiler overflow builtins on done_add_func function.
|
||||
- Define the scratch +utstring_converted_wide_string using
|
||||
CHAR_T.
|
||||
- Added a testcase and mention the bug report.
|
||||
|
||||
Both default and wide printf functions might leak memory when
|
||||
manipulate multibyte characters conversion depending of the size
|
||||
of the input (whether __libc_use_alloca trigger or not the fallback
|
||||
heap allocation).
|
||||
|
||||
This patch fixes it by removing the extra memory allocation on
|
||||
string formatting with conversion parts.
|
||||
|
||||
The testcase uses input argument size that trigger memory leaks
|
||||
on unpatched code (using a scratch buffer the threashold to use
|
||||
heap allocation is lower).
|
||||
|
||||
Checked on x86_64-linux-gnu and i686-linux-gnu.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
[1] https://sourceware.org/pipermail/libc-alpha/2017-June/082098.html
|
||||
|
||||
(cherry picked from commit 3cc4a8367c23582b7db14cf4e150e4068b7fd461)
|
||||
|
||||
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
|
||||
index ae412e4b8444aea2..dab56b6ba2c7bdbe 100644
|
||||
--- a/stdio-common/vfprintf.c
|
||||
+++ b/stdio-common/vfprintf.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <locale/localeinfo.h>
|
||||
#include <stdio.h>
|
||||
#include <scratch_buffer.h>
|
||||
+#include <intprops.h>
|
||||
|
||||
/* This code is shared between the standard stdio implementation found
|
||||
in GNU C library and the libio implementation originally found in
|
||||
@@ -64,23 +65,40 @@
|
||||
} while (0)
|
||||
#define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
|
||||
|
||||
-#define done_add(val) \
|
||||
- do { \
|
||||
- unsigned int _val = val; \
|
||||
- assert ((unsigned int) done < (unsigned int) INT_MAX); \
|
||||
- if (__glibc_unlikely (INT_MAX - done < _val)) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- __set_errno (EOVERFLOW); \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- done += _val; \
|
||||
- } while (0)
|
||||
+/* Add LENGTH to DONE. Return the new value of DONE, or -1 on
|
||||
+ overflow (and set errno accordingly). */
|
||||
+static inline int
|
||||
+done_add_func (size_t length, int done)
|
||||
+{
|
||||
+ if (done < 0)
|
||||
+ return done;
|
||||
+ int ret;
|
||||
+ if (INT_ADD_WRAPV (done, length, &ret))
|
||||
+ {
|
||||
+ __set_errno (EOVERFLOW);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+#define done_add(val) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ /* Ensure that VAL has a type similar to int. */ \
|
||||
+ _Static_assert (sizeof (val) == sizeof (int), "value int size"); \
|
||||
+ _Static_assert ((__typeof__ (val)) -1 < 0, "value signed"); \
|
||||
+ done = done_add_func ((val), done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ } \
|
||||
+ while (0)
|
||||
|
||||
#ifndef COMPILE_WPRINTF
|
||||
# define vfprintf _IO_vfprintf_internal
|
||||
# define CHAR_T char
|
||||
+# define CHAR_T char
|
||||
# define UCHAR_T unsigned char
|
||||
+# define OTHER_CHAR_T wchar_t
|
||||
# define INT_T int
|
||||
typedef const char *THOUSANDS_SEP_T;
|
||||
# define L_(Str) Str
|
||||
@@ -88,22 +106,10 @@ typedef const char *THOUSANDS_SEP_T;
|
||||
# define STR_LEN(Str) strlen (Str)
|
||||
|
||||
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
|
||||
-# define PAD(Padchar) \
|
||||
- do { \
|
||||
- if (width > 0) \
|
||||
- { \
|
||||
- ssize_t written = _IO_padn (s, (Padchar), width); \
|
||||
- if (__glibc_unlikely (written != width)) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- done_add (written); \
|
||||
- } \
|
||||
- } while (0)
|
||||
# define PUTC(C, F) _IO_putc_unlocked (C, F)
|
||||
# define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
|
||||
return -1
|
||||
+# define CONVERT_FROM_OTHER_STRING __wcsrtombs
|
||||
#else
|
||||
# define vfprintf _IO_vfwprintf
|
||||
# define CHAR_T wchar_t
|
||||
@@ -118,21 +124,11 @@ typedef wchar_t THOUSANDS_SEP_T;
|
||||
# include <_itowa.h>
|
||||
|
||||
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
|
||||
-# define PAD(Padchar) \
|
||||
- do { \
|
||||
- if (width > 0) \
|
||||
- { \
|
||||
- ssize_t written = _IO_wpadn (s, (Padchar), width); \
|
||||
- if (__glibc_unlikely (written != width)) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- done_add (written); \
|
||||
- } \
|
||||
- } while (0)
|
||||
# define PUTC(C, F) _IO_putwc_unlocked (C, F)
|
||||
# define ORIENT if (_IO_fwide (s, 1) != 1) return -1
|
||||
+# define CONVERT_FROM_OTHER_STRING __mbsrtowcs
|
||||
+# define CHAR_T wchar_t
|
||||
+# define OTHER_CHAR_T char
|
||||
|
||||
# undef _itoa
|
||||
# define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
|
||||
@@ -141,6 +137,33 @@ typedef wchar_t THOUSANDS_SEP_T;
|
||||
# define EOF WEOF
|
||||
#endif
|
||||
|
||||
+static inline int
|
||||
+pad_func (FILE *s, CHAR_T padchar, int width, int done)
|
||||
+{
|
||||
+ if (width > 0)
|
||||
+ {
|
||||
+ ssize_t written;
|
||||
+#ifndef COMPILE_WPRINTF
|
||||
+ written = _IO_padn (s, padchar, width);
|
||||
+#else
|
||||
+ written = _IO_wpadn (s, padchar, width);
|
||||
+#endif
|
||||
+ if (__glibc_unlikely (written != width))
|
||||
+ return -1;
|
||||
+ return done_add_func (width, done);
|
||||
+ }
|
||||
+ return done;
|
||||
+}
|
||||
+
|
||||
+#define PAD(Padchar) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ done = pad_func (s, (Padchar), width, done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ } \
|
||||
+ while (0)
|
||||
+
|
||||
#include "_i18n_number.h"
|
||||
|
||||
/* Include the shared code for parsing the format string. */
|
||||
@@ -160,24 +183,115 @@ typedef wchar_t THOUSANDS_SEP_T;
|
||||
} \
|
||||
while (0)
|
||||
|
||||
-#define outstring(String, Len) \
|
||||
- do \
|
||||
- { \
|
||||
- assert ((size_t) done <= (size_t) INT_MAX); \
|
||||
- if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- if (__glibc_unlikely (INT_MAX - done < (Len))) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- __set_errno (EOVERFLOW); \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- done += (Len); \
|
||||
- } \
|
||||
- while (0)
|
||||
+static inline int
|
||||
+outstring_func (FILE *s, const UCHAR_T *string, size_t length, int done)
|
||||
+{
|
||||
+ assert ((size_t) done <= (size_t) INT_MAX);
|
||||
+ if ((size_t) PUT (s, string, length) != (size_t) (length))
|
||||
+ return -1;
|
||||
+ return done_add_func (length, done);
|
||||
+}
|
||||
+
|
||||
+#define outstring(String, Len) \
|
||||
+ do \
|
||||
+ { \
|
||||
+ const void *string_ = (String); \
|
||||
+ done = outstring_func (s, string_, (Len), done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ } \
|
||||
+ while (0)
|
||||
+
|
||||
+/* Write the string SRC to S. If PREC is non-negative, write at most
|
||||
+ PREC bytes. If LEFT is true, perform left justification. */
|
||||
+static int
|
||||
+outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
|
||||
+ int width, bool left, int done)
|
||||
+{
|
||||
+ /* Use a small buffer to combine processing of multiple characters.
|
||||
+ CONVERT_FROM_OTHER_STRING expects the buffer size in (wide)
|
||||
+ characters, and buf_length counts that. */
|
||||
+ enum { buf_length = 256 / sizeof (CHAR_T) };
|
||||
+ CHAR_T buf[buf_length];
|
||||
+ _Static_assert (sizeof (buf) > MB_LEN_MAX,
|
||||
+ "buffer is large enough for a single multi-byte character");
|
||||
+
|
||||
+ /* Add the initial padding if needed. */
|
||||
+ if (width > 0 && !left)
|
||||
+ {
|
||||
+ /* Make a first pass to find the output width, so that we can
|
||||
+ add the required padding. */
|
||||
+ mbstate_t mbstate = { 0 };
|
||||
+ const OTHER_CHAR_T *src_copy = src;
|
||||
+ size_t total_written;
|
||||
+ if (prec < 0)
|
||||
+ total_written = CONVERT_FROM_OTHER_STRING
|
||||
+ (NULL, &src_copy, 0, &mbstate);
|
||||
+ else
|
||||
+ {
|
||||
+ /* The source might not be null-terminated. Enforce the
|
||||
+ limit manually, based on the output length. */
|
||||
+ total_written = 0;
|
||||
+ size_t limit = prec;
|
||||
+ while (limit > 0 && src_copy != NULL)
|
||||
+ {
|
||||
+ size_t write_limit = buf_length;
|
||||
+ if (write_limit > limit)
|
||||
+ write_limit = limit;
|
||||
+ size_t written = CONVERT_FROM_OTHER_STRING
|
||||
+ (buf, &src_copy, write_limit, &mbstate);
|
||||
+ if (written == (size_t) -1)
|
||||
+ return -1;
|
||||
+ if (written == 0)
|
||||
+ break;
|
||||
+ total_written += written;
|
||||
+ limit -= written;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Output initial padding. */
|
||||
+ if (total_written < width)
|
||||
+ {
|
||||
+ done = pad_func (s, L_(' '), width - total_written, done);
|
||||
+ if (done < 0)
|
||||
+ return done;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Convert the input string, piece by piece. */
|
||||
+ size_t total_written = 0;
|
||||
+ {
|
||||
+ mbstate_t mbstate = { 0 };
|
||||
+ /* If prec is negative, remaining is not decremented, otherwise,
|
||||
+ it serves as the write limit. */
|
||||
+ size_t remaining = -1;
|
||||
+ if (prec >= 0)
|
||||
+ remaining = prec;
|
||||
+ while (remaining > 0 && src != NULL)
|
||||
+ {
|
||||
+ size_t write_limit = buf_length;
|
||||
+ if (remaining < write_limit)
|
||||
+ write_limit = remaining;
|
||||
+ size_t written = CONVERT_FROM_OTHER_STRING
|
||||
+ (buf, &src, write_limit, &mbstate);
|
||||
+ if (written == (size_t) -1)
|
||||
+ return -1;
|
||||
+ if (written == 0)
|
||||
+ break;
|
||||
+ done = outstring_func (s, (const UCHAR_T *) buf, written, done);
|
||||
+ if (done < 0)
|
||||
+ return done;
|
||||
+ total_written += written;
|
||||
+ if (prec >= 0)
|
||||
+ remaining -= written;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Add final padding. */
|
||||
+ if (width > 0 && left && total_written < width)
|
||||
+ return pad_func (s, L_(' '), width - total_written, done);
|
||||
+ return done;
|
||||
+}
|
||||
|
||||
/* For handling long_double and longlong we use the same flag. If
|
||||
`long' and `long long' are effectively the same type define it to
|
||||
@@ -975,7 +1089,6 @@ static const uint8_t jump_table[] =
|
||||
LABEL (form_string): \
|
||||
{ \
|
||||
size_t len; \
|
||||
- int string_malloced; \
|
||||
\
|
||||
/* The string argument could in fact be `char *' or `wchar_t *'. \
|
||||
But this should not make a difference here. */ \
|
||||
@@ -987,7 +1100,6 @@ static const uint8_t jump_table[] =
|
||||
/* Entry point for printing other strings. */ \
|
||||
LABEL (print_string): \
|
||||
\
|
||||
- string_malloced = 0; \
|
||||
if (string == NULL) \
|
||||
{ \
|
||||
/* Write "(null)" if there's space. */ \
|
||||
@@ -1004,41 +1116,12 @@ static const uint8_t jump_table[] =
|
||||
} \
|
||||
else if (!is_long && spec != L_('S')) \
|
||||
{ \
|
||||
- /* This is complicated. We have to transform the multibyte \
|
||||
- string into a wide character string. */ \
|
||||
- const char *mbs = (const char *) string; \
|
||||
- mbstate_t mbstate; \
|
||||
- \
|
||||
- len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
|
||||
- \
|
||||
- /* Allocate dynamically an array which definitely is long \
|
||||
- enough for the wide character version. Each byte in the \
|
||||
- multi-byte string can produce at most one wide character. */ \
|
||||
- if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t))) \
|
||||
- { \
|
||||
- __set_errno (EOVERFLOW); \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- else if (__libc_use_alloca (len * sizeof (wchar_t))) \
|
||||
- string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \
|
||||
- else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \
|
||||
- == NULL) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- else \
|
||||
- string_malloced = 1; \
|
||||
- \
|
||||
- memset (&mbstate, '\0', sizeof (mbstate_t)); \
|
||||
- len = __mbsrtowcs (string, &mbs, len, &mbstate); \
|
||||
- if (len == (size_t) -1) \
|
||||
- { \
|
||||
- /* Illegal multibyte character. */ \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
+ done = outstring_converted_wide_string \
|
||||
+ (s, (const char *) string, prec, width, left, done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ /* The padding has already been written. */ \
|
||||
+ break; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
@@ -1061,8 +1144,6 @@ static const uint8_t jump_table[] =
|
||||
outstring (string, len); \
|
||||
if (left) \
|
||||
PAD (L' '); \
|
||||
- if (__glibc_unlikely (string_malloced)) \
|
||||
- free (string); \
|
||||
} \
|
||||
break;
|
||||
#else
|
||||
@@ -1111,7 +1192,6 @@ static const uint8_t jump_table[] =
|
||||
LABEL (form_string): \
|
||||
{ \
|
||||
size_t len; \
|
||||
- int string_malloced; \
|
||||
\
|
||||
/* The string argument could in fact be `char *' or `wchar_t *'. \
|
||||
But this should not make a difference here. */ \
|
||||
@@ -1123,7 +1203,6 @@ static const uint8_t jump_table[] =
|
||||
/* Entry point for printing other strings. */ \
|
||||
LABEL (print_string): \
|
||||
\
|
||||
- string_malloced = 0; \
|
||||
if (string == NULL) \
|
||||
{ \
|
||||
/* Write "(null)" if there's space. */ \
|
||||
@@ -1149,51 +1228,12 @@ static const uint8_t jump_table[] =
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
- const wchar_t *s2 = (const wchar_t *) string; \
|
||||
- mbstate_t mbstate; \
|
||||
- \
|
||||
- memset (&mbstate, '\0', sizeof (mbstate_t)); \
|
||||
- \
|
||||
- if (prec >= 0) \
|
||||
- { \
|
||||
- /* The string `s2' might not be NUL terminated. */ \
|
||||
- if (__libc_use_alloca (prec)) \
|
||||
- string = (char *) alloca (prec); \
|
||||
- else if ((string = (char *) malloc (prec)) == NULL) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- else \
|
||||
- string_malloced = 1; \
|
||||
- len = __wcsrtombs (string, &s2, prec, &mbstate); \
|
||||
- } \
|
||||
- else \
|
||||
- { \
|
||||
- len = __wcsrtombs (NULL, &s2, 0, &mbstate); \
|
||||
- if (len != (size_t) -1) \
|
||||
- { \
|
||||
- assert (__mbsinit (&mbstate)); \
|
||||
- s2 = (const wchar_t *) string; \
|
||||
- if (__libc_use_alloca (len + 1)) \
|
||||
- string = (char *) alloca (len + 1); \
|
||||
- else if ((string = (char *) malloc (len + 1)) == NULL) \
|
||||
- { \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
- else \
|
||||
- string_malloced = 1; \
|
||||
- (void) __wcsrtombs (string, &s2, len + 1, &mbstate); \
|
||||
- } \
|
||||
- } \
|
||||
- \
|
||||
- if (len == (size_t) -1) \
|
||||
- { \
|
||||
- /* Illegal wide-character string. */ \
|
||||
- done = -1; \
|
||||
- goto all_done; \
|
||||
- } \
|
||||
+ done = outstring_converted_wide_string \
|
||||
+ (s, (const wchar_t *) string, prec, width, left, done); \
|
||||
+ if (done < 0) \
|
||||
+ goto all_done; \
|
||||
+ /* The padding has already been written. */ \
|
||||
+ break; \
|
||||
} \
|
||||
\
|
||||
if ((width -= len) < 0) \
|
||||
@@ -1207,8 +1247,6 @@ static const uint8_t jump_table[] =
|
||||
outstring (string, len); \
|
||||
if (left) \
|
||||
PAD (' '); \
|
||||
- if (__glibc_unlikely (string_malloced)) \
|
||||
- free (string); \
|
||||
} \
|
||||
break;
|
||||
#endif
|
160
SOURCES/glibc-rh2122501-2.patch
Normal file
160
SOURCES/glibc-rh2122501-2.patch
Normal file
@ -0,0 +1,160 @@
|
||||
commit 29b12753b51866b227a6c0ac96c2c6c0e20f3497
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Thu Mar 19 18:35:46 2020 -0300
|
||||
|
||||
stdio: Add tests for printf multibyte convertion leak [BZ#25691]
|
||||
|
||||
Checked on x86_64-linux-gnu and i686-linux-gnu.
|
||||
|
||||
(cherry picked from commit 910a835dc96c1f518ac2a6179fc622ba81ffb159)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index a10f12ab3ccbd76e..51062a7dbf698931 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -63,6 +63,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
||||
tst-vfprintf-mbs-prec \
|
||||
tst-scanf-round \
|
||||
tst-renameat2 \
|
||||
+ tst-printf-bz25691 \
|
||||
|
||||
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
|
||||
|
||||
@@ -71,10 +72,12 @@ tests-special += $(objpfx)tst-unbputc.out $(objpfx)tst-printf.out \
|
||||
$(objpfx)tst-printf-bz18872-mem.out \
|
||||
$(objpfx)tst-setvbuf1-cmp.out \
|
||||
$(objpfx)tst-vfprintf-width-prec-mem.out \
|
||||
- $(objpfx)tst-printfsz-islongdouble.out
|
||||
+ $(objpfx)tst-printfsz-islongdouble.out \
|
||||
+ $(objpfx)tst-printf-bz25691-mem.out
|
||||
generated += tst-printf-bz18872.c tst-printf-bz18872.mtrace \
|
||||
tst-printf-bz18872-mem.out \
|
||||
- tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out
|
||||
+ tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out \
|
||||
+ tst-printf-bz25691.mtrace tst-printf-bz25691-mem.out
|
||||
endif
|
||||
|
||||
include ../Rules
|
||||
@@ -96,6 +99,8 @@ endif
|
||||
tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace
|
||||
tst-vfprintf-width-prec-ENV = \
|
||||
MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace
|
||||
+tst-printf-bz25691-ENV = \
|
||||
+ MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace
|
||||
|
||||
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
|
||||
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' > $@; \
|
||||
diff --git a/stdio-common/tst-printf-bz25691.c b/stdio-common/tst-printf-bz25691.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..37b30a3a8a7dc5e2
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-printf-bz25691.c
|
||||
@@ -0,0 +1,108 @@
|
||||
+/* Test for memory leak with large width (BZ#25691).
|
||||
+ Copyright (C) 2020 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/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <wchar.h>
|
||||
+#include <stdint.h>
|
||||
+#include <locale.h>
|
||||
+
|
||||
+#include <mcheck.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ mtrace ();
|
||||
+
|
||||
+ /* For 's' conversion specifier with 'l' modifier the array must be
|
||||
+ converted to multibyte characters up to the precision specific
|
||||
+ value. */
|
||||
+ {
|
||||
+ /* The input size value is to force a heap allocation on temporary
|
||||
+ buffer (in the old implementation). */
|
||||
+ const size_t winputsize = 64 * 1024 + 1;
|
||||
+ wchar_t *winput = xmalloc (winputsize * sizeof (wchar_t));
|
||||
+ wmemset (winput, L'a', winputsize - 1);
|
||||
+ winput[winputsize - 1] = L'\0';
|
||||
+
|
||||
+ char result[9];
|
||||
+ const char expected[] = "aaaaaaaa";
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = snprintf (result, sizeof (result), "%.65537ls", winput);
|
||||
+ TEST_COMPARE (ret, winputsize - 1);
|
||||
+ TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected));
|
||||
+
|
||||
+ ret = snprintf (result, sizeof (result), "%ls", winput);
|
||||
+ TEST_COMPARE (ret, winputsize - 1);
|
||||
+ TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected));
|
||||
+
|
||||
+ free (winput);
|
||||
+ }
|
||||
+
|
||||
+ /* For 's' converstion specifier the array is interpreted as a multibyte
|
||||
+ character sequence and converted to wide characters up to the precision
|
||||
+ specific value. */
|
||||
+ {
|
||||
+ /* The input size value is to force a heap allocation on temporary
|
||||
+ buffer (in the old implementation). */
|
||||
+ const size_t mbssize = 32 * 1024;
|
||||
+ char *mbs = xmalloc (mbssize);
|
||||
+ memset (mbs, 'a', mbssize - 1);
|
||||
+ mbs[mbssize - 1] = '\0';
|
||||
+
|
||||
+ const size_t expectedsize = 32 * 1024;
|
||||
+ wchar_t *expected = xmalloc (expectedsize * sizeof (wchar_t));
|
||||
+ wmemset (expected, L'a', expectedsize - 1);
|
||||
+ expected[expectedsize-1] = L'\0';
|
||||
+
|
||||
+ const size_t resultsize = mbssize * sizeof (wchar_t);
|
||||
+ wchar_t *result = xmalloc (resultsize);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = swprintf (result, resultsize, L"%.65537s", mbs);
|
||||
+ TEST_COMPARE (ret, mbssize - 1);
|
||||
+ TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t),
|
||||
+ expected, expectedsize * sizeof (wchar_t));
|
||||
+
|
||||
+ ret = swprintf (result, resultsize, L"%1$.65537s", mbs);
|
||||
+ TEST_COMPARE (ret, mbssize - 1);
|
||||
+ TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t),
|
||||
+ expected, expectedsize * sizeof (wchar_t));
|
||||
+
|
||||
+ /* Same test, but with an invalid multibyte sequence. */
|
||||
+ mbs[mbssize - 2] = 0xff;
|
||||
+
|
||||
+ ret = swprintf (result, resultsize, L"%.65537s", mbs);
|
||||
+ TEST_COMPARE (ret, -1);
|
||||
+
|
||||
+ ret = swprintf (result, resultsize, L"%1$.65537s", mbs);
|
||||
+ TEST_COMPARE (ret, -1);
|
||||
+
|
||||
+ free (mbs);
|
||||
+ free (result);
|
||||
+ free (expected);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
356
SOURCES/glibc-rh2122501-3.patch
Normal file
356
SOURCES/glibc-rh2122501-3.patch
Normal file
@ -0,0 +1,356 @@
|
||||
commit e1c0c00cc2bdd147bfcf362ada1443bee90465ec
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Tue Jul 7 14:54:12 2020 +0000
|
||||
|
||||
Remove most vfprintf width/precision-dependent allocations (bug 14231, bug 26211).
|
||||
|
||||
The vfprintf implementation (used for all printf-family functions)
|
||||
contains complicated logic to allocate internal buffers of a size
|
||||
depending on the width and precision used for a format, using either
|
||||
malloc or alloca depending on that size, and with consequent checks
|
||||
for size overflow and allocation failure.
|
||||
|
||||
As noted in bug 26211, the version of that logic used when '$' plus
|
||||
argument number formats are in use is missing the overflow checks,
|
||||
which can result in segfaults (quite possibly exploitable, I didn't
|
||||
try to work that out) when the width or precision is in the range
|
||||
0x7fffffe0 through 0x7fffffff (maybe smaller values as well in the
|
||||
wprintf case on 32-bit systems, when the multiplication by sizeof
|
||||
(CHAR_T) can overflow).
|
||||
|
||||
All that complicated logic in fact appears to be useless. As far as I
|
||||
can tell, there has been no need (outside the floating-point printf
|
||||
code, which does its own allocations) for allocations depending on
|
||||
width or precision since commit
|
||||
3e95f6602b226e0de06aaff686dc47b282d7cc16 ("Remove limitation on size
|
||||
of precision for integers", Sun Sep 12 21:23:32 1999 +0000). Thus,
|
||||
this patch removes that logic completely, thereby fixing both problems
|
||||
with excessive allocations for large width and precision for
|
||||
non-floating-point formats, and the problem with missing overflow
|
||||
checks with such allocations. Note that this does have the
|
||||
consequence that width and precision up to INT_MAX are now allowed
|
||||
where previously INT_MAX / sizeof (CHAR_T) - EXTSIZ or more would have
|
||||
been rejected, so could potentially expose any other overflows where
|
||||
the value would previously have been rejected by those removed checks.
|
||||
|
||||
I believe this completely fixes bugs 14231 and 26211.
|
||||
|
||||
Excessive allocations are still possible in the floating-point case
|
||||
(bug 21127), as are other integer or buffer overflows (see bug 26201).
|
||||
This does not address the cases where a precision larger than INT_MAX
|
||||
(embedded in the format string) would be meaningful without printf's
|
||||
return value overflowing (when it's used with a string format, or %g
|
||||
without the '#' flag, so the actual output will be much smaller), as
|
||||
mentioned in bug 17829 comment 8; using size_t internally for
|
||||
precision to handle that case would be complicated by struct
|
||||
printf_info being a public ABI. Nor does it address the matter of an
|
||||
INT_MIN width being negated (bug 17829 comment 7; the same logic
|
||||
appears a second time in the file as well, in the form of multiplying
|
||||
by -1). There may be other sources of memory allocations with malloc
|
||||
in printf functions as well (bug 24988, bug 16060). From inspection,
|
||||
I think there are also integer overflows in two copies of "if ((width
|
||||
-= len) < 0)" logic (where width is int, len is size_t and a very long
|
||||
string could result in spurious padding being output on a 32-bit
|
||||
system before printf overflows the count of output characters).
|
||||
|
||||
Tested for x86-64 and x86.
|
||||
|
||||
(cherry picked from commit 6caddd34bd7ffb5ac4f36c8e036eee100c2cc535)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index 51062a7dbf698931..d76b47bd5f932f69 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -64,6 +64,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
||||
tst-scanf-round \
|
||||
tst-renameat2 \
|
||||
tst-printf-bz25691 \
|
||||
+ tst-vfprintf-width-prec-alloc
|
||||
|
||||
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
|
||||
|
||||
diff --git a/stdio-common/bug22.c b/stdio-common/bug22.c
|
||||
index b26399acb7dfc775..e12b01731e1b4ac8 100644
|
||||
--- a/stdio-common/bug22.c
|
||||
+++ b/stdio-common/bug22.c
|
||||
@@ -42,7 +42,7 @@ do_test (void)
|
||||
|
||||
ret = fprintf (fp, "%." SN3 "d", 1);
|
||||
printf ("ret = %d\n", ret);
|
||||
- if (ret != -1 || errno != EOVERFLOW)
|
||||
+ if (ret != N3)
|
||||
return 1;
|
||||
|
||||
ret = fprintf (fp, "%" SN2 "d%" SN2 "d", 1, 1);
|
||||
diff --git a/stdio-common/tst-vfprintf-width-prec-alloc.c b/stdio-common/tst-vfprintf-width-prec-alloc.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..0a74b53a3389d699
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-vfprintf-width-prec-alloc.c
|
||||
@@ -0,0 +1,41 @@
|
||||
+/* Test large width or precision does not involve large allocation.
|
||||
+ Copyright (C) 2020 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/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <sys/resource.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+char test_string[] = "test";
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ struct rlimit limit;
|
||||
+ TEST_VERIFY_EXIT (getrlimit (RLIMIT_AS, &limit) == 0);
|
||||
+ limit.rlim_cur = 200 * 1024 * 1024;
|
||||
+ TEST_VERIFY_EXIT (setrlimit (RLIMIT_AS, &limit) == 0);
|
||||
+ FILE *fp = fopen ("/dev/null", "w");
|
||||
+ TEST_VERIFY_EXIT (fp != NULL);
|
||||
+ TEST_COMPARE (fprintf (fp, "%1000000000d", 1), 1000000000);
|
||||
+ TEST_COMPARE (fprintf (fp, "%.1000000000s", test_string), 4);
|
||||
+ TEST_COMPARE (fprintf (fp, "%1000000000d %1000000000d", 1, 2), 2000000001);
|
||||
+ TEST_COMPARE (fprintf (fp, "%2$.*1$s", 0x7fffffff, test_string), 4);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
|
||||
index dab56b6ba2c7bdbe..6b83ba91a12cdcd5 100644
|
||||
--- a/stdio-common/vfprintf.c
|
||||
+++ b/stdio-common/vfprintf.c
|
||||
@@ -42,10 +42,6 @@
|
||||
|
||||
#include <libioP.h>
|
||||
|
||||
-/* In some cases we need extra space for all the output which is not
|
||||
- counted in the width of the string. We assume 32 characters is
|
||||
- enough. */
|
||||
-#define EXTSIZ 32
|
||||
#define ARGCHECK(S, Format) \
|
||||
do \
|
||||
{ \
|
||||
@@ -1295,7 +1291,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
|
||||
/* Buffer intermediate results. */
|
||||
CHAR_T work_buffer[WORK_BUFFER_SIZE];
|
||||
- CHAR_T *workstart = NULL;
|
||||
CHAR_T *workend;
|
||||
|
||||
/* We have to save the original argument pointer. */
|
||||
@@ -1404,7 +1399,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
UCHAR_T pad = L_(' ');/* Padding character. */
|
||||
CHAR_T spec;
|
||||
|
||||
- workstart = NULL;
|
||||
workend = work_buffer + WORK_BUFFER_SIZE;
|
||||
|
||||
/* Get current character in format string. */
|
||||
@@ -1496,31 +1490,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
pad = L_(' ');
|
||||
left = 1;
|
||||
}
|
||||
-
|
||||
- if (__glibc_unlikely (width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
|
||||
- {
|
||||
- __set_errno (EOVERFLOW);
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
-
|
||||
- if (width >= WORK_BUFFER_SIZE - EXTSIZ)
|
||||
- {
|
||||
- /* We have to use a special buffer. */
|
||||
- size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
|
||||
- if (__libc_use_alloca (needed))
|
||||
- workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
|
||||
- else
|
||||
- {
|
||||
- workstart = (CHAR_T *) malloc (needed);
|
||||
- if (workstart == NULL)
|
||||
- {
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- workend = workstart + width + EXTSIZ;
|
||||
- }
|
||||
- }
|
||||
}
|
||||
JUMP (*f, step1_jumps);
|
||||
|
||||
@@ -1528,31 +1497,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
LABEL (width):
|
||||
width = read_int (&f);
|
||||
|
||||
- if (__glibc_unlikely (width == -1
|
||||
- || width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
|
||||
+ if (__glibc_unlikely (width == -1))
|
||||
{
|
||||
__set_errno (EOVERFLOW);
|
||||
done = -1;
|
||||
goto all_done;
|
||||
}
|
||||
|
||||
- if (width >= WORK_BUFFER_SIZE - EXTSIZ)
|
||||
- {
|
||||
- /* We have to use a special buffer. */
|
||||
- size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
|
||||
- if (__libc_use_alloca (needed))
|
||||
- workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
|
||||
- else
|
||||
- {
|
||||
- workstart = (CHAR_T *) malloc (needed);
|
||||
- if (workstart == NULL)
|
||||
- {
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- workend = workstart + width + EXTSIZ;
|
||||
- }
|
||||
- }
|
||||
if (*f == L_('$'))
|
||||
/* Oh, oh. The argument comes from a positional parameter. */
|
||||
goto do_positional;
|
||||
@@ -1601,34 +1552,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
}
|
||||
else
|
||||
prec = 0;
|
||||
- if (prec > width && prec > WORK_BUFFER_SIZE - EXTSIZ)
|
||||
- {
|
||||
- /* Deallocate any previously allocated buffer because it is
|
||||
- too small. */
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
- workstart = NULL;
|
||||
- if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
|
||||
- {
|
||||
- __set_errno (EOVERFLOW);
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- size_t needed = ((size_t) prec + EXTSIZ) * sizeof (CHAR_T);
|
||||
-
|
||||
- if (__libc_use_alloca (needed))
|
||||
- workend = (CHAR_T *) alloca (needed) + prec + EXTSIZ;
|
||||
- else
|
||||
- {
|
||||
- workstart = (CHAR_T *) malloc (needed);
|
||||
- if (workstart == NULL)
|
||||
- {
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- workend = workstart + prec + EXTSIZ;
|
||||
- }
|
||||
- }
|
||||
JUMP (*f, step2_jumps);
|
||||
|
||||
/* Process 'h' modifier. There might another 'h' following. */
|
||||
@@ -1692,10 +1615,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
/* The format is correctly handled. */
|
||||
++nspecs_done;
|
||||
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
- workstart = NULL;
|
||||
-
|
||||
/* Look for next format specifier. */
|
||||
#ifdef COMPILE_WPRINTF
|
||||
f = __find_specwc ((end_of_spec = ++f));
|
||||
@@ -1713,18 +1632,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
|
||||
|
||||
/* Hand off processing for positional parameters. */
|
||||
do_positional:
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- {
|
||||
- free (workstart);
|
||||
- workstart = NULL;
|
||||
- }
|
||||
done = printf_positional (s, format, readonly_format, ap, &ap_save,
|
||||
done, nspecs_done, lead_str_end, work_buffer,
|
||||
save_errno, grouping, thousands_sep);
|
||||
|
||||
all_done:
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
/* Unlock the stream. */
|
||||
_IO_funlockfile (s);
|
||||
_IO_cleanup_region_end (0);
|
||||
@@ -1767,8 +1679,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
/* Just a counter. */
|
||||
size_t cnt;
|
||||
|
||||
- CHAR_T *workstart = NULL;
|
||||
-
|
||||
if (grouping == (const char *) -1)
|
||||
{
|
||||
#ifdef COMPILE_WPRINTF
|
||||
@@ -1957,7 +1867,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
char pad = specs[nspecs_done].info.pad;
|
||||
CHAR_T spec = specs[nspecs_done].info.spec;
|
||||
|
||||
- workstart = NULL;
|
||||
CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
|
||||
|
||||
/* Fill in last information. */
|
||||
@@ -1991,27 +1900,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
prec = specs[nspecs_done].info.prec;
|
||||
}
|
||||
|
||||
- /* Maybe the buffer is too small. */
|
||||
- if (MAX (prec, width) + EXTSIZ > WORK_BUFFER_SIZE)
|
||||
- {
|
||||
- if (__libc_use_alloca ((MAX (prec, width) + EXTSIZ)
|
||||
- * sizeof (CHAR_T)))
|
||||
- workend = ((CHAR_T *) alloca ((MAX (prec, width) + EXTSIZ)
|
||||
- * sizeof (CHAR_T))
|
||||
- + (MAX (prec, width) + EXTSIZ));
|
||||
- else
|
||||
- {
|
||||
- workstart = (CHAR_T *) malloc ((MAX (prec, width) + EXTSIZ)
|
||||
- * sizeof (CHAR_T));
|
||||
- if (workstart == NULL)
|
||||
- {
|
||||
- done = -1;
|
||||
- goto all_done;
|
||||
- }
|
||||
- workend = workstart + (MAX (prec, width) + EXTSIZ);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
/* Process format specifiers. */
|
||||
while (1)
|
||||
{
|
||||
@@ -2085,18 +1973,12 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
break;
|
||||
}
|
||||
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
- workstart = NULL;
|
||||
-
|
||||
/* Write the following constant string. */
|
||||
outstring (specs[nspecs_done].end_of_fmt,
|
||||
specs[nspecs_done].next_fmt
|
||||
- specs[nspecs_done].end_of_fmt);
|
||||
}
|
||||
all_done:
|
||||
- if (__glibc_unlikely (workstart != NULL))
|
||||
- free (workstart);
|
||||
scratch_buffer_free (&argsbuf);
|
||||
scratch_buffer_free (&specsbuf);
|
||||
return done;
|
86
SOURCES/glibc-rh2122501-4.patch
Normal file
86
SOURCES/glibc-rh2122501-4.patch
Normal file
@ -0,0 +1,86 @@
|
||||
commit 211a30a92b72a18ea4caa35ed503b70bc644923e
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Nov 8 19:11:51 2021 +0000
|
||||
|
||||
Fix memmove call in vfprintf-internal.c:group_number
|
||||
|
||||
A recent GCC mainline change introduces errors of the form:
|
||||
|
||||
vfprintf-internal.c: In function 'group_number':
|
||||
vfprintf-internal.c:2093:15: error: 'memmove' specified bound between 9223372036854775808 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Werror=stringop-overflow=]
|
||||
2093 | memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is a genuine bug in the glibc code: s > front_ptr is always true
|
||||
at this point in the code, and the intent is clearly for the
|
||||
subtraction to be the other way round. The other arguments to the
|
||||
memmove call here also appear to be wrong; w and s point just *after*
|
||||
the destination and source for copying the rest of the number, so the
|
||||
size needs to be subtracted to get appropriate pointers for the
|
||||
copying. Adjust the memmove call to conform to the apparent intent of
|
||||
the code, so fixing the -Wstringop-overflow error.
|
||||
|
||||
Now, if the original code were ever executed, a buffer overrun would
|
||||
result. However, I believe this code (introduced in commit
|
||||
edc1686af0c0fc2eb535f1d38cdf63c1a5a03675, "vfprintf: Reuse work_buffer
|
||||
in group_number", so in glibc 2.26) is unreachable in prior glibc
|
||||
releases (so there is no need for a bug in Bugzilla, no need to
|
||||
consider any backports unless someone wants to build older glibc
|
||||
releases with GCC 12 and no possibility of this buffer overrun
|
||||
resulting in a security issue).
|
||||
|
||||
work_buffer is 1000 bytes / 250 wide characters. This case is only
|
||||
reachable if an initial part of the number, plus a grouped copy of the
|
||||
rest of the number, fail to fit in that space; that is, if the grouped
|
||||
number fails to fit in the space. In the wide character case,
|
||||
grouping is always one wide character, so even with a locale (of which
|
||||
there aren't any in glibc) grouping every digit, a number would need
|
||||
to occupy at least 125 wide characters to overflow, and a 64-bit
|
||||
integer occupies at most 23 characters in octal including a leading 0.
|
||||
In the narrow character case, the multibyte encoding of the grouping
|
||||
separator would need to be at least 42 bytes to overflow, again
|
||||
supposing grouping every digit, but MB_LEN_MAX is 16. So even if we
|
||||
admit the case of artificially constructed locales not shipped with
|
||||
glibc, given that such a locale would need to use one of the character
|
||||
sets supported by glibc, this code cannot be reached at present. (And
|
||||
POSIX only actually specifies the ' flag for grouping for decimal
|
||||
output, though glibc acts on it for other bases as well.)
|
||||
|
||||
With binary output (if you consider use of grouping there to be
|
||||
valid), you'd need a 15-byte multibyte character for overflow; I don't
|
||||
know if any supported character set has such a character (if, again,
|
||||
we admit constructed locales using grouping every digit and a grouping
|
||||
separator chosen to have a multibyte encoding as long as possible, as
|
||||
well as accepting use of grouping with binary), but given that we have
|
||||
this code at all (clearly it's not *correct*, or in accordance with
|
||||
the principle of avoiding arbitrary limits, to skip grouping on
|
||||
running out of internal space like that), I don't think it should need
|
||||
any further changes for binary printf support to go in.
|
||||
|
||||
On the other hand, support for large sizes of _BitInt in printf (see
|
||||
the N2858 proposal) *would* require something to be done about such
|
||||
arbitrary limits (presumably using dynamic allocation in printf again,
|
||||
for sufficiently large _BitInt arguments only - currently only
|
||||
floating-point uses dynamic allocation, and, as previously discussed,
|
||||
that could actually be replaced by bounded allocation given smarter
|
||||
code).
|
||||
|
||||
Tested with build-many-glibcs.py for aarch64-linux-gnu (GCC mainline).
|
||||
Also tested natively for x86_64.
|
||||
|
||||
(cherry picked from commit db6c4935fae6005d46af413b32aa92f4f6059dce)
|
||||
|
||||
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
|
||||
index 6b83ba91a12cdcd5..2d434ba45a67911e 100644
|
||||
--- a/stdio-common/vfprintf.c
|
||||
+++ b/stdio-common/vfprintf.c
|
||||
@@ -2101,7 +2101,8 @@ group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
|
||||
copy_rest:
|
||||
/* No further grouping to be done. Copy the rest of the
|
||||
number. */
|
||||
- memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
|
||||
+ w -= s - front_ptr;
|
||||
+ memmove (w, front_ptr, (s - front_ptr) * sizeof (CHAR_T));
|
||||
break;
|
||||
}
|
||||
else if (*grouping != '\0')
|
81
SOURCES/glibc-rh2122501-5.patch
Normal file
81
SOURCES/glibc-rh2122501-5.patch
Normal file
@ -0,0 +1,81 @@
|
||||
commit 8b915921fbf4d32bf68fc3d637413cf96236b3fd
|
||||
Author: Andreas Schwab <schwab@suse.de>
|
||||
Date: Mon Aug 29 15:05:40 2022 +0200
|
||||
|
||||
Add test for bug 29530
|
||||
|
||||
This tests for a bug that was introduced in commit edc1686af0 ("vfprintf:
|
||||
Reuse work_buffer in group_number") and fixed as a side effect of commit
|
||||
6caddd34bd ("Remove most vfprintf width/precision-dependent allocations
|
||||
(bug 14231, bug 26211).").
|
||||
|
||||
(cherry picked from commit ca6466e8be32369a658035d69542d47603e58a99)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index d76b47bd5f932f69..ac61093660ef9063 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -64,7 +64,9 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
||||
tst-scanf-round \
|
||||
tst-renameat2 \
|
||||
tst-printf-bz25691 \
|
||||
- tst-vfprintf-width-prec-alloc
|
||||
+ tst-vfprintf-width-prec-alloc \
|
||||
+ tst-grouping2 \
|
||||
+ # tests
|
||||
|
||||
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
|
||||
|
||||
@@ -91,6 +93,7 @@ $(objpfx)bug14.out: $(gen-locales)
|
||||
$(objpfx)scanf13.out: $(gen-locales)
|
||||
$(objpfx)test-vfprintf.out: $(gen-locales)
|
||||
$(objpfx)tst-grouping.out: $(gen-locales)
|
||||
+$(objpfx)tst-grouping2.out: $(gen-locales)
|
||||
$(objpfx)tst-sprintf.out: $(gen-locales)
|
||||
$(objpfx)tst-sscanf.out: $(gen-locales)
|
||||
$(objpfx)tst-swprintf.out: $(gen-locales)
|
||||
diff --git a/stdio-common/tst-grouping2.c b/stdio-common/tst-grouping2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..3024c942a60e51bf
|
||||
--- /dev/null
|
||||
+++ b/stdio-common/tst-grouping2.c
|
||||
@@ -0,0 +1,39 @@
|
||||
+/* Test printf with grouping and large width (bug 29530)
|
||||
+ Copyright (C) 2022 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/>. */
|
||||
+
|
||||
+#include <locale.h>
|
||||
+#include <stdio.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ const int field_width = 1000;
|
||||
+ char buf[field_width + 1];
|
||||
+
|
||||
+ xsetlocale (LC_NUMERIC, "de_DE.UTF-8");
|
||||
+
|
||||
+ /* This used to crash in group_number. */
|
||||
+ TEST_COMPARE (sprintf (buf, "%'*d", field_width, 1000), field_width);
|
||||
+ TEST_COMPARE_STRING (buf + field_width - 6, " 1.000");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
54
SOURCES/glibc-rh2125222.patch
Normal file
54
SOURCES/glibc-rh2125222.patch
Normal file
@ -0,0 +1,54 @@
|
||||
commit a23820f6052a740246fdc7dcd9c43ce8eed0c45a
|
||||
Author: Javier Pello <devel@otheo.eu>
|
||||
Date: Mon Sep 5 20:09:01 2022 +0200
|
||||
|
||||
elf: Fix hwcaps string size overestimation
|
||||
|
||||
Commit dad90d528259b669342757c37dedefa8577e2636 added glibc-hwcaps
|
||||
support for LD_LIBRARY_PATH and, for this, it adjusted the total
|
||||
string size required in _dl_important_hwcaps. However, in doing so
|
||||
it inadvertently altered the calculation of the size required for
|
||||
the power set strings, as the computation of the power set string
|
||||
size depended on the first value assigned to the total variable,
|
||||
which is later shifted, resulting in overallocation of string
|
||||
space. Fix this now by using a different variable to hold the
|
||||
string size required for glibc-hwcaps.
|
||||
|
||||
Signed-off-by: Javier Pello <devel@otheo.eu>
|
||||
|
||||
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
|
||||
index 2fc4ae67a0f5d051..7ac27fd689187edc 100644
|
||||
--- a/elf/dl-hwcaps.c
|
||||
+++ b/elf/dl-hwcaps.c
|
||||
@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||||
/* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix
|
||||
and a "/" suffix once stored in the result. */
|
||||
hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1;
|
||||
- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
|
||||
+ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
|
||||
+ hwcaps_counts.total_length);
|
||||
|
||||
/* Count the number of bits set in the masked value. */
|
||||
@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||||
assert (m == cnt);
|
||||
|
||||
/* Determine the total size of all strings together. */
|
||||
+ size_t total;
|
||||
if (cnt == 1)
|
||||
- total += temp[0].len + 1;
|
||||
+ total = temp[0].len + 1;
|
||||
else
|
||||
{
|
||||
- total += temp[0].len + temp[cnt - 1].len + 2;
|
||||
+ total = temp[0].len + temp[cnt - 1].len + 2;
|
||||
if (cnt > 2)
|
||||
{
|
||||
total <<= 1;
|
||||
@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||||
/* This is the overall result, including both glibc-hwcaps
|
||||
subdirectories and the legacy hwcaps subdirectories using the
|
||||
power set construction. */
|
||||
+ total += hwcaps_sz;
|
||||
struct r_strlenpair *overall_result
|
||||
= malloc (*sz * sizeof (*result) + total);
|
||||
if (overall_result == NULL)
|
32
SOURCES/glibc-rh2139875-1.patch
Normal file
32
SOURCES/glibc-rh2139875-1.patch
Normal file
@ -0,0 +1,32 @@
|
||||
commit acb55dcb892d4321ada6fd9b663b28fada432682
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Wed Jan 2 18:35:50 2019 +0000
|
||||
|
||||
Update Linux kernel version in tst-mman-consts.py.
|
||||
|
||||
This patch updates the Linux kernel version in tst-mman-consts.py to
|
||||
4.20 (meaning that's the version for which glibc is expected to have
|
||||
the same constants as the kernel, up to the exceptions listed in the
|
||||
test). (Once we have more such tests sharing common infrastructure, I
|
||||
expect the kernel version will be something set in the infrastructure
|
||||
shared by all such tests, rather than something needing updating
|
||||
separately for each test for each new kernel version.)
|
||||
|
||||
Tested with build-many-glibcs.py.
|
||||
|
||||
* sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Expect
|
||||
constants to match with Linux 4.20.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
index 1a613beec0da16fb..4a2ddd49c4c7282b 100644
|
||||
--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
@@ -41,7 +41,7 @@ def main():
|
||||
help='C compiler (including options) to use')
|
||||
args = parser.parse_args()
|
||||
linux_version_headers = linux_kernel_version(args.cc)
|
||||
- linux_version_glibc = (4, 19)
|
||||
+ linux_version_glibc = (4, 20)
|
||||
sys.exit(glibcextract.compare_macro_consts(
|
||||
'#define _GNU_SOURCE 1\n'
|
||||
'#include <sys/mman.h>\n',
|
31
SOURCES/glibc-rh2139875-2.patch
Normal file
31
SOURCES/glibc-rh2139875-2.patch
Normal file
@ -0,0 +1,31 @@
|
||||
commit c7a26cba2ab949216ac9ef245ca78696815ea4c4
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Fri Aug 2 11:36:07 2019 +0000
|
||||
|
||||
Update Linux kernel version number in tst-mman-consts.py to 5.2.
|
||||
|
||||
The tst-mman-consts.py test includes a kernel version number, to avoid
|
||||
failures because of newly added constants in the kernel (if kernel
|
||||
headers are newer than this version of glibc) or missing constants in
|
||||
the kernel (if kernel headers are older than this version of glibc).
|
||||
This patch updates it to 5.2 to reflect that the MAP_* constants in
|
||||
glibc are still current as of that kernel version.
|
||||
|
||||
Tested with build-many-glibcs.py.
|
||||
|
||||
* sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Update Linux
|
||||
kernel version number to 5.2.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
index 4a2ddd49c4c7282b..9e326b1f31799a72 100644
|
||||
--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
@@ -41,7 +41,7 @@ def main():
|
||||
help='C compiler (including options) to use')
|
||||
args = parser.parse_args()
|
||||
linux_version_headers = linux_kernel_version(args.cc)
|
||||
- linux_version_glibc = (4, 20)
|
||||
+ linux_version_glibc = (5, 2)
|
||||
sys.exit(glibcextract.compare_macro_consts(
|
||||
'#define _GNU_SOURCE 1\n'
|
||||
'#include <sys/mman.h>\n',
|
61
SOURCES/glibc-rh2139875-3.patch
Normal file
61
SOURCES/glibc-rh2139875-3.patch
Normal file
@ -0,0 +1,61 @@
|
||||
commit 71bdf29ac1de04efcce96bc5ce50af3263851ac7
|
||||
Author: Joseph Myers <joseph@codesourcery.com>
|
||||
Date: Mon Sep 30 15:49:25 2019 +0000
|
||||
|
||||
Update bits/mman.h constants and tst-mman-consts.py for Linux 5.3.
|
||||
|
||||
The Linux 5.3 uapi headers have some rearrangement relating to MAP_*
|
||||
constants, which includes the effect of adding definitions of MAP_SYNC
|
||||
on powerpc and sparc. This patch updates the corresponding glibc
|
||||
bits/mman.h headers accordingly, and updates the Linux kernel version
|
||||
number in tst-mman-consts.py to reflect that these constants are now
|
||||
current with that kernel version.
|
||||
|
||||
Tested with build-many-glibcs.py.
|
||||
|
||||
* sysdeps/unix/sysv/linux/powerpc/bits/mman.h [__USE_MISC]
|
||||
(MAP_SYNC): New macro.
|
||||
* sysdeps/unix/sysv/linux/sparc/bits/mman.h [__USE_MISC]
|
||||
(MAP_SYNC): Likewise.
|
||||
* sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Update Linux
|
||||
kernel version number to 5.3.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/mman.h b/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
|
||||
index e652467c8c091381..0e7fa647793ed585 100644
|
||||
--- a/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
|
||||
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
|
||||
@@ -36,6 +36,8 @@
|
||||
# define MAP_NONBLOCK 0x10000 /* Do not block on IO. */
|
||||
# define MAP_STACK 0x20000 /* Allocation is for a stack. */
|
||||
# define MAP_HUGETLB 0x40000 /* Create huge page mapping. */
|
||||
+# define MAP_SYNC 0x80000 /* Perform synchronous page
|
||||
+ faults for the mapping. */
|
||||
# define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED but do not unmap
|
||||
underlying mapping. */
|
||||
#endif
|
||||
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/mman.h b/sysdeps/unix/sysv/linux/sparc/bits/mman.h
|
||||
index 3a3ffb994631e2b6..03f6f732bb5efbe2 100644
|
||||
--- a/sysdeps/unix/sysv/linux/sparc/bits/mman.h
|
||||
+++ b/sysdeps/unix/sysv/linux/sparc/bits/mman.h
|
||||
@@ -36,6 +36,8 @@
|
||||
# define MAP_NONBLOCK 0x10000 /* Do not block on IO. */
|
||||
# define MAP_STACK 0x20000 /* Allocation is for a stack. */
|
||||
# define MAP_HUGETLB 0x40000 /* Create huge page mapping. */
|
||||
+# define MAP_SYNC 0x80000 /* Perform synchronous page
|
||||
+ faults for the mapping. */
|
||||
# define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED but do not unmap
|
||||
underlying mapping. */
|
||||
#endif
|
||||
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
index 9e326b1f31799a72..42914e4e0ba84712 100644
|
||||
--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
|
||||
@@ -41,7 +41,7 @@ def main():
|
||||
help='C compiler (including options) to use')
|
||||
args = parser.parse_args()
|
||||
linux_version_headers = linux_kernel_version(args.cc)
|
||||
- linux_version_glibc = (5, 2)
|
||||
+ linux_version_glibc = (5, 3)
|
||||
sys.exit(glibcextract.compare_macro_consts(
|
||||
'#define _GNU_SOURCE 1\n'
|
||||
'#include <sys/mman.h>\n',
|
101
SOURCES/glibc-rh2141989.patch
Normal file
101
SOURCES/glibc-rh2141989.patch
Normal file
@ -0,0 +1,101 @@
|
||||
This change is equivalent to this upstream change:
|
||||
|
||||
commit 22a46dee24351fd5f4f188ad80554cad79c82524
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Nov 8 14:15:02 2022 +0100
|
||||
|
||||
Linux: Support __IPC_64 in sysvctl *ctl command arguments (bug 29771)
|
||||
|
||||
Old applications pass __IPC_64 as part of the command argument because
|
||||
old glibc did not check for unknown commands, and passed through the
|
||||
arguments directly to the kernel, without adding __IPC_64.
|
||||
Applications need to continue doing that for old glibc compatibility,
|
||||
so this commit enables this approach in current glibc.
|
||||
|
||||
For msgctl and shmctl, if no translation is required, make
|
||||
direct system calls, as we did before the time64 changes. If
|
||||
translation is required, mask __IPC_64 from the command argument.
|
||||
|
||||
For semctl, the union-in-vararg argument handling means that
|
||||
translation is needed on all architectures.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
The downstream versions of shmctl and msgctl did not produce
|
||||
errors because they lacked a -1 error return path. There is no
|
||||
translation requirement downstream on any architecture, so we
|
||||
can remove the switch from shmctl and msgctl.
|
||||
|
||||
For semctl, we have to do the varargs translation, so this patch adds
|
||||
the same masking as the upstream commit.
|
||||
|
||||
diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c
|
||||
index 3362f4562f58f28b..7280cba31a8815a2 100644
|
||||
--- a/sysdeps/unix/sysv/linux/msgctl.c
|
||||
+++ b/sysdeps/unix/sysv/linux/msgctl.c
|
||||
@@ -29,20 +29,6 @@
|
||||
int
|
||||
__new_msgctl (int msqid, int cmd, struct msqid_ds *buf)
|
||||
{
|
||||
- switch (cmd)
|
||||
- {
|
||||
- case IPC_RMID:
|
||||
- case IPC_SET:
|
||||
- case IPC_STAT:
|
||||
- case MSG_STAT:
|
||||
- case MSG_STAT_ANY:
|
||||
- case IPC_INFO:
|
||||
- case MSG_INFO:
|
||||
- break;
|
||||
- default:
|
||||
- __set_errno (EINVAL);
|
||||
- return -1;
|
||||
- }
|
||||
#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
|
||||
return INLINE_SYSCALL_CALL (msgctl, msqid, cmd | __IPC_64, buf);
|
||||
#else
|
||||
diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c
|
||||
index 03c56c69a5412c82..16d3f04fadd039ab 100644
|
||||
--- a/sysdeps/unix/sysv/linux/semctl.c
|
||||
+++ b/sysdeps/unix/sysv/linux/semctl.c
|
||||
@@ -42,6 +42,13 @@ __new_semctl (int semid, int semnum, int cmd, ...)
|
||||
union semun arg = { 0 };
|
||||
va_list ap;
|
||||
|
||||
+ /* Some applications pass the __IPC_64 flag in cmd, to invoke
|
||||
+ previously unsupported commands back when there was no EINVAL
|
||||
+ error checking in glibc. Mask the flag for the switch statements
|
||||
+ below. msgctl_syscall adds back the __IPC_64 flag for the actual
|
||||
+ system call. */
|
||||
+ cmd &= ~__IPC_64;
|
||||
+
|
||||
/* Get the argument only if required. */
|
||||
switch (cmd)
|
||||
{
|
||||
diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c
|
||||
index 00768bc47614f9aa..25c5152944a6fcf3 100644
|
||||
--- a/sysdeps/unix/sysv/linux/shmctl.c
|
||||
+++ b/sysdeps/unix/sysv/linux/shmctl.c
|
||||
@@ -33,22 +33,6 @@
|
||||
int
|
||||
__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
|
||||
{
|
||||
- switch (cmd)
|
||||
- {
|
||||
- case IPC_RMID:
|
||||
- case SHM_LOCK:
|
||||
- case SHM_UNLOCK:
|
||||
- case IPC_SET:
|
||||
- case IPC_STAT:
|
||||
- case SHM_STAT:
|
||||
- case SHM_STAT_ANY:
|
||||
- case IPC_INFO:
|
||||
- case SHM_INFO:
|
||||
- break;
|
||||
- default:
|
||||
- __set_errno (EINVAL);
|
||||
- break;
|
||||
- }
|
||||
#ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
|
||||
return INLINE_SYSCALL_CALL (shmctl, shmid, cmd | __IPC_64, buf);
|
||||
#else
|
354
SOURCES/glibc-rh2142937-1.patch
Normal file
354
SOURCES/glibc-rh2142937-1.patch
Normal file
@ -0,0 +1,354 @@
|
||||
commit 2fe64148a81f0d78050c302f34a6853d21f7cae4
|
||||
Author: DJ Delorie <dj@redhat.com>
|
||||
Date: Mon Mar 28 23:53:33 2022 -0400
|
||||
|
||||
Allow for unpriviledged nested containers
|
||||
|
||||
If the build itself is run in a container, we may not be able to
|
||||
fully set up a nested container for test-container testing.
|
||||
Notably is the mounting of /proc, since it's critical that it
|
||||
be mounted from within the same PID namespace as its users, and
|
||||
thus cannot be bind mounted from outside the container like other
|
||||
mounts.
|
||||
|
||||
This patch defaults to using the parent's PID namespace instead of
|
||||
creating a new one, as this is more likely to be allowed.
|
||||
|
||||
If the test needs an isolated PID namespace, it should add the "pidns"
|
||||
command to its init script.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
nss/tst-reload2.c
|
||||
(not in RHEL-8)
|
||||
support/Makefile
|
||||
(RHEL-8 missing some routines in libsupport-routines)
|
||||
|
||||
diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
|
||||
index f381cb0fa7e6b93d..45ac033a0f897088 100644
|
||||
--- a/elf/tst-pldd.c
|
||||
+++ b/elf/tst-pldd.c
|
||||
@@ -85,6 +85,8 @@ in_str_list (const char *libname, const char *const strlist[])
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
+ support_need_proc ("needs /proc/sys/kernel/yama/ptrace_scope and /proc/$child");
|
||||
+
|
||||
/* Check if our subprocess can be debugged with ptrace. */
|
||||
{
|
||||
int ptrace_scope = support_ptrace_scope ();
|
||||
diff --git a/nptl/tst-pthread-getattr.c b/nptl/tst-pthread-getattr.c
|
||||
index 273b6073abe9cb60..f1c0b39f3a27724c 100644
|
||||
--- a/nptl/tst-pthread-getattr.c
|
||||
+++ b/nptl/tst-pthread-getattr.c
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
+#include <support/support.h>
|
||||
+
|
||||
/* There is an obscure bug in the kernel due to which RLIMIT_STACK is sometimes
|
||||
returned as unlimited when it is not, which may cause this test to fail.
|
||||
There is also the other case where RLIMIT_STACK is intentionally set as
|
||||
@@ -152,6 +154,8 @@ check_stack_top (void)
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
+ support_need_proc ("Reads /proc/self/maps to get stack size.");
|
||||
+
|
||||
pagesize = sysconf (_SC_PAGESIZE);
|
||||
return check_stack_top ();
|
||||
}
|
||||
diff --git a/support/Makefile b/support/Makefile
|
||||
index 636d69c4f8e7e139..e184fccbe7d2310c 100644
|
||||
--- a/support/Makefile
|
||||
+++ b/support/Makefile
|
||||
@@ -59,6 +59,7 @@ libsupport-routines = \
|
||||
support_format_hostent \
|
||||
support_format_netent \
|
||||
support_isolate_in_subprocess \
|
||||
+ support_need_proc \
|
||||
support_process_state \
|
||||
support_ptrace \
|
||||
support_openpty \
|
||||
diff --git a/support/support.h b/support/support.h
|
||||
index 96833bd4e992e6d3..1466eb29f840fa59 100644
|
||||
--- a/support/support.h
|
||||
+++ b/support/support.h
|
||||
@@ -81,6 +81,11 @@ char *support_quote_string (const char *);
|
||||
regular file open for writing, and initially empty. */
|
||||
int support_descriptor_supports_holes (int fd);
|
||||
|
||||
+/* Predicates that a test requires a working /proc filesystem. This
|
||||
+ call will exit with UNSUPPORTED if /proc is not available, printing
|
||||
+ WHY_MSG as part of the diagnostic. */
|
||||
+void support_need_proc (const char *why_msg);
|
||||
+
|
||||
/* Error-checking wrapper functions which terminate the process on
|
||||
error. */
|
||||
|
||||
diff --git a/support/support_need_proc.c b/support/support_need_proc.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..9b4eab7539b2d6c3
|
||||
--- /dev/null
|
||||
+++ b/support/support_need_proc.c
|
||||
@@ -0,0 +1,35 @@
|
||||
+/* Indicate that a test requires a working /proc.
|
||||
+ Copyright (C) 2022 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/>. */
|
||||
+
|
||||
+#include <unistd.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/support.h>
|
||||
+
|
||||
+/* We test for /proc/self/maps since that's one of the files that one
|
||||
+ of our tests actually uses, but the general idea is if Linux's
|
||||
+ /proc/ (procfs) filesystem is mounted. If not, the process exits
|
||||
+ with an UNSUPPORTED result code. */
|
||||
+
|
||||
+void
|
||||
+support_need_proc (const char *why_msg)
|
||||
+{
|
||||
+#ifdef __linux__
|
||||
+ if (access ("/proc/self/maps", R_OK))
|
||||
+ FAIL_UNSUPPORTED ("/proc is not available, %s", why_msg);
|
||||
+#endif
|
||||
+}
|
||||
diff --git a/support/test-container.c b/support/test-container.c
|
||||
index 9975c8cb7bc9a955..2bce4db841ff7668 100644
|
||||
--- a/support/test-container.c
|
||||
+++ b/support/test-container.c
|
||||
@@ -95,6 +95,7 @@ int verbose = 0;
|
||||
* mytest.root/mytest.script has a list of "commands" to run:
|
||||
syntax:
|
||||
# comment
|
||||
+ pidns <comment>
|
||||
su
|
||||
mv FILE FILE
|
||||
cp FILE FILE
|
||||
@@ -120,6 +121,8 @@ int verbose = 0;
|
||||
|
||||
details:
|
||||
- '#': A comment.
|
||||
+ - 'pidns': Require a separate PID namespace, prints comment if it can't
|
||||
+ (default is a shared pid namespace)
|
||||
- 'su': Enables running test as root in the container.
|
||||
- 'mv': A minimal move files command.
|
||||
- 'cp': A minimal copy files command.
|
||||
@@ -143,7 +146,7 @@ int verbose = 0;
|
||||
* Simple, easy to review code (i.e. prefer simple naive code over
|
||||
complex efficient code)
|
||||
|
||||
- * The current implementation ist parallel-make-safe, but only in
|
||||
+ * The current implementation is parallel-make-safe, but only in
|
||||
that it uses a lock to prevent parallel access to the testroot. */
|
||||
|
||||
|
||||
@@ -222,11 +225,37 @@ concat (const char *str, ...)
|
||||
return bufs[n];
|
||||
}
|
||||
|
||||
+/* Like the above, but put spaces between words. Caller frees. */
|
||||
+static char *
|
||||
+concat_words (char **words, int num_words)
|
||||
+{
|
||||
+ int len = 0;
|
||||
+ int i;
|
||||
+ char *rv, *p;
|
||||
+
|
||||
+ for (i = 0; i < num_words; i ++)
|
||||
+ {
|
||||
+ len += strlen (words[i]);
|
||||
+ len ++;
|
||||
+ }
|
||||
+
|
||||
+ p = rv = (char *) xmalloc (len);
|
||||
+
|
||||
+ for (i = 0; i < num_words; i ++)
|
||||
+ {
|
||||
+ if (i > 0)
|
||||
+ p = stpcpy (p, " ");
|
||||
+ p = stpcpy (p, words[i]);
|
||||
+ }
|
||||
+
|
||||
+ return rv;
|
||||
+}
|
||||
+
|
||||
/* Try to mount SRC onto DEST. */
|
||||
static void
|
||||
trymount (const char *src, const char *dest)
|
||||
{
|
||||
- if (mount (src, dest, "", MS_BIND, NULL) < 0)
|
||||
+ if (mount (src, dest, "", MS_BIND | MS_REC, NULL) < 0)
|
||||
FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest);
|
||||
}
|
||||
|
||||
@@ -709,6 +738,9 @@ main (int argc, char **argv)
|
||||
gid_t original_gid;
|
||||
/* If set, the test runs as root instead of the user running the testsuite. */
|
||||
int be_su = 0;
|
||||
+ int require_pidns = 0;
|
||||
+ const char *pidns_comment = NULL;
|
||||
+ int do_proc_mounts = 0;
|
||||
int UMAP;
|
||||
int GMAP;
|
||||
/* Used for "%lld %lld 1" so need not be large. */
|
||||
@@ -991,6 +1023,12 @@ main (int argc, char **argv)
|
||||
{
|
||||
be_su = 1;
|
||||
}
|
||||
+ else if (nt >= 1 && strcmp (the_words[0], "pidns") == 0)
|
||||
+ {
|
||||
+ require_pidns = 1;
|
||||
+ if (nt > 1)
|
||||
+ pidns_comment = concat_words (the_words + 1, nt - 1);
|
||||
+ }
|
||||
else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0)
|
||||
{
|
||||
long int m;
|
||||
@@ -1048,7 +1086,8 @@ main (int argc, char **argv)
|
||||
|
||||
#ifdef CLONE_NEWNS
|
||||
/* The unshare here gives us our own spaces and capabilities. */
|
||||
- if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0)
|
||||
+ if (unshare (CLONE_NEWUSER | CLONE_NEWNS
|
||||
+ | (require_pidns ? CLONE_NEWPID : 0)) < 0)
|
||||
{
|
||||
/* Older kernels may not support all the options, or security
|
||||
policy may block this call. */
|
||||
@@ -1059,6 +1098,11 @@ main (int argc, char **argv)
|
||||
check_for_unshare_hints ();
|
||||
FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
|
||||
}
|
||||
+ /* We're about to exit anyway, it's "safe" to call unshare again
|
||||
+ just to see if the CLONE_NEWPID caused the error. */
|
||||
+ else if (require_pidns && unshare (CLONE_NEWUSER | CLONE_NEWNS) >= 0)
|
||||
+ FAIL_EXIT1 ("unable to unshare pid ns: %s : %s", strerror (errno),
|
||||
+ pidns_comment ? pidns_comment : "required by test");
|
||||
else
|
||||
FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno));
|
||||
}
|
||||
@@ -1074,6 +1118,15 @@ main (int argc, char **argv)
|
||||
trymount (support_srcdir_root, new_srcdir_path);
|
||||
trymount (support_objdir_root, new_objdir_path);
|
||||
|
||||
+ /* It may not be possible to mount /proc directly. */
|
||||
+ if (! require_pidns)
|
||||
+ {
|
||||
+ char *new_proc = concat (new_root_path, "/proc", NULL);
|
||||
+ xmkdirp (new_proc, 0755);
|
||||
+ trymount ("/proc", new_proc);
|
||||
+ do_proc_mounts = 1;
|
||||
+ }
|
||||
+
|
||||
xmkdirp (concat (new_root_path, "/dev", NULL), 0755);
|
||||
devmount (new_root_path, "null");
|
||||
devmount (new_root_path, "zero");
|
||||
@@ -1136,42 +1189,60 @@ main (int argc, char **argv)
|
||||
|
||||
maybe_xmkdir ("/tmp", 0755);
|
||||
|
||||
- /* Now that we're pid 1 (effectively "root") we can mount /proc */
|
||||
- maybe_xmkdir ("/proc", 0777);
|
||||
- if (mount ("proc", "/proc", "proc", 0, NULL) < 0)
|
||||
- FAIL_EXIT1 ("Unable to mount /proc: ");
|
||||
-
|
||||
- /* We map our original UID to the same UID in the container so we
|
||||
- can own our own files normally. */
|
||||
- UMAP = open ("/proc/self/uid_map", O_WRONLY);
|
||||
- if (UMAP < 0)
|
||||
- FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
|
||||
-
|
||||
- sprintf (tmp, "%lld %lld 1\n",
|
||||
- (long long) (be_su ? 0 : original_uid), (long long) original_uid);
|
||||
- write (UMAP, tmp, strlen (tmp));
|
||||
- xclose (UMAP);
|
||||
-
|
||||
- /* We must disable setgroups () before we can map our groups, else we
|
||||
- get EPERM. */
|
||||
- GMAP = open ("/proc/self/setgroups", O_WRONLY);
|
||||
- if (GMAP >= 0)
|
||||
+ if (require_pidns)
|
||||
{
|
||||
- /* We support kernels old enough to not have this. */
|
||||
- write (GMAP, "deny\n", 5);
|
||||
- xclose (GMAP);
|
||||
+ /* Now that we're pid 1 (effectively "root") we can mount /proc */
|
||||
+ maybe_xmkdir ("/proc", 0777);
|
||||
+ if (mount ("proc", "/proc", "proc", 0, NULL) != 0)
|
||||
+ {
|
||||
+ /* This happens if we're trying to create a nested container,
|
||||
+ like if the build is running under podman, and we lack
|
||||
+ priviledges.
|
||||
+
|
||||
+ Ideally we would WARN here, but that would just add noise to
|
||||
+ *every* test-container test, and the ones that care should
|
||||
+ have their own relevent diagnostics.
|
||||
+
|
||||
+ FAIL_EXIT1 ("Unable to mount /proc: "); */
|
||||
+ }
|
||||
+ else
|
||||
+ do_proc_mounts = 1;
|
||||
}
|
||||
|
||||
- /* We map our original GID to the same GID in the container so we
|
||||
- can own our own files normally. */
|
||||
- GMAP = open ("/proc/self/gid_map", O_WRONLY);
|
||||
- if (GMAP < 0)
|
||||
- FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
|
||||
+ if (do_proc_mounts)
|
||||
+ {
|
||||
+ /* We map our original UID to the same UID in the container so we
|
||||
+ can own our own files normally. */
|
||||
+ UMAP = open ("/proc/self/uid_map", O_WRONLY);
|
||||
+ if (UMAP < 0)
|
||||
+ FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
|
||||
+
|
||||
+ sprintf (tmp, "%lld %lld 1\n",
|
||||
+ (long long) (be_su ? 0 : original_uid), (long long) original_uid);
|
||||
+ write (UMAP, tmp, strlen (tmp));
|
||||
+ xclose (UMAP);
|
||||
+
|
||||
+ /* We must disable setgroups () before we can map our groups, else we
|
||||
+ get EPERM. */
|
||||
+ GMAP = open ("/proc/self/setgroups", O_WRONLY);
|
||||
+ if (GMAP >= 0)
|
||||
+ {
|
||||
+ /* We support kernels old enough to not have this. */
|
||||
+ write (GMAP, "deny\n", 5);
|
||||
+ xclose (GMAP);
|
||||
+ }
|
||||
|
||||
- sprintf (tmp, "%lld %lld 1\n",
|
||||
- (long long) (be_su ? 0 : original_gid), (long long) original_gid);
|
||||
- write (GMAP, tmp, strlen (tmp));
|
||||
- xclose (GMAP);
|
||||
+ /* We map our original GID to the same GID in the container so we
|
||||
+ can own our own files normally. */
|
||||
+ GMAP = open ("/proc/self/gid_map", O_WRONLY);
|
||||
+ if (GMAP < 0)
|
||||
+ FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
|
||||
+
|
||||
+ sprintf (tmp, "%lld %lld 1\n",
|
||||
+ (long long) (be_su ? 0 : original_gid), (long long) original_gid);
|
||||
+ write (GMAP, tmp, strlen (tmp));
|
||||
+ xclose (GMAP);
|
||||
+ }
|
||||
|
||||
if (change_cwd)
|
||||
{
|
24
SOURCES/glibc-rh2142937-2.patch
Normal file
24
SOURCES/glibc-rh2142937-2.patch
Normal file
@ -0,0 +1,24 @@
|
||||
commit b2cd93fce666fdc8c9a5c64af2741a8a6940ac99
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Fri Mar 25 11:16:49 2022 -0300
|
||||
|
||||
elf: Fix wrong fscanf usage on tst-pldd
|
||||
|
||||
To take in consideration the extra '\0'.
|
||||
|
||||
Checked on x86_64-linux-gnu.
|
||||
|
||||
diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
|
||||
index 45ac033a0f897088..ab89798e250fdccc 100644
|
||||
--- a/elf/tst-pldd.c
|
||||
+++ b/elf/tst-pldd.c
|
||||
@@ -115,7 +115,8 @@ do_test (void)
|
||||
TEST_VERIFY (out != NULL);
|
||||
|
||||
/* First line is in the form of <pid>: <full path of executable> */
|
||||
- TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2);
|
||||
+ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (sizeof (buffer) - 1), &pid,
|
||||
+ buffer), 2);
|
||||
|
||||
TEST_COMPARE (pid, *target_pid_ptr);
|
||||
TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
|
37
SOURCES/glibc-rh2142937-3.patch
Normal file
37
SOURCES/glibc-rh2142937-3.patch
Normal file
@ -0,0 +1,37 @@
|
||||
commit c353689e49e72f3aafa1a9e68d4f7a4f33a79cbe
|
||||
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
Date: Tue Jul 5 12:58:40 2022 -0300
|
||||
|
||||
elf: Fix wrong fscanf usage on tst-pldd
|
||||
|
||||
The fix done b2cd93fce666fdc8c9a5c64af2741a8a6940ac99 does not really
|
||||
work since macro strification does not expand the sizeof nor the
|
||||
arithmetic operation.
|
||||
|
||||
Checked on x86_64-linux-gnu.
|
||||
|
||||
diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
|
||||
index ab89798e250fdccc..52c0a75be5a808d1 100644
|
||||
--- a/elf/tst-pldd.c
|
||||
+++ b/elf/tst-pldd.c
|
||||
@@ -108,15 +108,16 @@ do_test (void)
|
||||
loader and libc. */
|
||||
{
|
||||
pid_t pid;
|
||||
- char buffer[512];
|
||||
-#define STRINPUT(size) "%" # size "s"
|
||||
+#define BUFFERLEN 511
|
||||
+ char buffer[BUFFERLEN + 1];
|
||||
+#define STRINPUT(size) XSTRINPUT(size)
|
||||
+#define XSTRINPUT(size) "%" # size "s"
|
||||
|
||||
FILE *out = fmemopen (pldd.out.buffer, pldd.out.length, "r");
|
||||
TEST_VERIFY (out != NULL);
|
||||
|
||||
/* First line is in the form of <pid>: <full path of executable> */
|
||||
- TEST_COMPARE (fscanf (out, "%u: " STRINPUT (sizeof (buffer) - 1), &pid,
|
||||
- buffer), 2);
|
||||
+ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (BUFFERLEN), &pid, buffer), 2);
|
||||
|
||||
TEST_COMPARE (pid, *target_pid_ptr);
|
||||
TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
|
45
SOURCES/glibc-rh2144568.patch
Normal file
45
SOURCES/glibc-rh2144568.patch
Normal file
@ -0,0 +1,45 @@
|
||||
commit eb4181e9f4a512de37dad4ba623c921671584dea
|
||||
Author: Vladislav Khmelevsky <och95@yandex.ru>
|
||||
Date: Thu Nov 17 12:47:29 2022 +0400
|
||||
|
||||
elf: Fix rtld-audit trampoline for aarch64
|
||||
|
||||
This patch fixes two problems with audit:
|
||||
|
||||
1. The DL_OFFSET_RV_VPCS offset was mixed up with DL_OFFSET_RG_VPCS,
|
||||
resulting in x2 register value nulling in RG structure.
|
||||
|
||||
2. We need to preserve the x8 register before function call, but
|
||||
don't have to save it's new value and restore it before return.
|
||||
|
||||
Anyway the final restore was using OFFSET_RV instead of OFFSET_RG value
|
||||
which is wrong (althoug doesn't affect anything).
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S
|
||||
index a83e7fc5f97047e2..b4b9c86224785a2c 100644
|
||||
--- a/sysdeps/aarch64/dl-trampoline.S
|
||||
+++ b/sysdeps/aarch64/dl-trampoline.S
|
||||
@@ -282,12 +282,11 @@ _dl_runtime_profile:
|
||||
stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1]
|
||||
stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2]
|
||||
stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3]
|
||||
- str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4]
|
||||
stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
|
||||
stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
|
||||
stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2]
|
||||
stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3]
|
||||
- str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS]
|
||||
+ str xzr, [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS]
|
||||
|
||||
/* Setup call to pltexit */
|
||||
ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0]
|
||||
@@ -299,7 +298,6 @@ _dl_runtime_profile:
|
||||
ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1]
|
||||
ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2]
|
||||
ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3]
|
||||
- ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4]
|
||||
ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
|
||||
ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
|
||||
ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2]
|
297
SOURCES/glibc-rh2154914-1.patch
Normal file
297
SOURCES/glibc-rh2154914-1.patch
Normal file
@ -0,0 +1,297 @@
|
||||
Maintain an explicit order of tunables, so that the tunable_list
|
||||
array and the tunable_id_t constant can remain consistent over time.
|
||||
|
||||
Related to this upstream bug:
|
||||
|
||||
Internal tunables ABI depends on awk array iteration order
|
||||
<https://sourceware.org/bugzilla/show_bug.cgi?id=30027>
|
||||
|
||||
The new dl-tunables.list files are already on the sysdeps search
|
||||
path, which is why the existing Makeconfig rule picks them up.
|
||||
The files for RHEL 8.7.z were created by applying the gen-tunables.awk
|
||||
part of this patch to RHEL 8.7.0 (glibc-2.28-211.el8_7, to be precise).
|
||||
The sysdeps/unix/sysv/linux/**/dl-tunables.list files were created
|
||||
based on the generated error message during the RHEL 8.7.z build.
|
||||
Afterwards, the glibc.rtld.dynamic_sort tunable was added at the
|
||||
end of the files, for the RHEL 8.8.0 build.
|
||||
|
||||
Going forward, new tunables will have to be added manually to the end
|
||||
of those files. Existing tunables should not be deleted. For
|
||||
deletion, the script would have to be extended to be able to create
|
||||
gaps in the tunable_list array.
|
||||
|
||||
diff --git a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk
|
||||
index 622199061a140ccd..8ebfb560976ead41 100644
|
||||
--- a/scripts/gen-tunables.awk
|
||||
+++ b/scripts/gen-tunables.awk
|
||||
@@ -12,6 +12,7 @@ BEGIN {
|
||||
tunable=""
|
||||
ns=""
|
||||
top_ns=""
|
||||
+ tunable_order_count = 0
|
||||
}
|
||||
|
||||
# Skip over blank lines and comments.
|
||||
@@ -78,6 +79,37 @@ $1 == "}" {
|
||||
next
|
||||
}
|
||||
|
||||
+$1 == "@order" {
|
||||
+ if (top_ns != "") {
|
||||
+ printf("%s:%d: error: invalid @order directive inside namespace %s\n",
|
||||
+ FILENAME, FNR, top_ns) > "/dev/stderr"
|
||||
+ exit 1
|
||||
+ }
|
||||
+ if (NF != 2) {
|
||||
+ printf("%s:%d: error: invalid argument count in @order directive\n",
|
||||
+ FILENAME, FNR) > "/dev/stderr"
|
||||
+ exit 1
|
||||
+ }
|
||||
+ order_arg = $2
|
||||
+ if (split(order_arg, indices, /\./) != 3) {
|
||||
+ printf("%s:%d: error: invalid tunable syntax in @order directive\n",
|
||||
+ FILENAME, FNR) > "/dev/stderr"
|
||||
+ exit 1
|
||||
+ }
|
||||
+ t = indices[1]
|
||||
+ n = indices[2]
|
||||
+ m = indices[3]
|
||||
+ if ((t, n, m) in tunable_order) {
|
||||
+ printf("%s:%d: error: duplicate\"@order %s\"\n" \
|
||||
+ FILENAME, FNR, order_arg) > "/dev/stderr"
|
||||
+ exit 1
|
||||
+ }
|
||||
+ ++tunable_order_count
|
||||
+ tunable_order[t,n,m] = tunable_order_count
|
||||
+ tunable_order_list[tunable_order_count] = t SUBSEP n SUBSEP m
|
||||
+ next
|
||||
+}
|
||||
+
|
||||
# Everything else, which could either be a tunable without any attributes or a
|
||||
# tunable attribute.
|
||||
{
|
||||
@@ -137,6 +169,31 @@ END {
|
||||
exit 1
|
||||
}
|
||||
|
||||
+ missing_order = 0
|
||||
+ for (tnm in types) {
|
||||
+ if (!(tnm in tunable_order)) {
|
||||
+ if (!missing_order) {
|
||||
+ print "error: Missing @order directives:" > "/dev/stderr"
|
||||
+ missing_order = 1
|
||||
+ }
|
||||
+ split(tnm, indices, SUBSEP)
|
||||
+ printf("@order %s.%s.%s\n", indices[1], indices[2], indices[3]) \
|
||||
+ > "/dev/stderr"
|
||||
+ }
|
||||
+ }
|
||||
+ for (i = 1; i <= tunable_order_count; ++i) {
|
||||
+ tnm = tunable_order_list[i]
|
||||
+ if (!(tnm in types)) {
|
||||
+ split(tnm, indices, SUBSEP)
|
||||
+ printf("error: tunable in \"@order %s.%s.%s\" not known\n", \
|
||||
+ indices[1], indices[2], indices[3]) > "/dev/stderr"
|
||||
+ missing_order = 1
|
||||
+ }
|
||||
+ }
|
||||
+ if (missing_order) {
|
||||
+ exit 1
|
||||
+ }
|
||||
+
|
||||
print "/* AUTOGENERATED by gen-tunables.awk. */"
|
||||
print "#ifndef _TUNABLES_H_"
|
||||
print "# error \"Do not include this file directly.\""
|
||||
@@ -147,7 +204,8 @@ END {
|
||||
# Now, the enum names
|
||||
print "\ntypedef enum"
|
||||
print "{"
|
||||
- for (tnm in types) {
|
||||
+ for (i = 1; i <= tunable_order_count; ++i) {
|
||||
+ tnm = tunable_order_list[i]
|
||||
split (tnm, indices, SUBSEP);
|
||||
t = indices[1];
|
||||
n = indices[2];
|
||||
@@ -159,7 +217,8 @@ END {
|
||||
# Finally, the tunable list.
|
||||
print "\n#ifdef TUNABLES_INTERNAL"
|
||||
print "static tunable_t tunable_list[] attribute_relro = {"
|
||||
- for (tnm in types) {
|
||||
+ for (i = 1; i <= tunable_order_count; ++i) {
|
||||
+ tnm = tunable_order_list[i]
|
||||
split (tnm, indices, SUBSEP);
|
||||
t = indices[1];
|
||||
n = indices[2];
|
||||
diff --git a/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list b/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list
|
||||
new file mode 100644
|
||||
index 0000000000000000..5c3c5292025607a1
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/aarch64/dl-tunables.list
|
||||
@@ -0,0 +1,26 @@
|
||||
+# Order of tunables in RHEL 8.7.0.
|
||||
+@order glibc.rtld.nns
|
||||
+@order glibc.elision.skip_lock_after_retries
|
||||
+@order glibc.malloc.trim_threshold
|
||||
+@order glibc.malloc.perturb
|
||||
+@order glibc.cpu.name
|
||||
+@order glibc.elision.tries
|
||||
+@order glibc.elision.enable
|
||||
+@order glibc.malloc.mxfast
|
||||
+@order glibc.elision.skip_lock_busy
|
||||
+@order glibc.malloc.top_pad
|
||||
+@order glibc.cpu.hwcap_mask
|
||||
+@order glibc.malloc.mmap_max
|
||||
+@order glibc.elision.skip_trylock_internal_abort
|
||||
+@order glibc.malloc.tcache_unsorted_limit
|
||||
+@order glibc.elision.skip_lock_internal_abort
|
||||
+@order glibc.malloc.arena_max
|
||||
+@order glibc.malloc.mmap_threshold
|
||||
+@order glibc.malloc.tcache_count
|
||||
+@order glibc.malloc.arena_test
|
||||
+@order glibc.rtld.optional_static_tls
|
||||
+@order glibc.malloc.tcache_max
|
||||
+@order glibc.malloc.check
|
||||
+
|
||||
+# Tunables added in RHEL 8.8.0
|
||||
+@order glibc.rtld.dynamic_sort
|
||||
diff --git a/sysdeps/unix/sysv/linux/i386/dl-tunables.list b/sysdeps/unix/sysv/linux/i386/dl-tunables.list
|
||||
new file mode 100644
|
||||
index 0000000000000000..b9cad4af62d9f2e5
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/i386/dl-tunables.list
|
||||
@@ -0,0 +1,33 @@
|
||||
+# Order of tunables in RHEL 8.7.0.
|
||||
+@order glibc.rtld.nns
|
||||
+@order glibc.elision.skip_lock_after_retries
|
||||
+@order glibc.malloc.trim_threshold
|
||||
+@order glibc.malloc.perturb
|
||||
+@order glibc.cpu.x86_shared_cache_size
|
||||
+@order glibc.elision.tries
|
||||
+@order glibc.elision.enable
|
||||
+@order glibc.cpu.x86_rep_movsb_threshold
|
||||
+@order glibc.malloc.mxfast
|
||||
+@order glibc.elision.skip_lock_busy
|
||||
+@order glibc.malloc.top_pad
|
||||
+@order glibc.cpu.x86_rep_stosb_threshold
|
||||
+@order glibc.cpu.x86_non_temporal_threshold
|
||||
+@order glibc.cpu.x86_shstk
|
||||
+@order glibc.cpu.hwcap_mask
|
||||
+@order glibc.malloc.mmap_max
|
||||
+@order glibc.elision.skip_trylock_internal_abort
|
||||
+@order glibc.malloc.tcache_unsorted_limit
|
||||
+@order glibc.cpu.x86_ibt
|
||||
+@order glibc.cpu.hwcaps
|
||||
+@order glibc.elision.skip_lock_internal_abort
|
||||
+@order glibc.malloc.arena_max
|
||||
+@order glibc.malloc.mmap_threshold
|
||||
+@order glibc.cpu.x86_data_cache_size
|
||||
+@order glibc.malloc.tcache_count
|
||||
+@order glibc.malloc.arena_test
|
||||
+@order glibc.rtld.optional_static_tls
|
||||
+@order glibc.malloc.tcache_max
|
||||
+@order glibc.malloc.check
|
||||
+
|
||||
+# Tunables added in RHEL 8.8.0
|
||||
+@order glibc.rtld.dynamic_sort
|
||||
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list
|
||||
new file mode 100644
|
||||
index 0000000000000000..ee1e6fca95e1f2da
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/dl-tunables.list
|
||||
@@ -0,0 +1,26 @@
|
||||
+# Order of tunables in RHEL 8.7.0.
|
||||
+@order glibc.rtld.nns
|
||||
+@order glibc.elision.skip_lock_after_retries
|
||||
+@order glibc.malloc.trim_threshold
|
||||
+@order glibc.malloc.perturb
|
||||
+@order glibc.elision.tries
|
||||
+@order glibc.elision.enable
|
||||
+@order glibc.malloc.mxfast
|
||||
+@order glibc.elision.skip_lock_busy
|
||||
+@order glibc.malloc.top_pad
|
||||
+@order glibc.cpu.hwcap_mask
|
||||
+@order glibc.malloc.mmap_max
|
||||
+@order glibc.elision.skip_trylock_internal_abort
|
||||
+@order glibc.malloc.tcache_unsorted_limit
|
||||
+@order glibc.elision.skip_lock_internal_abort
|
||||
+@order glibc.malloc.arena_max
|
||||
+@order glibc.malloc.mmap_threshold
|
||||
+@order glibc.cpu.cached_memopt
|
||||
+@order glibc.malloc.tcache_count
|
||||
+@order glibc.malloc.arena_test
|
||||
+@order glibc.rtld.optional_static_tls
|
||||
+@order glibc.malloc.tcache_max
|
||||
+@order glibc.malloc.check
|
||||
+
|
||||
+# Tunables added in RHEL 8.8.0
|
||||
+@order glibc.rtld.dynamic_sort
|
||||
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list b/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list
|
||||
new file mode 100644
|
||||
index 0000000000000000..099e28d8f8e67944
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/dl-tunables.list
|
||||
@@ -0,0 +1,25 @@
|
||||
+# Order of tunables in RHEL 8.7.0.
|
||||
+@order glibc.rtld.nns
|
||||
+@order glibc.elision.skip_lock_after_retries
|
||||
+@order glibc.malloc.trim_threshold
|
||||
+@order glibc.malloc.perturb
|
||||
+@order glibc.elision.tries
|
||||
+@order glibc.elision.enable
|
||||
+@order glibc.malloc.mxfast
|
||||
+@order glibc.elision.skip_lock_busy
|
||||
+@order glibc.malloc.top_pad
|
||||
+@order glibc.cpu.hwcap_mask
|
||||
+@order glibc.malloc.mmap_max
|
||||
+@order glibc.elision.skip_trylock_internal_abort
|
||||
+@order glibc.malloc.tcache_unsorted_limit
|
||||
+@order glibc.elision.skip_lock_internal_abort
|
||||
+@order glibc.malloc.arena_max
|
||||
+@order glibc.malloc.mmap_threshold
|
||||
+@order glibc.malloc.tcache_count
|
||||
+@order glibc.malloc.arena_test
|
||||
+@order glibc.rtld.optional_static_tls
|
||||
+@order glibc.malloc.tcache_max
|
||||
+@order glibc.malloc.check
|
||||
+
|
||||
+# Tunables added in RHEL 8.8.0
|
||||
+@order glibc.rtld.dynamic_sort
|
||||
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list
|
||||
new file mode 100644
|
||||
index 0000000000000000..b9cad4af62d9f2e5
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-tunables.list
|
||||
@@ -0,0 +1,33 @@
|
||||
+# Order of tunables in RHEL 8.7.0.
|
||||
+@order glibc.rtld.nns
|
||||
+@order glibc.elision.skip_lock_after_retries
|
||||
+@order glibc.malloc.trim_threshold
|
||||
+@order glibc.malloc.perturb
|
||||
+@order glibc.cpu.x86_shared_cache_size
|
||||
+@order glibc.elision.tries
|
||||
+@order glibc.elision.enable
|
||||
+@order glibc.cpu.x86_rep_movsb_threshold
|
||||
+@order glibc.malloc.mxfast
|
||||
+@order glibc.elision.skip_lock_busy
|
||||
+@order glibc.malloc.top_pad
|
||||
+@order glibc.cpu.x86_rep_stosb_threshold
|
||||
+@order glibc.cpu.x86_non_temporal_threshold
|
||||
+@order glibc.cpu.x86_shstk
|
||||
+@order glibc.cpu.hwcap_mask
|
||||
+@order glibc.malloc.mmap_max
|
||||
+@order glibc.elision.skip_trylock_internal_abort
|
||||
+@order glibc.malloc.tcache_unsorted_limit
|
||||
+@order glibc.cpu.x86_ibt
|
||||
+@order glibc.cpu.hwcaps
|
||||
+@order glibc.elision.skip_lock_internal_abort
|
||||
+@order glibc.malloc.arena_max
|
||||
+@order glibc.malloc.mmap_threshold
|
||||
+@order glibc.cpu.x86_data_cache_size
|
||||
+@order glibc.malloc.tcache_count
|
||||
+@order glibc.malloc.arena_test
|
||||
+@order glibc.rtld.optional_static_tls
|
||||
+@order glibc.malloc.tcache_max
|
||||
+@order glibc.malloc.check
|
||||
+
|
||||
+# Tunables added in RHEL 8.8.0
|
||||
+@order glibc.rtld.dynamic_sort
|
81
SOURCES/glibc-rh2154914-2.patch
Normal file
81
SOURCES/glibc-rh2154914-2.patch
Normal file
@ -0,0 +1,81 @@
|
||||
Move _dl_dso_sort_algo out of _rtld_global_ro. It is only used
|
||||
locally in elf/dl-sort-maps.c. This avoids changing the internal
|
||||
_rtld_global_ro ABI.
|
||||
|
||||
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
|
||||
index 6f5c17b47b98fbc7..aeb79b40b45054c0 100644
|
||||
--- a/elf/dl-sort-maps.c
|
||||
+++ b/elf/dl-sort-maps.c
|
||||
@@ -290,12 +290,21 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
}
|
||||
}
|
||||
|
||||
+/* DSO sort algorithm to use. */
|
||||
+enum dso_sort_algorithm
|
||||
+ {
|
||||
+ dso_sort_algorithm_original,
|
||||
+ dso_sort_algorithm_dfs
|
||||
+ };
|
||||
+
|
||||
+static enum dso_sort_algorithm _dl_dso_sort_algo;
|
||||
+
|
||||
void
|
||||
_dl_sort_maps_init (void)
|
||||
{
|
||||
int32_t algorithm = TUNABLE_GET (glibc, rtld, dynamic_sort, int32_t, NULL);
|
||||
- GLRO(dl_dso_sort_algo) = algorithm == 1 ? dso_sort_algorithm_original
|
||||
- : dso_sort_algorithm_dfs;
|
||||
+ _dl_dso_sort_algo = (algorithm == 1 ? dso_sort_algorithm_original
|
||||
+ : dso_sort_algorithm_dfs);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -309,7 +318,7 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
PTR_MANGLE/DEMANGLE, further impairing performance of small, common
|
||||
input cases. A simple if-case with direct function calls appears to
|
||||
be the fastest. */
|
||||
- if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
|
||||
+ if (__glibc_likely (_dl_dso_sort_algo == dso_sort_algorithm_original))
|
||||
_dl_sort_maps_original (maps, nmaps, force_first, for_fini);
|
||||
else
|
||||
_dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
|
||||
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||||
index ae03aec9764e29d3..e9943e889ef447ad 100644
|
||||
--- a/elf/dl-support.c
|
||||
+++ b/elf/dl-support.c
|
||||
@@ -155,8 +155,6 @@ size_t _dl_phnum;
|
||||
uint64_t _dl_hwcap __attribute__ ((nocommon));
|
||||
uint64_t _dl_hwcap2 __attribute__ ((nocommon));
|
||||
|
||||
-enum dso_sort_algorithm _dl_dso_sort_algo;
|
||||
-
|
||||
/* The value of the FPU control word the kernel will preset in hardware. */
|
||||
fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
|
||||
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 2c1b4c47c6a6c643..29bbde3e83e37d7e 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -240,13 +240,6 @@ enum allowmask
|
||||
};
|
||||
|
||||
|
||||
-/* DSO sort algorithm to use (check dl-sort-maps.c). */
|
||||
-enum dso_sort_algorithm
|
||||
- {
|
||||
- dso_sort_algorithm_original,
|
||||
- dso_sort_algorithm_dfs
|
||||
- };
|
||||
-
|
||||
struct audit_ifaces
|
||||
{
|
||||
void (*activity) (uintptr_t *, unsigned int);
|
||||
@@ -640,8 +633,6 @@ struct rtld_global_ro
|
||||
platforms. */
|
||||
EXTERN uint64_t _dl_hwcap2;
|
||||
|
||||
- EXTERN enum dso_sort_algorithm _dl_dso_sort_algo;
|
||||
-
|
||||
#ifdef SHARED
|
||||
/* We add a function table to _rtld_global which is then used to
|
||||
call the function instead of going through the PLT. The result
|
@ -17,6 +17,8 @@
|
||||
set -evx
|
||||
|
||||
tar_tmp="$(mktemp)"
|
||||
declare -A libc_dlink_tmp_list
|
||||
ldso_annobin_sym_tmp_list=""
|
||||
|
||||
# Prefer a separately installed debugedit over the RPM-integrated one.
|
||||
if command -v debugedit >/dev/null ; then
|
||||
@ -26,7 +28,7 @@ else
|
||||
fi
|
||||
|
||||
cleanup () {
|
||||
rm -f "$tar_tmp"
|
||||
rm -f "$tar_tmp" ${libc_dlink_tmp_list[@]} $ldso_annobin_sym_tmp_list
|
||||
}
|
||||
trap cleanup 0
|
||||
|
||||
@ -51,6 +53,15 @@ full_list="$ldso_list $libc_list $libdl_list $libpthread_list $librt_list"
|
||||
# Run the debuginfo extraction.
|
||||
"$script_path" "$@"
|
||||
|
||||
# libc.so.6: Extract the .gnu_debuglink section
|
||||
for f in $libc_list
|
||||
do
|
||||
dlink_tmp="$(mktemp)"
|
||||
libc_dlink_tmp_list["$f"]="$dlink_tmp"
|
||||
objcopy -j.gnu_debuglink --set-section-flags .gnu_debuglink=alloc \
|
||||
-O binary "$sysroot_path/$f" "$dlink_tmp"
|
||||
done
|
||||
|
||||
# Restore the original files.
|
||||
(cd "$sysroot_path"; tar xf "$tar_tmp")
|
||||
(cd "$sysroot_path"; ls -l $full_list)
|
||||
@ -61,6 +72,20 @@ do
|
||||
objcopy --merge-notes "$sysroot_path/$p"
|
||||
done
|
||||
|
||||
# libc.so.6: Restore the .gnu_debuglink section
|
||||
for f in ${!libc_dlink_tmp_list[@]}
|
||||
do
|
||||
dlink_tmp="${libc_dlink_tmp_list[$f]}"
|
||||
objcopy --add-section .gnu_debuglink="$dlink_tmp" "$sysroot_path/$f"
|
||||
done
|
||||
|
||||
# ld.so does not have separated debuginfo and so the debuginfo file
|
||||
# generated by find-debuginfo is redundant. Therefore, remove it.
|
||||
for ldso_debug in `find "$sysroot_path" -name 'ld-*.so*.debug' -type f`
|
||||
do
|
||||
rm -f "$ldso_debug"
|
||||
done
|
||||
|
||||
# libc.so.6 and other shared objects: Reduce to valuable symbols.
|
||||
# Eliminate file symbols, annobin symbols, and symbols used by the
|
||||
# glibc build to implement hidden aliases (__EI_*). We would also
|
||||
@ -103,6 +128,14 @@ debug_base_name=${last_arg:-$RPM_BUILD_ROOT}
|
||||
for p in $ldso_list
|
||||
do
|
||||
$debugedit -b "$debug_base_name" -d "$debug_dest_name" -n "$sysroot_path/$p"
|
||||
|
||||
# Remove the .annobin* symbols (and only them).
|
||||
ldso_annobin_sym_tmp="$(mktemp)"
|
||||
ldso_annobin_sym_tmp_list+=" $ldso_annobin_sym_tmp"
|
||||
if nm --format=posix "$sysroot_path/$p" | cut -d' ' -f1 \
|
||||
| grep '^\.annobin' > "$ldso_annobin_sym_tmp"; then
|
||||
objcopy --strip-symbols="$ldso_annobin_sym_tmp" "$sysroot_path/$p"
|
||||
fi
|
||||
done
|
||||
|
||||
# Apply single-file DWARF optimization.
|
||||
|
111
SPECS/glibc.spec
111
SPECS/glibc.spec
@ -1,6 +1,6 @@
|
||||
%define glibcsrcdir glibc-2.28
|
||||
%define glibcversion 2.28
|
||||
%define glibcrelease 211%{?dist}
|
||||
%define glibcrelease 225%{?dist}
|
||||
# Pre-release tarballs are pulled in from git using a command that is
|
||||
# effectively:
|
||||
#
|
||||
@ -968,6 +968,69 @@ Patch775: glibc-rh2104907.patch
|
||||
Patch776: glibc-rh2119304-1.patch
|
||||
Patch777: glibc-rh2119304-2.patch
|
||||
Patch778: glibc-rh2119304-3.patch
|
||||
Patch779: glibc-rh2118667.patch
|
||||
Patch780: glibc-rh2122498.patch
|
||||
Patch781: glibc-rh2125222.patch
|
||||
Patch782: glibc-rh1871383-1.patch
|
||||
Patch783: glibc-rh1871383-2.patch
|
||||
Patch784: glibc-rh1871383-3.patch
|
||||
Patch785: glibc-rh1871383-4.patch
|
||||
Patch786: glibc-rh1871383-5.patch
|
||||
Patch787: glibc-rh1871383-6.patch
|
||||
Patch788: glibc-rh1871383-7.patch
|
||||
Patch789: glibc-rh2122501-1.patch
|
||||
Patch790: glibc-rh2122501-2.patch
|
||||
Patch791: glibc-rh2122501-3.patch
|
||||
Patch792: glibc-rh2122501-4.patch
|
||||
Patch793: glibc-rh2122501-5.patch
|
||||
Patch794: glibc-rh2121746-1.patch
|
||||
Patch795: glibc-rh2121746-2.patch
|
||||
Patch796: glibc-rh2116938.patch
|
||||
Patch797: glibc-rh2109510-1.patch
|
||||
Patch798: glibc-rh2109510-2.patch
|
||||
Patch799: glibc-rh2109510-3.patch
|
||||
Patch800: glibc-rh2109510-4.patch
|
||||
Patch801: glibc-rh2109510-5.patch
|
||||
Patch802: glibc-rh2109510-6.patch
|
||||
Patch803: glibc-rh2109510-7.patch
|
||||
Patch804: glibc-rh2109510-8.patch
|
||||
Patch805: glibc-rh2109510-9.patch
|
||||
Patch806: glibc-rh2109510-10.patch
|
||||
Patch807: glibc-rh2109510-11.patch
|
||||
Patch808: glibc-rh2109510-12.patch
|
||||
Patch809: glibc-rh2109510-13.patch
|
||||
Patch810: glibc-rh2109510-14.patch
|
||||
Patch811: glibc-rh2109510-15.patch
|
||||
Patch812: glibc-rh2109510-16.patch
|
||||
Patch813: glibc-rh2109510-17.patch
|
||||
Patch814: glibc-rh2109510-18.patch
|
||||
Patch815: glibc-rh2109510-19.patch
|
||||
Patch816: glibc-rh2109510-20.patch
|
||||
Patch817: glibc-rh2109510-21.patch
|
||||
Patch818: glibc-rh2109510-22.patch
|
||||
Patch819: glibc-rh2109510-23.patch
|
||||
Patch820: glibc-rh2139875-1.patch
|
||||
Patch821: glibc-rh2139875-2.patch
|
||||
Patch822: glibc-rh2139875-3.patch
|
||||
Patch823: glibc-rh1159809-1.patch
|
||||
Patch824: glibc-rh1159809-2.patch
|
||||
Patch825: glibc-rh1159809-3.patch
|
||||
Patch826: glibc-rh1159809-4.patch
|
||||
Patch827: glibc-rh1159809-5.patch
|
||||
Patch828: glibc-rh1159809-6.patch
|
||||
Patch829: glibc-rh1159809-7.patch
|
||||
Patch830: glibc-rh1159809-8.patch
|
||||
Patch831: glibc-rh1159809-9.patch
|
||||
Patch832: glibc-rh1159809-10.patch
|
||||
Patch833: glibc-rh1159809-11.patch
|
||||
Patch834: glibc-rh1159809-12.patch
|
||||
Patch835: glibc-rh2141989.patch
|
||||
Patch836: glibc-rh2142937-1.patch
|
||||
Patch837: glibc-rh2142937-2.patch
|
||||
Patch838: glibc-rh2142937-3.patch
|
||||
Patch839: glibc-rh2144568.patch
|
||||
Patch840: glibc-rh2154914-1.patch
|
||||
Patch841: glibc-rh2154914-2.patch
|
||||
|
||||
##############################################################################
|
||||
# Continued list of core "glibc" package information:
|
||||
@ -2798,6 +2861,52 @@ fi
|
||||
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
|
||||
|
||||
%changelog
|
||||
* Fri Jan 20 2023 Florian Weimer <fweimer@redhat.com> - 2.28-225
|
||||
- Enforce a specififc internal ordering for tunables (#2154914)
|
||||
|
||||
* Wed Nov 30 2022 Arjun Shankar <arjun@redhat.com> - 2.28-224
|
||||
- Fix rtld-audit trampoline for aarch64 (#2144568)
|
||||
|
||||
* Fri Nov 25 2022 Arjun Shankar <arjun@redhat.com> - 2.28-223
|
||||
- Backport upstream fixes to tst-pldd (#2142937)
|
||||
|
||||
* Tue Nov 22 2022 Florian Weimer <fweimer@redhat.com> - 2.28-222
|
||||
- Restore IPC_64 support in sysvipc *ctl functions (#2141989)
|
||||
|
||||
* Fri Nov 18 2022 Florian Weimer <fweimer@redhat.com> - 2.28-221
|
||||
- Switch to fast DSO dependency sorting algorithm (#1159809)
|
||||
|
||||
* Thu Nov 3 2022 Florian Weimer <fweimer@redhat.com> - 2.28-220
|
||||
- Explicitly switch to --with-default-link=no (#2109510)
|
||||
- Define MAP_SYNC on ppc64le (#2139875)
|
||||
|
||||
* Mon Oct 24 2022 Arjun Shankar <arjun@redhat.com> - 2.28-219
|
||||
- Fix -Wstrict-overflow warning when using CMSG_NXTHDR macro (#2116938)
|
||||
|
||||
* Fri Oct 14 2022 DJ Delorie <dj@redhat.com> - 2.28-218
|
||||
- Fix dlmopen/dlclose/dlmopen sequence and libc initialization (#2121746)
|
||||
|
||||
* Thu Oct 13 2022 Arjun Shankar <arjun@redhat.com> - 2.28-217
|
||||
- Fix memory corruption in printf with thousands separators and large
|
||||
integer width (#2122501)
|
||||
|
||||
* Wed Oct 05 2022 Arjun Shankar <arjun@redhat.com> - 2.28-216
|
||||
- Retain .gnu_debuglink section for libc.so.6 (#2115830)
|
||||
- Remove .annobin* symbols from ld.so
|
||||
- Remove redundant ld.so debuginfo file
|
||||
|
||||
* Wed Sep 28 2022 DJ Delorie <dj@redhat.com> - 2.28-215
|
||||
- Improve malloc implementation (#1871383)
|
||||
|
||||
* Tue Sep 20 2022 Florian Weimer <fweimer@redhat.com> - 2.28-214
|
||||
- Fix hwcaps search path size computation (#2125222)
|
||||
|
||||
* Tue Sep 20 2022 Florian Weimer <fweimer@redhat.com> - 2.28-213
|
||||
- Fix nscd netlink cache invalidation if epoll is used (#2122498)
|
||||
|
||||
* Tue Sep 20 2022 Florian Weimer <fweimer@redhat.com> - 2.28-212
|
||||
- Run tst-audit-tlsdesc, tst-audit-tlsdesc-dlopen everywhere (#2118667)
|
||||
|
||||
* Thu Aug 25 2022 Florian Weimer <fweimer@redhat.com> - 2.28-211
|
||||
- Preserve GLRO (dl_naudit) internal ABI (#2119304)
|
||||
- Avoid s390x ABI change due to z16 recognition on s390x (#2119304)
|
||||
|
Loading…
Reference in New Issue
Block a user