mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-10 05:59:39 +08:00
Compare commits
153
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a56c4ee4e | ||
|
|
1bc1832cfc | ||
|
|
8aef9e7a7a | ||
|
|
7b7a7a48dc | ||
|
|
6fa61e5997 | ||
|
|
5ad449c398 | ||
|
|
f80f3409e8 | ||
|
|
c18f8a69f7 | ||
|
|
4ab74e9ba7 | ||
|
|
3ed195a8ec | ||
|
|
be60218014 | ||
|
|
394eae3381 | ||
|
|
a77064893b | ||
|
|
682ad4c862 | ||
|
|
9d5c6d007e | ||
|
|
af3cbeec36 | ||
|
|
83cb4f5026 | ||
|
|
e059e458b8 | ||
|
|
ce9a4f6a3c | ||
|
|
bb36cb21ef | ||
|
|
196458764f | ||
|
|
2a4c4043d0 | ||
|
|
f55ba2fedc | ||
|
|
91680682e5 | ||
|
|
e213c2205e | ||
|
|
d30d8bb5ca | ||
|
|
405dd5b536 | ||
|
|
0dc9ac6d5c | ||
|
|
bd1ded3d05 | ||
|
|
077f1f78bb | ||
|
|
ed4ceabea1 | ||
|
|
05c2893095 | ||
|
|
b462b80b08 | ||
|
|
bf4a99baed | ||
|
|
0a888ff9bd | ||
|
|
0c9137a444 | ||
|
|
7a9e8a984a | ||
|
|
76e807f5f1 | ||
|
|
52d57fc76d | ||
|
|
b10d5e62a6 | ||
|
|
6fd634e9b9 | ||
|
|
1896ace580 | ||
|
|
cdf5ee727d | ||
|
|
aa510aa276 | ||
|
|
3299ce69c5 | ||
|
|
b2229db87d | ||
|
|
32022774db | ||
|
|
09c113cf00 | ||
|
|
f6f96a16e6 | ||
|
|
ede8acfdee | ||
|
|
51e00fc5aa | ||
|
|
6bbc1a3a35 | ||
|
|
f9e29095fc | ||
|
|
51b72ac04b | ||
|
|
6f8c9dc8bb | ||
|
|
443e146ce7 | ||
|
|
7bbad8e3cf | ||
|
|
720263fcb8 | ||
|
|
e6251366b6 | ||
|
|
0f8a239000 | ||
|
|
9d1cd8bd7a | ||
|
|
d528cb5165 | ||
|
|
b1fcaf14fe | ||
|
|
77317b3b0d | ||
|
|
f996f678b9 | ||
|
|
bee0b69a58 | ||
|
|
63c84a82a3 | ||
|
|
7dbd7af692 | ||
|
|
04b9cc156d | ||
|
|
ad711f9eee | ||
|
|
5d8687bfb7 | ||
|
|
f73bf74102 | ||
|
|
ae98c17a1d | ||
|
|
72c0787561 | ||
|
|
30b429c2bf | ||
|
|
ca7d6c8d7f | ||
|
|
33046deb96 | ||
|
|
e218418d49 | ||
|
|
05751d1c5c | ||
|
|
6479c904df | ||
|
|
f82385fcce | ||
|
|
90496a2f5d | ||
|
|
c42821ec05 | ||
|
|
2a7cef79d5 | ||
|
|
43e3ba09ec | ||
|
|
04e991f22e | ||
|
|
0b5c3ed5e3 | ||
|
|
6b5d4f31ed | ||
|
|
a1999f6ad9 | ||
|
|
3bb13e9149 | ||
|
|
40eebb02cc | ||
|
|
3a5f4c4010 | ||
|
|
5abb1c32c2 | ||
|
|
b923e061d4 | ||
|
|
a2539f5b1d | ||
|
|
53c8f3f125 | ||
|
|
1d40023939 | ||
|
|
d299f19889 | ||
|
|
5c77e0cca9 | ||
|
|
182ffd8e75 | ||
|
|
cc6ff883a6 | ||
|
|
75507b3337 | ||
|
|
76dfec9324 | ||
|
|
737efa27fc | ||
|
|
27e892f660 | ||
|
|
16949aeaa0 | ||
|
|
ff75390ef5 | ||
|
|
1799ac8eab | ||
|
|
b936cdc7f7 | ||
|
|
0e49f103ad | ||
|
|
36ae20e676 | ||
|
|
3c207c9c29 | ||
|
|
c511c9bd05 | ||
|
|
778b8d3786 | ||
|
|
44b3959329 | ||
|
|
1d45265691 | ||
|
|
760e1d2878 | ||
|
|
d3cb8f6222 | ||
|
|
082798622d | ||
|
|
33dc30bc83 | ||
|
|
46e1e64fe3 | ||
|
|
b6eae83717 | ||
|
|
c6090dcebd | ||
|
|
610e2c5150 | ||
|
|
4c619b3eed | ||
|
|
87450ecf8a | ||
|
|
2b4f67c2b3 | ||
|
|
1a24bbd43e | ||
|
|
0d9793e82a | ||
|
|
1d49bede4d | ||
|
|
050022910b | ||
|
|
ac0a6929c5 | ||
|
|
3ea24955bf | ||
|
|
5c36293f06 | ||
|
|
2dfa659a66 | ||
|
|
05c025abca | ||
|
|
f688bcd83d | ||
|
|
eba0ce6058 | ||
|
|
5337b2af4b | ||
|
|
c6e794640c | ||
|
|
70ee5e8b57 | ||
|
|
8813b2682e | ||
|
|
e61a8fd8fa | ||
|
|
0b9460d22e | ||
|
|
c4aeedea59 | ||
|
|
9b139b6b81 | ||
|
|
81c5484d93 | ||
|
|
0f8f0ed25c | ||
|
|
23482f7886 | ||
|
|
69beb5cbf8 | ||
|
|
fe62c4d173 | ||
|
|
386543bc44 | ||
|
|
cebc01cbfd |
+5
-2
@@ -557,9 +557,12 @@ link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link)
|
||||
# before the expansion of LDLIBS-* variables).
|
||||
|
||||
# Tests use -Wl,-rpath instead of -Wl,-rpath-link for
|
||||
# build-hardcoded-path-in-tests.
|
||||
# build-hardcoded-path-in-tests. Add -Wl,--disable-new-dtags to force
|
||||
# DT_RPATH instead of DT_RUNPATH which only applies to DT_NEEDED entries
|
||||
# in the executable and doesn't applies to DT_NEEDED entries in shared
|
||||
# libraries which are loaded via DT_NEEDED entries in the executable.
|
||||
ifeq (yes,$(build-hardcoded-path-in-tests))
|
||||
link-libc-tests-rpath-link = $(link-libc-rpath)
|
||||
link-libc-tests-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags
|
||||
else
|
||||
link-libc-tests-rpath-link = $(link-libc-rpath-link)
|
||||
endif # build-hardcoded-path-in-tests
|
||||
|
||||
@@ -4,6 +4,120 @@ See the end for copying conditions.
|
||||
|
||||
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
|
||||
using `glibc' in the "product" field.
|
||||
|
||||
Version 2.32.1
|
||||
|
||||
Security related changes:
|
||||
|
||||
CVE-2019-25013: A buffer overflow has been fixed in the iconv function when
|
||||
invoked with EUC-KR input containing invalid multibyte input sequences.
|
||||
|
||||
CVE-2020-29562: An assertion failure has been fixed in the iconv function
|
||||
when invoked with UCS4 input containing an invalid character.
|
||||
|
||||
CVE-2020-27618: An infinite loop has been fixed in the iconv program when
|
||||
invoked with input containing redundant shift sequences in the IBM1364,
|
||||
IBM1371, IBM1388, IBM1390, or IBM1399 character sets.
|
||||
|
||||
CVE-2021-3326: An assertion failure during conversion from the
|
||||
ISO-20220-JP-3 character set using the iconv function has been fixed.
|
||||
This assertion was triggered by certain valid inputs in which the
|
||||
converted output contains a combined sequence of two wide characters
|
||||
crossing a buffer boundary. Reported by Tavis Ormandy.
|
||||
|
||||
CVE-2021-27645: The nameserver caching daemon (nscd), when processing
|
||||
a request for netgroup lookup, may crash due to a double-free,
|
||||
potentially resulting in degraded service or Denial of Service on the
|
||||
local system. Reported by Chris Schanzle.
|
||||
|
||||
CVE-2021-33574: The mq_notify function has a potential use-after-free
|
||||
issue when using a notification type of SIGEV_THREAD and a thread
|
||||
attribute with a non-default affinity mask.
|
||||
|
||||
CVE-2021-35942: The wordexp function may overflow the positional
|
||||
parameter number when processing the expansion resulting in a crash.
|
||||
Reported by Philippe Antoine.
|
||||
|
||||
CVE-2022-23219: Passing an overlong file name to the clnt_create
|
||||
legacy function could result in a stack-based buffer overflow when
|
||||
using the "unix" protocol. Reported by Martin Sebor.
|
||||
|
||||
CVE-2022-23218: Passing an overlong file name to the svcunix_create
|
||||
legacy function could result in a stack-based buffer overflow.
|
||||
|
||||
GLIBC-SA-2026-0003: wordexp with WRDE_REUSE and WRDE_APPEND may return
|
||||
uninitialized memory (CVE-2025-15281).
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[20019] NULL pointer dereference in libc.so.6 IFUNC due to uninitialized GOT
|
||||
[22542] CVE-2022-23219: Buffer overflow in sunrpc clnt_create for "unix"
|
||||
[24973] locale: iconv encounters segmentation fault when converting
|
||||
0x00 0xfe in EUC-KR to UTF-8 (CVE-2019-25013)
|
||||
[25399] string: undefined reference to `__warn_memset_zero_len' when
|
||||
changing gnuc version
|
||||
[26224] iconv hangs when converting some invalid inputs from several IBM
|
||||
character sets (CVE-2020-27618)
|
||||
[26383] locale: bind_textdomain_codeset doesn't accept //TRANSLIT
|
||||
anymore
|
||||
[26534] libm.so 2.32 SIGILL in pow() due to FMA4 instruction on non-FMA4
|
||||
system
|
||||
[26555] string: strerrorname_np does not return the documented value
|
||||
[26600] Transaction ID collisions cause slow DNS lookups in getaddrinfo
|
||||
[26636] libc: 32-bit shmctl(IPC_INFO) crashes when shminfo struct is
|
||||
at the end of a memory mapping
|
||||
[26637] libc: semctl SEM_STAT_ANY fails to pass the buffer specified
|
||||
by the caller to the kernel
|
||||
[26639] libc: msgctl IPC_INFO and MSG_INFO return garbage
|
||||
[26690] stdio: Aliasing violation in __vfscanf_internal
|
||||
[26798] dynamic-link: aarch64: variant PCS symbols may be incorrectly
|
||||
lazy bound
|
||||
[26831] aarch64: seccomp filters may prevent mprotect(PROT_EXEC|PROT_BTI)
|
||||
[26853] aarch64: Missing unwind information in statically linked startup code
|
||||
[26923] Assertion failure in iconv when converting invalid UCS4 (CVE-2020-29562)
|
||||
[26926] dynamic-link: aarch64: library dependencies are not bti
|
||||
protected
|
||||
[26932] libc: sh: Multiple floating point functions defined as stubs only
|
||||
[26988] dynamic-link: aarch64: BTI mprotect address is not page
|
||||
aligned
|
||||
[27024] Wrong access (read_only, 3, 4) attribute for readlinkat
|
||||
[27068] Static PIE binaries SIGILL when BTI is enabled on aarch64
|
||||
[27130] "rep movsb" performance issue
|
||||
[27177] GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on doesn't work
|
||||
[27256] locale: Assertion failure in ISO-2022-JP-3 gconv module
|
||||
related to combining characters (CVE-2021-3326)
|
||||
[27398] x86: Improve testing false positive for tst-cpu-features-cpuinfo with
|
||||
bad hardware
|
||||
[27457] vzeroupper use in AVX2 multiarch string functions cause HTM aborts
|
||||
[27462] nscd: double-free in nscd (CVE-2021-27645)
|
||||
[27471] GLIBC_TUNABLES aren't parsed properly in AT_SECURE binaries
|
||||
[27476] getcwd(NULL, PATH_MAX) generates warnings on -Wnonnull
|
||||
[27511] libc: S390 memmove assumes Vector Facility when MIE Facility 3
|
||||
is present
|
||||
[27609] dynamic-link: [2.32/2.33/2.34 Regression] In elf/dl-open.c
|
||||
(_dl_open) we might use __LM_ID_CALLER to index GL(dl_ns)[]
|
||||
[27655] string: Wrong size calculation in string/test-strnlen.c
|
||||
[27896] nptl: mq_notify does not handle separately allocated thread
|
||||
attributes (CVE-2021-33574)
|
||||
[27974] Overflow bug in some implementation of wcsnlen, wmemchr, and wcsncat
|
||||
[28011] libc: Wild read in wordexp (parse_param) (CVE-2021-35942)
|
||||
[28033] libc: Need to check RTM_ALWAYS_ABORT for RTM
|
||||
[28064] string: x86_64:wcslen implementation list has wcsnlen
|
||||
[28213] librt: NULL pointer dereference in mq_notify (CVE-2021-38604)
|
||||
[28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs
|
||||
[28607] Masked signals are delivered on thread exit
|
||||
[28755] overflow bug in wcsncmp_avx2 and wcsncmp_evex
|
||||
[28768] CVE-2022-23218: Buffer overflow in sunrpc svcunix_create
|
||||
[28896] strncmp-avx2-rtm and wcsncmp-avx2-rtm fallback on non-rtm
|
||||
variants when avoiding overflow
|
||||
[29304] libc: mq_timedreceive does not handle 64 bit syscall return
|
||||
correct for !__ASSUME_TIME64_SYSCALLS
|
||||
[29528] elf: Call __libc_early_init for reused namespaces
|
||||
[29611] Optimized AVX2 string functions unconditionally use BMI2 instructions
|
||||
[33185] Fix double-free after allocation failure in regcomp
|
||||
[33814] glob: wordexp with WRDE_REUSE and WRDE_APPEND may return
|
||||
uninitialized memory
|
||||
|
||||
|
||||
Version 2.32
|
||||
|
||||
@@ -23,14 +137,14 @@ Major new features:
|
||||
- arc-linux-gnuhf
|
||||
- arceb-linux-gnu
|
||||
|
||||
The arc* ABI is little-endian while arceb is big-endian. All ABIs use
|
||||
The arc* ABIs are little-endian while arceb is big-endian. All ABIs use
|
||||
64-bit time (y2038 safe) and 64-bit file offsets (LFS default).
|
||||
|
||||
* The GNU C Library now loads audit modules listed in the DT_AUDIT and
|
||||
DT_DEPAUDIT dynamic section entries of the main executable.
|
||||
|
||||
* powerpc64le supports IEEE128 long double libm/libc redirects when
|
||||
using the -mabi=ieeelongdouble to compile C code on supported GCC
|
||||
using -mabi=ieeelongdouble to compile C code on supported GCC
|
||||
toolchains. It is recommended to use GCC 8 or newer when testing
|
||||
this option.
|
||||
|
||||
@@ -38,7 +152,7 @@ Major new features:
|
||||
several APIs have been annotated with GCC 'access' attribute. This
|
||||
should help GCC 10 issue better warnings.
|
||||
|
||||
* On Linux, functions the pthread_attr_setsigmask_np and
|
||||
* On Linux, functions pthread_attr_setsigmask_np and
|
||||
pthread_attr_getsigmask_np have been added. They allow applications
|
||||
to specify the signal mask of a thread created with pthread_create.
|
||||
|
||||
@@ -49,9 +163,9 @@ Major new features:
|
||||
libpthread.
|
||||
|
||||
* The functions sigabbrev_np and sigdescr_np have been added. The
|
||||
sigabbrev_np returns the abbreviated signal name (e.g. "HUP" for SIGHUP)
|
||||
while sigdescr_np returns a string describing the signal number (e.g
|
||||
"Hangup" for SIGHUP). Different than strsignal, sigdescr_np does not
|
||||
sigabbrev_np function returns the abbreviated signal name (e.g. "HUP" for
|
||||
SIGHUP) while sigdescr_np returns a string describing the signal number
|
||||
(e.g "Hangup" for SIGHUP). Different than strsignal, sigdescr_np does not
|
||||
attempt to translate the return description, both functions return
|
||||
NULL for an invalid signal number.
|
||||
|
||||
@@ -59,8 +173,8 @@ Major new features:
|
||||
are both thread and async-signal safe. These functions are GNU extensions.
|
||||
|
||||
* The functions strerrorname_np and strerrordesc_np have been added. The
|
||||
strerroname_np returns error number name (e.g. "EINVAL" for EINVAL) while
|
||||
strerrordesc_np returns string describing error number
|
||||
strerroname_np function returns error number name (e.g. "EINVAL" for EINVAL)
|
||||
while strerrordesc_np returns a string describing the error number
|
||||
(e.g "Invalid argument" for EINVAL). Different than strerror,
|
||||
strerrordesc_np does not attempt to translate the return description, both
|
||||
functions return NULL for an invalid error number.
|
||||
@@ -98,7 +212,7 @@ Deprecated and removed features, and other changes affecting compatibility:
|
||||
that have been added in or before version 2.28. Replacement
|
||||
implementations based on TI-RPC, which additionally support IPv6, are
|
||||
available from <https://github.com/thkukuk/>. This change does not
|
||||
affect the "compat" NSS module, which does not depended on libnsl
|
||||
affect the "compat" NSS module, which does not depend on libnsl
|
||||
since 2.27 and thus can be used without NIS.
|
||||
|
||||
* The deprecated <sys/sysctl.h> header and the sysctl function have been
|
||||
@@ -127,7 +241,7 @@ Deprecated and removed features, and other changes affecting compatibility:
|
||||
|
||||
* The deprecated symbols sys_errlist, _sys_errlist, sys_nerr, and _sys_nerr
|
||||
are no longer available to newly linked binaries, and their declarations
|
||||
have been removed from from <stdio.h>. They are exported solely as
|
||||
have been removed from <stdio.h>. They are exported solely as
|
||||
compatibility symbols to support old binaries. All programs should use
|
||||
strerror or strerror_r instead.
|
||||
|
||||
@@ -669,7 +783,7 @@ The following bugs are resolved with this release:
|
||||
[24040] libc: riscv64: unterminated call chain in __thread_start
|
||||
[24047] network: libresolv should use IP_RECVERR/IPV6_RECVERR to avoid
|
||||
long timeouts
|
||||
[24051] stdio: puts and putchar ouput to _IO_stdout instead of stdout
|
||||
[24051] stdio: puts and putchar output to _IO_stdout instead of stdout
|
||||
[24059] nss: nss_files: get_next_alias calls fgets_unlocked without
|
||||
checking for NULL.
|
||||
[24114] regex: regexec buffer read overrun in "grep -i
|
||||
@@ -1847,7 +1961,7 @@ The following bugs are resolved with this release:
|
||||
[22111] malloc: malloc: per thread cache is not returned when thread exits
|
||||
[22112] localedata: Fix LC_TELEPHONE/LC_NAME for az_AZ
|
||||
[22134] libc: [linux] implement fexecve with execveat
|
||||
[22142] libc: [powerpc] printf oupts a wrong value of DBL_MAX on ppc64 and
|
||||
[22142] libc: [powerpc] printf outputs a wrong value of DBL_MAX on ppc64 and
|
||||
ppc64le
|
||||
[22145] libc: ttyname() gives up too early in the face of namespaces
|
||||
[22146] math: C++ build issue with float128 on x86_64
|
||||
@@ -2630,7 +2744,7 @@ Security related changes:
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[4099] stdio: Overly agressive caching by stream i/o functions.
|
||||
[4099] stdio: Overly aggressive caching by stream i/o functions.
|
||||
[7065] build: Support building glibc with -fstack-protector or -fstack-
|
||||
protector-all
|
||||
[9842] localedata: en_CA: incorrect date format
|
||||
|
||||
@@ -155,6 +155,7 @@ xtests: tests $(xtests-special)
|
||||
else
|
||||
tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \
|
||||
$(tests-container:%=$(objpfx)%.out) \
|
||||
$(tests-mcheck:%=$(objpfx)%-mcheck.out) \
|
||||
$(tests-special) $(tests-printers-out)
|
||||
xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special)
|
||||
endif
|
||||
@@ -165,7 +166,7 @@ ifeq ($(run-built-tests),no)
|
||||
tests-expected =
|
||||
else
|
||||
tests-expected = $(tests) $(tests-internal) $(tests-printers) \
|
||||
$(tests-container)
|
||||
$(tests-container) $(tests-mcheck:%=%-mcheck)
|
||||
endif
|
||||
tests:
|
||||
$(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
|
||||
@@ -191,6 +192,7 @@ else
|
||||
binaries-pie-tests =
|
||||
binaries-pie-notests =
|
||||
endif
|
||||
binaries-mcheck-tests = $(tests-mcheck:%=%-mcheck)
|
||||
else
|
||||
binaries-all-notests =
|
||||
binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs)
|
||||
@@ -200,6 +202,7 @@ binaries-static-tests =
|
||||
binaries-static =
|
||||
binaries-pie-tests =
|
||||
binaries-pie-notests =
|
||||
binaries-mcheck-tests =
|
||||
endif
|
||||
|
||||
binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests)
|
||||
@@ -223,6 +226,14 @@ $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \
|
||||
$(+link-tests)
|
||||
endif
|
||||
|
||||
ifneq "$(strip $(binaries-mcheck-tests))" ""
|
||||
$(addprefix $(objpfx),$(binaries-mcheck-tests)): %-mcheck: %.o \
|
||||
$(link-extra-libs-tests) \
|
||||
$(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
|
||||
$(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
|
||||
$(+link-tests)
|
||||
endif
|
||||
|
||||
ifneq "$(strip $(binaries-pie-tests))" ""
|
||||
$(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \
|
||||
$(link-extra-libs-tests) \
|
||||
@@ -253,6 +264,12 @@ $(addprefix $(objpfx),$(binaries-static-tests)): %: %.o \
|
||||
$(+link-static-tests)
|
||||
endif
|
||||
|
||||
# All mcheck tests will be run with MALLOC_CHECK_=3
|
||||
define mcheck-ENVS
|
||||
$(1)-mcheck-ENV = MALLOC_CHECK_=3
|
||||
endef
|
||||
$(foreach t,$(tests-mcheck),$(eval $(call mcheck-ENVS,$(t))))
|
||||
|
||||
ifneq "$(strip $(tests) $(tests-internal) $(xtests) $(test-srcs))" ""
|
||||
# These are the implicit rules for making test outputs
|
||||
# from the test programs and whatever input files are present.
|
||||
|
||||
+3
-1
@@ -51,7 +51,7 @@ routines = backtrace backtracesyms backtracesymsfd noophooks \
|
||||
explicit_bzero_chk \
|
||||
stack_chk_fail fortify_fail \
|
||||
$(static-only-routines)
|
||||
static-only-routines := warning-nop stack_chk_fail_local
|
||||
static-only-routines := stack_chk_fail_local
|
||||
|
||||
# Don't add stack_chk_fail_local.o to libc.a since __stack_chk_fail_local
|
||||
# is an alias of __stack_chk_fail in stack_chk_fail.o.
|
||||
@@ -168,6 +168,8 @@ extra-libs-others = $(extra-libs)
|
||||
|
||||
libSegFault-routines = segfault
|
||||
libSegFault-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
# libSegFault.so installs a signal handler in its ELF constructor.
|
||||
LDFLAGS-SegFault.so = -Wl,--enable-new-dtags,-z,nodelete
|
||||
|
||||
libpcprofile-routines = pcprofile
|
||||
libpcprofile-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/* Dummy nop functions to elicit link-time warnings.
|
||||
Copyright (C) 2005-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.
|
||||
|
||||
In addition to the permissions in the GNU Lesser General Public
|
||||
License, the Free Software Foundation gives you unlimited
|
||||
permission to link the compiled version of this file with other
|
||||
programs, and to distribute those programs without any restriction
|
||||
coming from the use of this file. (The GNU Lesser General Public
|
||||
License restrictions do apply in other respects; for example, they
|
||||
cover modification of the file, and distribution when not linked
|
||||
into another program.)
|
||||
|
||||
Note that people who make modified versions of this file are not
|
||||
obligated to grant this special exception for their modified
|
||||
versions; it is their choice whether to do so. The GNU Lesser
|
||||
General Public License gives permission to release a modified
|
||||
version without this exception; this exception also makes it
|
||||
possible to release a modified version which carries forward this
|
||||
exception.
|
||||
|
||||
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/cdefs.h>
|
||||
|
||||
static void
|
||||
__attribute__ ((used))
|
||||
nop (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Don't insert any other #include's before this #undef! */
|
||||
|
||||
#undef __warndecl
|
||||
#define __warndecl(name, msg) \
|
||||
extern void name (void) __attribute__ ((alias ("nop"))) attribute_hidden; \
|
||||
link_warning (name, msg)
|
||||
|
||||
#undef __USE_FORTIFY_LEVEL
|
||||
#define __USE_FORTIFY_LEVEL 99
|
||||
|
||||
/* Following here we need an #include for each public header file
|
||||
that uses __warndecl. */
|
||||
|
||||
/* Define away to avoid warnings with compilers that do not have these
|
||||
builtins. */
|
||||
#define __builtin___memcpy_chk(dest, src, len, bos) NULL
|
||||
#define __builtin___memmove_chk(dest, src, len, bos) NULL
|
||||
#define __builtin___mempcpy_chk(dest, src, len, bos) NULL
|
||||
#define __builtin___memset_chk(dest, ch, len, bos) NULL
|
||||
#define __builtin___stpcpy_chk(dest, src, bos) NULL
|
||||
#define __builtin___strcat_chk(dest, src, bos) NULL
|
||||
#define __builtin___strcpy_chk(dest, src, bos) NULL
|
||||
#define __builtin___strncat_chk(dest, src, len, bos) NULL
|
||||
#define __builtin___strncpy_chk(dest, src, len, bos) NULL
|
||||
#define __builtin_object_size(bos, level) 0
|
||||
|
||||
#include <string.h>
|
||||
+10
-4
@@ -210,7 +210,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \
|
||||
tst-audit14 tst-audit15 tst-audit16 \
|
||||
tst-single_threaded tst-single_threaded-pthread \
|
||||
tst-tls-ie tst-tls-ie-dlmopen
|
||||
tst-tls-ie tst-tls-ie-dlmopen tst-dlmopen-twice
|
||||
# reldep9
|
||||
tests-internal += loadtest unload unload2 circleload1 \
|
||||
neededtest neededtest2 neededtest3 neededtest4 \
|
||||
@@ -328,7 +328,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
tst-single_threaded-mod3 tst-single_threaded-mod4 \
|
||||
tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \
|
||||
tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 \
|
||||
tst-tls-ie-mod6
|
||||
tst-tls-ie-mod6 \
|
||||
tst-dlmopen-twice-mod1 tst-dlmopen-twice-mod2 \
|
||||
|
||||
# Most modules build with _ISOMAC defined, but those filtered out
|
||||
# depend on internal headers.
|
||||
@@ -1381,6 +1382,8 @@ CFLAGS-ifuncmain7pie.c += $(pie-ccflag)
|
||||
CFLAGS-ifuncmain9pie.c += $(pie-ccflag)
|
||||
CFLAGS-tst-ifunc-textrel.c += $(pic-ccflag)
|
||||
|
||||
LDFLAGS-ifuncmain6pie = -Wl,-z,lazy
|
||||
|
||||
$(objpfx)ifuncmain1pie: $(objpfx)ifuncmod1.so
|
||||
$(objpfx)ifuncmain1staticpie: $(objpfx)ifuncdep1pic.o
|
||||
$(objpfx)ifuncmain1vispie: $(objpfx)ifuncmod1.so
|
||||
@@ -1630,8 +1633,6 @@ $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \
|
||||
|
||||
tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
|
||||
LD_HWCAP_MASK=0x1
|
||||
tst-env-setuid-tunables-ENV = \
|
||||
GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
|
||||
|
||||
$(objpfx)tst-debug1: $(libdl)
|
||||
$(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so
|
||||
@@ -1796,3 +1797,8 @@ $(objpfx)tst-tls-ie-dlmopen.out: \
|
||||
$(objpfx)tst-tls-ie-mod6.so
|
||||
|
||||
$(objpfx)tst-tls-surplus: $(libdl)
|
||||
|
||||
$(objpfx)tst-dlmopen-twice: $(libdl)
|
||||
$(objpfx)tst-dlmopen-twice.out: \
|
||||
$(objpfx)tst-dlmopen-twice-mod1.so \
|
||||
$(objpfx)tst-dlmopen-twice-mod2.so
|
||||
|
||||
+20
-18
@@ -855,10 +855,12 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
|
||||
|
||||
/* Process PT_GNU_PROPERTY program header PH in module L after
|
||||
PT_LOAD segments are mapped. Only one NT_GNU_PROPERTY_TYPE_0
|
||||
note is handled which contains processor specific properties. */
|
||||
note is handled which contains processor specific properties.
|
||||
FD is -1 for the kernel mapped main executable otherwise it is
|
||||
the fd used for loading module L. */
|
||||
|
||||
void
|
||||
_dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph)
|
||||
_dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph)
|
||||
{
|
||||
const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
|
||||
const ElfW(Addr) size = ph->p_memsz;
|
||||
@@ -905,7 +907,7 @@ _dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph)
|
||||
last_type = type;
|
||||
|
||||
/* Target specific property processing. */
|
||||
if (_dl_process_gnu_property (l, type, datasz, ptr) == 0)
|
||||
if (_dl_process_gnu_property (l, fd, type, datasz, ptr) == 0)
|
||||
return;
|
||||
|
||||
/* Check the next property item. */
|
||||
@@ -1251,21 +1253,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
maplength, has_holes, loader);
|
||||
if (__glibc_unlikely (errstring != NULL))
|
||||
goto call_lose;
|
||||
|
||||
/* Process program headers again after load segments are mapped in
|
||||
case processing requires accessing those segments. Scan program
|
||||
headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY
|
||||
exits. */
|
||||
for (ph = &phdr[l->l_phnum]; ph != phdr; --ph)
|
||||
switch (ph[-1].p_type)
|
||||
{
|
||||
case PT_NOTE:
|
||||
_dl_process_pt_note (l, &ph[-1]);
|
||||
break;
|
||||
case PT_GNU_PROPERTY:
|
||||
_dl_process_pt_gnu_property (l, &ph[-1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (l->l_ld == 0)
|
||||
@@ -1377,6 +1364,21 @@ cannot enable executable stack as shared object requires");
|
||||
if (l->l_tls_initimage != NULL)
|
||||
l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
|
||||
|
||||
/* Process program headers again after load segments are mapped in
|
||||
case processing requires accessing those segments. Scan program
|
||||
headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY
|
||||
exits. */
|
||||
for (ph = &l->l_phdr[l->l_phnum]; ph != l->l_phdr; --ph)
|
||||
switch (ph[-1].p_type)
|
||||
{
|
||||
case PT_NOTE:
|
||||
_dl_process_pt_note (l, fd, &ph[-1]);
|
||||
break;
|
||||
case PT_GNU_PROPERTY:
|
||||
_dl_process_pt_gnu_property (l, fd, &ph[-1]);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We are done mapping in the file. We no longer need the descriptor. */
|
||||
if (__glibc_unlikely (__close_nocancel (fd) != 0))
|
||||
{
|
||||
|
||||
+9
-6
@@ -825,11 +825,14 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
|
||||
_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;
|
||||
}
|
||||
@@ -887,7 +890,7 @@ no more namespaces available for dlmopen()"));
|
||||
/* Avoid keeping around a dangling reference to the libc.so link
|
||||
map in case it has been cached in libc_map. */
|
||||
if (!args.libc_already_loaded)
|
||||
GL(dl_ns)[nsid].libc_map = NULL;
|
||||
GL(dl_ns)[args.nsid].libc_map = NULL;
|
||||
|
||||
/* Remove the object from memory. It may be in an inconsistent
|
||||
state if relocation failed, for example. */
|
||||
|
||||
+26
-30
@@ -177,6 +177,7 @@ parse_tunables (char *tunestr, char *valstring)
|
||||
return;
|
||||
|
||||
char *p = tunestr;
|
||||
size_t off = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -190,7 +191,11 @@ parse_tunables (char *tunestr, char *valstring)
|
||||
/* If we reach the end of the string before getting a valid name-value
|
||||
pair, bail out. */
|
||||
if (p[len] == '\0')
|
||||
return;
|
||||
{
|
||||
if (__libc_enable_secure)
|
||||
tunestr[off] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
/* We did not find a valid name-value pair before encountering the
|
||||
colon. */
|
||||
@@ -216,35 +221,28 @@ parse_tunables (char *tunestr, char *valstring)
|
||||
|
||||
if (tunable_is_name (cur->name, name))
|
||||
{
|
||||
/* If we are in a secure context (AT_SECURE) then ignore the tunable
|
||||
unless it is explicitly marked as secure. Tunable values take
|
||||
precedence over their envvar aliases. */
|
||||
/* If we are in a secure context (AT_SECURE) then ignore the
|
||||
tunable unless it is explicitly marked as secure. Tunable
|
||||
values take precedence over their envvar aliases. We write
|
||||
the tunables that are not SXID_ERASE back to TUNESTR, thus
|
||||
dropping all SXID_ERASE tunables and any invalid or
|
||||
unrecognized tunables. */
|
||||
if (__libc_enable_secure)
|
||||
{
|
||||
if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
|
||||
if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
|
||||
{
|
||||
if (p[len] == '\0')
|
||||
{
|
||||
/* Last tunable in the valstring. Null-terminate and
|
||||
return. */
|
||||
*name = '\0';
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove the current tunable from the string. We do
|
||||
this by overwriting the string starting from NAME
|
||||
(which is where the current tunable begins) with
|
||||
the remainder of the string. We then have P point
|
||||
to NAME so that we continue in the correct
|
||||
position in the valstring. */
|
||||
char *q = &p[len + 1];
|
||||
p = name;
|
||||
while (*q != '\0')
|
||||
*name++ = *q++;
|
||||
name[0] = '\0';
|
||||
len = 0;
|
||||
}
|
||||
if (off > 0)
|
||||
tunestr[off++] = ':';
|
||||
|
||||
const char *n = cur->name;
|
||||
|
||||
while (*n != '\0')
|
||||
tunestr[off++] = *n++;
|
||||
|
||||
tunestr[off++] = '=';
|
||||
|
||||
for (size_t j = 0; j < len; j++)
|
||||
tunestr[off++] = value[j];
|
||||
}
|
||||
|
||||
if (cur->security_level != TUNABLE_SECLEVEL_NONE)
|
||||
@@ -257,9 +255,7 @@ parse_tunables (char *tunestr, char *valstring)
|
||||
}
|
||||
}
|
||||
|
||||
if (p[len] == '\0')
|
||||
return;
|
||||
else
|
||||
if (p[len] != '\0')
|
||||
p += len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,14 @@ typedef int (*foo_p) (void);
|
||||
#endif
|
||||
|
||||
foo_p foo_ptr = foo;
|
||||
|
||||
/* Address-significant access to protected symbols is not supported in
|
||||
position-dependent mode on several architectures because GCC
|
||||
generates relocations that assume that the address is local to the
|
||||
main program. */
|
||||
#ifdef __PIE__
|
||||
foo_p foo_procted_ptr = foo_protected;
|
||||
#endif
|
||||
|
||||
extern foo_p get_foo_p (void);
|
||||
extern foo_p get_foo_hidden_p (void);
|
||||
@@ -37,12 +44,16 @@ main (void)
|
||||
if ((*foo_ptr) () != -1)
|
||||
abort ();
|
||||
|
||||
#ifdef __PIE__
|
||||
if (foo_procted_ptr != foo_protected)
|
||||
abort ();
|
||||
#endif
|
||||
if (foo_protected () != 0)
|
||||
abort ();
|
||||
#ifdef __PIE__
|
||||
if ((*foo_procted_ptr) () != 0)
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
p = get_foo_p ();
|
||||
if (p != foo)
|
||||
@@ -55,8 +66,10 @@ main (void)
|
||||
abort ();
|
||||
|
||||
p = get_foo_protected_p ();
|
||||
#ifdef __PIE__
|
||||
if (p != foo_protected)
|
||||
abort ();
|
||||
#endif
|
||||
if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
|
||||
abort ();
|
||||
|
||||
|
||||
@@ -14,12 +14,19 @@ get_foo (void)
|
||||
return foo;
|
||||
}
|
||||
|
||||
|
||||
/* Address-significant access to protected symbols is not supported in
|
||||
position-dependent mode on several architectures because GCC
|
||||
generates relocations that assume that the address is local to the
|
||||
main program. */
|
||||
#ifdef __PIE__
|
||||
foo_p
|
||||
__attribute__ ((noinline))
|
||||
get_foo_protected (void)
|
||||
{
|
||||
return foo_protected;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main (void)
|
||||
@@ -30,9 +37,11 @@ main (void)
|
||||
if ((*p) () != -1)
|
||||
abort ();
|
||||
|
||||
#ifdef __PIE__
|
||||
p = get_foo_protected ();
|
||||
if ((*p) () != 0)
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+3
-11
@@ -9,7 +9,6 @@
|
||||
#include "ifunc-sel.h"
|
||||
|
||||
typedef int (*foo_p) (void);
|
||||
extern foo_p foo_ptr;
|
||||
|
||||
static int
|
||||
one (void)
|
||||
@@ -28,20 +27,17 @@ foo_ifunc (void)
|
||||
}
|
||||
|
||||
extern int foo (void);
|
||||
extern foo_p get_foo (void);
|
||||
extern int call_foo (void);
|
||||
extern foo_p get_foo_p (void);
|
||||
|
||||
foo_p my_foo_ptr = foo;
|
||||
foo_p foo_ptr = foo;
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
foo_p p;
|
||||
|
||||
p = get_foo ();
|
||||
if (p != foo)
|
||||
abort ();
|
||||
if ((*p) () != -30)
|
||||
if (call_foo () != -30)
|
||||
abort ();
|
||||
|
||||
p = get_foo_p ();
|
||||
@@ -52,12 +48,8 @@ main (void)
|
||||
|
||||
if (foo_ptr != foo)
|
||||
abort ();
|
||||
if (my_foo_ptr != foo)
|
||||
abort ();
|
||||
if ((*foo_ptr) () != -30)
|
||||
abort ();
|
||||
if ((*my_foo_ptr) () != -30)
|
||||
abort ();
|
||||
if (foo () != -30)
|
||||
abort ();
|
||||
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@ extern int foo (void);
|
||||
|
||||
typedef int (*foo_p) (void);
|
||||
|
||||
foo_p foo_ptr = foo;
|
||||
extern foo_p foo_ptr;
|
||||
|
||||
foo_p
|
||||
get_foo_p (void)
|
||||
@@ -12,8 +12,8 @@ get_foo_p (void)
|
||||
return foo_ptr;
|
||||
}
|
||||
|
||||
foo_p
|
||||
get_foo (void)
|
||||
int
|
||||
call_foo (void)
|
||||
{
|
||||
return foo;
|
||||
return foo ();
|
||||
}
|
||||
|
||||
+2
-2
@@ -1534,10 +1534,10 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
switch (ph[-1].p_type)
|
||||
{
|
||||
case PT_NOTE:
|
||||
_dl_process_pt_note (main_map, &ph[-1]);
|
||||
_dl_process_pt_note (main_map, -1, &ph[-1]);
|
||||
break;
|
||||
case PT_GNU_PROPERTY:
|
||||
_dl_process_pt_gnu_property (main_map, &ph[-1]);
|
||||
_dl_process_pt_gnu_property (main_map, -1, &ph[-1]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -25,35 +25,76 @@
|
||||
#include "config.h"
|
||||
#undef _LIBC
|
||||
|
||||
#define test_parent test_parent_tunables
|
||||
#define test_child test_child_tunables
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <intprops.h>
|
||||
#include <array_length.h>
|
||||
|
||||
static int test_child_tunables (void);
|
||||
static int test_parent_tunables (void);
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
|
||||
#include "tst-env-setuid.c"
|
||||
const char *teststrings[] =
|
||||
{
|
||||
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2",
|
||||
"glibc.malloc.perturb=0x800",
|
||||
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
|
||||
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
|
||||
":glibc.malloc.garbage=2:glibc.malloc.check=1",
|
||||
"glibc.malloc.check=1:glibc.malloc.check=2",
|
||||
"not_valid.malloc.check=2",
|
||||
"glibc.not_valid.check=2",
|
||||
};
|
||||
|
||||
#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096"
|
||||
#define PARENT_VALSTRING_VALUE \
|
||||
"glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096"
|
||||
const char *resultstrings[] =
|
||||
{
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.perturb=0x800",
|
||||
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"glibc.malloc.mmap_threshold=4096",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
};
|
||||
|
||||
static int
|
||||
test_child_tunables (void)
|
||||
test_child (int off)
|
||||
{
|
||||
const char *val = getenv ("GLIBC_TUNABLES");
|
||||
|
||||
#if HAVE_TUNABLES
|
||||
if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0)
|
||||
if (val != NULL && strcmp (val, resultstrings[off]) == 0)
|
||||
return 0;
|
||||
|
||||
if (val != NULL)
|
||||
printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
|
||||
printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
|
||||
|
||||
return 1;
|
||||
#else
|
||||
if (val != NULL)
|
||||
{
|
||||
printf ("GLIBC_TUNABLES not cleared\n");
|
||||
printf ("[%d] GLIBC_TUNABLES not cleared\n", off);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -61,15 +102,48 @@ test_child_tunables (void)
|
||||
}
|
||||
|
||||
static int
|
||||
test_parent_tunables (void)
|
||||
do_test (int argc, char **argv)
|
||||
{
|
||||
const char *val = getenv ("GLIBC_TUNABLES");
|
||||
/* Setgid child process. */
|
||||
if (argc == 2)
|
||||
{
|
||||
if (getgid () == getegid ())
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
|
||||
if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0)
|
||||
return 0;
|
||||
int ret = test_child (atoi (argv[1]));
|
||||
|
||||
if (val != NULL)
|
||||
printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
|
||||
if (ret != 0)
|
||||
exit (1);
|
||||
|
||||
return 1;
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Spawn tests. */
|
||||
for (int i = 0; i < array_length (teststrings); i++)
|
||||
{
|
||||
char buf[INT_BUFSIZE_BOUND (int)];
|
||||
|
||||
printf ("Spawned test for %s (%d)\n", teststrings[i], i);
|
||||
snprintf (buf, sizeof (buf), "%d\n", i);
|
||||
if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
|
||||
exit (1);
|
||||
|
||||
int status = support_capture_subprogram_self_sgid (buf);
|
||||
|
||||
/* Bail out early if unsupported. */
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
ret |= status;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION_ARGV do_test
|
||||
#include <support/test-driver.c>
|
||||
|
||||
+14
-183
@@ -29,173 +29,12 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
|
||||
static char SETGID_CHILD[] = "setgid-child";
|
||||
#define CHILD_STATUS 42
|
||||
|
||||
/* Return a GID which is not our current GID, but is present in the
|
||||
supplementary group list. */
|
||||
static gid_t
|
||||
choose_gid (void)
|
||||
{
|
||||
const int count = 64;
|
||||
gid_t groups[count];
|
||||
int ret = getgroups (count, groups);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf ("getgroups: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
gid_t current = getgid ();
|
||||
for (int i = 0; i < ret; ++i)
|
||||
{
|
||||
if (groups[i] != current)
|
||||
return groups[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */
|
||||
static pid_t
|
||||
do_execve (char **args)
|
||||
{
|
||||
pid_t kid = vfork ();
|
||||
|
||||
if (kid < 0)
|
||||
{
|
||||
printf ("vfork: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (kid == 0)
|
||||
{
|
||||
/* Child process. */
|
||||
execve (args[0], args, environ);
|
||||
_exit (-errno);
|
||||
}
|
||||
|
||||
if (kid < 0)
|
||||
return 1;
|
||||
|
||||
int status;
|
||||
|
||||
if (waitpid (kid, &status, 0) < 0)
|
||||
{
|
||||
printf ("waitpid: %m\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS)
|
||||
{
|
||||
printf ("Unexpected exit status %d from child process\n",
|
||||
WEXITSTATUS (status));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copies the executable into a restricted directory, so that we can
|
||||
safely make it SGID with the TARGET group ID. Then runs the
|
||||
executable. */
|
||||
static int
|
||||
run_executable_sgid (gid_t target)
|
||||
{
|
||||
char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
|
||||
test_dir, (intmax_t) getpid ());
|
||||
char *execname = xasprintf ("%s/bin", dirname);
|
||||
int infd = -1;
|
||||
int outfd = -1;
|
||||
int ret = 0;
|
||||
if (mkdir (dirname, 0700) < 0)
|
||||
{
|
||||
printf ("mkdir: %m\n");
|
||||
goto err;
|
||||
}
|
||||
infd = open ("/proc/self/exe", O_RDONLY);
|
||||
if (infd < 0)
|
||||
{
|
||||
printf ("open (/proc/self/exe): %m\n");
|
||||
goto err;
|
||||
}
|
||||
outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
|
||||
if (outfd < 0)
|
||||
{
|
||||
printf ("open (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
char buf[4096];
|
||||
for (;;)
|
||||
{
|
||||
ssize_t rdcount = read (infd, buf, sizeof (buf));
|
||||
if (rdcount < 0)
|
||||
{
|
||||
printf ("read: %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (rdcount == 0)
|
||||
break;
|
||||
char *p = buf;
|
||||
char *end = buf + rdcount;
|
||||
while (p != end)
|
||||
{
|
||||
ssize_t wrcount = write (outfd, buf, end - p);
|
||||
if (wrcount == 0)
|
||||
errno = ENOSPC;
|
||||
if (wrcount <= 0)
|
||||
{
|
||||
printf ("write: %m\n");
|
||||
goto err;
|
||||
}
|
||||
p += wrcount;
|
||||
}
|
||||
}
|
||||
if (fchown (outfd, getuid (), target) < 0)
|
||||
{
|
||||
printf ("fchown (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
if (fchmod (outfd, 02750) < 0)
|
||||
{
|
||||
printf ("fchmod (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
if (close (outfd) < 0)
|
||||
{
|
||||
printf ("close (outfd): %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (close (infd) < 0)
|
||||
{
|
||||
printf ("close (infd): %m\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
char *args[] = {execname, SETGID_CHILD, NULL};
|
||||
|
||||
ret = do_execve (args);
|
||||
|
||||
err:
|
||||
if (outfd >= 0)
|
||||
close (outfd);
|
||||
if (infd >= 0)
|
||||
close (infd);
|
||||
if (execname)
|
||||
{
|
||||
unlink (execname);
|
||||
free (execname);
|
||||
}
|
||||
if (dirname)
|
||||
{
|
||||
rmdir (dirname);
|
||||
free (dirname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef test_child
|
||||
static int
|
||||
@@ -256,40 +95,32 @@ do_test (int argc, char **argv)
|
||||
if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
|
||||
{
|
||||
if (getgid () == getegid ())
|
||||
{
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
exit (EXIT_UNSUPPORTED);
|
||||
}
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
|
||||
int ret = test_child ();
|
||||
|
||||
if (ret != 0)
|
||||
exit (1);
|
||||
|
||||
exit (CHILD_STATUS);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (test_parent () != 0)
|
||||
exit (1);
|
||||
|
||||
/* Try running a setgid program. */
|
||||
gid_t target = choose_gid ();
|
||||
if (target == 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Could not find a suitable GID for user %jd, skipping test\n",
|
||||
(intmax_t) getuid ());
|
||||
exit (0);
|
||||
}
|
||||
int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
|
||||
|
||||
return run_executable_sgid (target);
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
if (!WIFEXITED (status))
|
||||
FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Something went wrong and our argv was corrupted. */
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION_ARGV do_test
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ CFLAGS-linereader.c += -DNO_TRANSLITERATION
|
||||
CFLAGS-simple-hash.c += -I../locale
|
||||
|
||||
tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 \
|
||||
tst-iconv7 tst-iconv-mt tst-iconv-opt
|
||||
tst-iconv7 tst-iconv8 tst-iconv-mt tst-iconv-opt
|
||||
|
||||
others = iconv_prog iconvconfig
|
||||
install-others-programs = $(inst_bindir)/iconv
|
||||
|
||||
+3
-1
@@ -6,7 +6,9 @@ libc {
|
||||
GLIBC_PRIVATE {
|
||||
# functions shared with iconv program
|
||||
__gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db;
|
||||
__gconv_open; __gconv_create_spec;
|
||||
|
||||
# functions used elsewhere in glibc
|
||||
__gconv_open; __gconv_create_spec; __gconv_destroy_spec;
|
||||
|
||||
# function used by the gconv modules
|
||||
__gconv_transliterate;
|
||||
|
||||
@@ -216,3 +216,13 @@ out:
|
||||
return ret;
|
||||
}
|
||||
libc_hidden_def (__gconv_create_spec)
|
||||
|
||||
|
||||
void
|
||||
__gconv_destroy_spec (struct gconv_spec *conv_spec)
|
||||
{
|
||||
free (conv_spec->fromcode);
|
||||
free (conv_spec->tocode);
|
||||
return;
|
||||
}
|
||||
libc_hidden_def (__gconv_destroy_spec)
|
||||
|
||||
@@ -48,33 +48,6 @@
|
||||
#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE"
|
||||
|
||||
|
||||
/* This function accepts the charset names of the source and destination of the
|
||||
conversion and populates *conv_spec with an equivalent conversion
|
||||
specification that may later be used by __gconv_open. The charset names
|
||||
might contain options in the form of suffixes that alter the conversion,
|
||||
e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
|
||||
and truncating any suffix options in fromcode, and processing and truncating
|
||||
any suffix options in tocode. Supported suffix options ("TRANSLIT" or
|
||||
"IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
|
||||
to be set to true. Unrecognized suffix options are silently discarded. If
|
||||
the function succeeds, it returns conv_spec back to the caller. It returns
|
||||
NULL upon failure. */
|
||||
struct gconv_spec *
|
||||
__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
|
||||
const char *tocode);
|
||||
libc_hidden_proto (__gconv_create_spec)
|
||||
|
||||
|
||||
/* This function frees all heap memory allocated by __gconv_create_spec. */
|
||||
static void __attribute__ ((unused))
|
||||
gconv_destroy_spec (struct gconv_spec *conv_spec)
|
||||
{
|
||||
free (conv_spec->fromcode);
|
||||
free (conv_spec->tocode);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* This function copies in-order, characters from the source 's' that are
|
||||
either alpha-numeric or one in one of these: "_-.,:/" - into the destination
|
||||
'wp' while dropping all other characters. In the process, it converts all
|
||||
|
||||
@@ -152,6 +152,27 @@ extern int __gconv_open (struct gconv_spec *conv_spec,
|
||||
__gconv_t *handle, int flags);
|
||||
libc_hidden_proto (__gconv_open)
|
||||
|
||||
/* This function accepts the charset names of the source and destination of the
|
||||
conversion and populates *conv_spec with an equivalent conversion
|
||||
specification that may later be used by __gconv_open. The charset names
|
||||
might contain options in the form of suffixes that alter the conversion,
|
||||
e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
|
||||
and truncating any suffix options in fromcode, and processing and truncating
|
||||
any suffix options in tocode. Supported suffix options ("TRANSLIT" or
|
||||
"IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
|
||||
to be set to true. Unrecognized suffix options are silently discarded. If
|
||||
the function succeeds, it returns conv_spec back to the caller. It returns
|
||||
NULL upon failure. */
|
||||
extern struct gconv_spec *
|
||||
__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
|
||||
const char *tocode);
|
||||
libc_hidden_proto (__gconv_create_spec)
|
||||
|
||||
/* This function frees all heap memory allocated by __gconv_create_spec. */
|
||||
extern void
|
||||
__gconv_destroy_spec (struct gconv_spec *conv_spec);
|
||||
libc_hidden_proto (__gconv_destroy_spec)
|
||||
|
||||
/* Free resources associated with transformation descriptor CD. */
|
||||
extern int __gconv_close (__gconv_t cd)
|
||||
attribute_hidden;
|
||||
|
||||
+4
-12
@@ -239,11 +239,9 @@ ucs4_internal_loop (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
uint32_t inval;
|
||||
|
||||
@@ -307,11 +305,9 @@ ucs4_internal_loop_unaligned (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
if (__glibc_unlikely (inptr[0] > 0x80))
|
||||
{
|
||||
@@ -613,11 +609,9 @@ ucs4le_internal_loop (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
uint32_t inval;
|
||||
|
||||
@@ -684,11 +678,9 @@ ucs4le_internal_loop_unaligned (struct __gconv_step *step,
|
||||
int flags = step_data->__flags;
|
||||
const unsigned char *inptr = *inptrp;
|
||||
unsigned char *outptr = *outptrp;
|
||||
size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
|
||||
int result;
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
|
||||
for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
|
||||
{
|
||||
if (__glibc_unlikely (inptr[3] > 0x80))
|
||||
{
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ iconv_open (const char *tocode, const char *fromcode)
|
||||
|
||||
int res = __gconv_open (&conv_spec, &cd, 0);
|
||||
|
||||
gconv_destroy_spec (&conv_spec);
|
||||
__gconv_destroy_spec (&conv_spec);
|
||||
|
||||
if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
|
||||
{
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ main (int argc, char *argv[])
|
||||
/* Let's see whether we have these coded character sets. */
|
||||
res = __gconv_open (&conv_spec, &cd, 0);
|
||||
|
||||
gconv_destroy_spec (&conv_spec);
|
||||
__gconv_destroy_spec (&conv_spec);
|
||||
|
||||
if (res != __GCONV_OK)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Test iconv behavior on UCS4 conversions with //IGNORE.
|
||||
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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Derived from BZ #26923 */
|
||||
#include <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
iconv_t cd = iconv_open ("UTF-8//IGNORE", "ISO-10646/UCS4/");
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
/*
|
||||
* Convert sequence beginning with an irreversible character into buffer that
|
||||
* is too small.
|
||||
*/
|
||||
char input[12] = "\xe1\x80\xa1" "AAAAAAAAA";
|
||||
char *inptr = input;
|
||||
size_t insize = sizeof (input);
|
||||
char output[6];
|
||||
char *outptr = output;
|
||||
size_t outsize = sizeof (output);
|
||||
|
||||
TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == -1);
|
||||
TEST_VERIFY (errno == E2BIG);
|
||||
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) != -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+10
-6
@@ -102,12 +102,16 @@ hangarray=(
|
||||
"\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE"
|
||||
# These are known hangs that are yet to be fixed:
|
||||
# "\x00\x0f;-c;IBM1364;UTF-8"
|
||||
# "\x00\x0f;-c;IBM1371;UTF-8"
|
||||
# "\x00\x0f;-c;IBM1388;UTF-8"
|
||||
# "\x00\x0f;-c;IBM1390;UTF-8"
|
||||
# "\x00\x0f;-c;IBM1399;UTF-8"
|
||||
"\x00\x0f;-c;IBM1364;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1364;UTF-8"
|
||||
"\x00\x0f;-c;IBM1371;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1371;UTF-8"
|
||||
"\x00\x0f;-c;IBM1388;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1388;UTF-8"
|
||||
"\x00\x0f;-c;IBM1390;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1390;UTF-8"
|
||||
"\x00\x0f;-c;IBM1399;UTF-8"
|
||||
"\x0e\x0e;-c;IBM1399;UTF-8"
|
||||
"\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE"
|
||||
"\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE"
|
||||
|
||||
+10
-1
@@ -1,4 +1,5 @@
|
||||
# Copyright (C) 1997-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 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
|
||||
@@ -73,7 +74,9 @@ modules.so := $(addsuffix .so, $(modules))
|
||||
ifeq (yes,$(build-shared))
|
||||
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
|
||||
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
|
||||
bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4
|
||||
bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
|
||||
bug-iconv13 bug-iconv14 bug-iconv15 \
|
||||
tst-iconv-iso-2022-cn-ext
|
||||
ifeq ($(have-thread-library),yes)
|
||||
tests += bug-iconv3
|
||||
endif
|
||||
@@ -321,6 +324,12 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
$(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) \
|
||||
$(addprefix $(objpfx),$(modules.so))
|
||||
|
||||
$(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
|
||||
$(addprefix $(objpfx),$(modules.so)) \
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/* bug 24973: Test EUC-KR module
|
||||
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 <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
iconv_t cd = iconv_open ("UTF-8//IGNORE", "EUC-KR");
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
/* 0xfe (->0x7e : row 94) and 0xc9 (->0x49 : row 41) are user-defined
|
||||
areas, which are not allowed and should be skipped over due to
|
||||
//IGNORE. The trailing 0xfe also is an incomplete sequence, which
|
||||
should be checked first. */
|
||||
char input[4] = { '\xc9', '\xa1', '\0', '\xfe' };
|
||||
char *inptr = input;
|
||||
size_t insize = sizeof (input);
|
||||
char output[4];
|
||||
char *outptr = output;
|
||||
size_t outsize = sizeof (output);
|
||||
|
||||
/* This used to crash due to buffer overrun. */
|
||||
TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) -1);
|
||||
TEST_VERIFY (errno == EINVAL);
|
||||
/* The conversion should produce one character, the converted null
|
||||
character. */
|
||||
TEST_VERIFY (sizeof (output) - outsize == 1);
|
||||
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) != -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,127 @@
|
||||
/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256).
|
||||
Copyright (C) 2021 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 <iconv.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <support/check.h>
|
||||
|
||||
/* Use an escape sequence to return to the initial state. */
|
||||
static void
|
||||
with_escape_sequence (void)
|
||||
{
|
||||
iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
|
||||
TEST_VERIFY_EXIT (c != (iconv_t) -1);
|
||||
|
||||
char in[] = "\e$(O+D\e(B";
|
||||
char *inbuf = in;
|
||||
size_t inleft = strlen (in);
|
||||
char out[3]; /* Space for one output character. */
|
||||
char *outbuf;
|
||||
size_t outleft;
|
||||
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
|
||||
TEST_COMPARE (errno, E2BIG);
|
||||
TEST_COMPARE (inleft, 3);
|
||||
TEST_COMPARE (inbuf - in, strlen (in) - 3);
|
||||
TEST_COMPARE (outleft, sizeof (out) - 2);
|
||||
TEST_COMPARE (outbuf - out, 2);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xc3);
|
||||
TEST_COMPARE (out[1] & 0xff, 0xa6);
|
||||
|
||||
/* Return to the initial shift state, producing the pending
|
||||
character. */
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0);
|
||||
TEST_COMPARE (inleft, 0);
|
||||
TEST_COMPARE (inbuf - in, strlen (in));
|
||||
TEST_COMPARE (outleft, sizeof (out) - 2);
|
||||
TEST_COMPARE (outbuf - out, 2);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xcc);
|
||||
TEST_COMPARE (out[1] & 0xff, 0x80);
|
||||
|
||||
/* Nothing should be flushed the second time. */
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
|
||||
TEST_COMPARE (outleft, sizeof (out));
|
||||
TEST_COMPARE (outbuf - out, 0);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xcc);
|
||||
TEST_COMPARE (out[1] & 0xff, 0x80);
|
||||
|
||||
TEST_COMPARE (iconv_close (c), 0);
|
||||
}
|
||||
|
||||
/* Use an explicit flush to return to the initial state. */
|
||||
static void
|
||||
with_flush (void)
|
||||
{
|
||||
iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
|
||||
TEST_VERIFY_EXIT (c != (iconv_t) -1);
|
||||
|
||||
char in[] = "\e$(O+D";
|
||||
char *inbuf = in;
|
||||
size_t inleft = strlen (in);
|
||||
char out[3]; /* Space for one output character. */
|
||||
char *outbuf;
|
||||
size_t outleft;
|
||||
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
|
||||
TEST_COMPARE (errno, E2BIG);
|
||||
TEST_COMPARE (inleft, 0);
|
||||
TEST_COMPARE (inbuf - in, strlen (in));
|
||||
TEST_COMPARE (outleft, sizeof (out) - 2);
|
||||
TEST_COMPARE (outbuf - out, 2);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xc3);
|
||||
TEST_COMPARE (out[1] & 0xff, 0xa6);
|
||||
|
||||
/* Flush the pending character. */
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
|
||||
TEST_COMPARE (outleft, sizeof (out) - 2);
|
||||
TEST_COMPARE (outbuf - out, 2);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xcc);
|
||||
TEST_COMPARE (out[1] & 0xff, 0x80);
|
||||
|
||||
/* Nothing should be flushed the second time. */
|
||||
outbuf = out;
|
||||
outleft = sizeof (out);
|
||||
TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
|
||||
TEST_COMPARE (outleft, sizeof (out));
|
||||
TEST_COMPARE (outbuf - out, 0);
|
||||
TEST_COMPARE (out[0] & 0xff, 0xcc);
|
||||
TEST_COMPARE (out[1] & 0xff, 0x80);
|
||||
|
||||
TEST_COMPARE (iconv_close (c), 0);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
with_escape_sequence ();
|
||||
with_flush ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv
|
||||
may emit spurious NUL character on state reset.
|
||||
Copyright (C) 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/>. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <iconv.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char in[] = "\x1b(I";
|
||||
char *inbuf = in;
|
||||
size_t inleft = sizeof (in) - 1;
|
||||
char out[1];
|
||||
char *outbuf = out;
|
||||
size_t outleft = sizeof (out);
|
||||
iconv_t cd;
|
||||
|
||||
cd = iconv_open ("UTF8", "ISO-2022-JP-3");
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
/* First call to iconv should alter internal state.
|
||||
Now, JISX0201_Kana_set is selected and
|
||||
state value != ASCII_set. */
|
||||
TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1);
|
||||
|
||||
/* No bytes should have been added to
|
||||
the output buffer at this point. */
|
||||
TEST_VERIFY (outbuf == out);
|
||||
TEST_VERIFY (outleft == sizeof (out));
|
||||
|
||||
/* Second call shall emit spurious NUL character in unpatched glibc. */
|
||||
TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1);
|
||||
|
||||
/* No characters are expected to be produced. */
|
||||
TEST_VERIFY (outbuf == out);
|
||||
TEST_VERIFY (outleft == sizeof (out));
|
||||
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) != -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+1
-5
@@ -80,11 +80,7 @@ euckr_from_ucs4 (uint32_t ch, unsigned char *cp)
|
||||
\
|
||||
if (ch <= 0x9f) \
|
||||
++inptr; \
|
||||
/* 0xfe(->0x7e : row 94) and 0xc9(->0x59 : row 41) are \
|
||||
user-defined areas. */ \
|
||||
else if (__builtin_expect (ch == 0xa0, 0) \
|
||||
|| __builtin_expect (ch > 0xfe, 0) \
|
||||
|| __builtin_expect (ch == 0xc9, 0)) \
|
||||
else if (__glibc_unlikely (ch == 0xa0)) \
|
||||
{ \
|
||||
/* This is illegal. */ \
|
||||
STANDARD_FROM_LOOP_ERR_HANDLER (1); \
|
||||
|
||||
+2
-12
@@ -158,24 +158,14 @@ enum
|
||||
\
|
||||
if (__builtin_expect (ch, 0) == SO) \
|
||||
{ \
|
||||
/* Shift OUT, change to DBCS converter. */ \
|
||||
if (curcs == db) \
|
||||
{ \
|
||||
result = __GCONV_ILLEGAL_INPUT; \
|
||||
break; \
|
||||
} \
|
||||
/* Shift OUT, change to DBCS converter (redundant escape okay). */ \
|
||||
curcs = db; \
|
||||
++inptr; \
|
||||
continue; \
|
||||
} \
|
||||
if (__builtin_expect (ch, 0) == SI) \
|
||||
{ \
|
||||
/* Shift IN, change to SBCS converter. */ \
|
||||
if (curcs == sb) \
|
||||
{ \
|
||||
result = __GCONV_ILLEGAL_INPUT; \
|
||||
break; \
|
||||
} \
|
||||
/* Shift IN, change to SBCS converter (redundant escape okay). */ \
|
||||
curcs = sb; \
|
||||
++inptr; \
|
||||
continue; \
|
||||
|
||||
@@ -575,6 +575,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
|
||||
{ \
|
||||
const char *escseq; \
|
||||
\
|
||||
if (outptr + 4 > outend) \
|
||||
{ \
|
||||
result = __GCONV_FULL_OUTPUT; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
assert (used == CNS11643_2_set); /* XXX */ \
|
||||
escseq = "*H"; \
|
||||
*outptr++ = ESC; \
|
||||
@@ -588,6 +594,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
|
||||
{ \
|
||||
const char *escseq; \
|
||||
\
|
||||
if (outptr + 4 > outend) \
|
||||
{ \
|
||||
result = __GCONV_FULL_OUTPUT; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
assert ((used >> 5) >= 3 && (used >> 5) <= 7); \
|
||||
escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2; \
|
||||
*outptr++ = ESC; \
|
||||
|
||||
+59
-18
@@ -1,5 +1,6 @@
|
||||
/* Conversion module for ISO-2022-JP-3.
|
||||
Copyright (C) 1998-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) The GNU Toolchain Authors.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998,
|
||||
and Bruno Haible <bruno@clisp.org>, 2002.
|
||||
@@ -67,10 +68,15 @@ enum
|
||||
CURRENT_SEL_MASK = 7 << 3
|
||||
};
|
||||
|
||||
/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state
|
||||
also contains the last two bytes to be output, shifted by 6 bits, and a
|
||||
one-bit indicator whether they must be preceded by the shift sequence,
|
||||
in bit 22. */
|
||||
/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the
|
||||
state also contains the last two bytes to be output, shifted by 6
|
||||
bits, and a one-bit indicator whether they must be preceded by the
|
||||
shift sequence, in bit 22. During ISO-2022-JP-3 to UCS-4
|
||||
conversion, COUNT may also contain a non-zero pending wide
|
||||
character, shifted by six bits. This happens for certain inputs in
|
||||
JISX0213_1_2004_set and JISX0213_2_set if the second wide character
|
||||
in a combining sequence cannot be written because the buffer is
|
||||
full. */
|
||||
|
||||
/* Since this is a stateful encoding we have to provide code which resets
|
||||
the output state to the initial state. This has to be done during the
|
||||
@@ -80,10 +86,27 @@ enum
|
||||
{ \
|
||||
if (FROM_DIRECTION) \
|
||||
{ \
|
||||
/* It's easy, we don't have to emit anything, we just reset the \
|
||||
state for the input. */ \
|
||||
data->__statep->__count &= 7; \
|
||||
data->__statep->__count |= ASCII_set; \
|
||||
uint32_t ch = data->__statep->__count >> 6; \
|
||||
\
|
||||
if (__glibc_unlikely (ch != 0)) \
|
||||
{ \
|
||||
if (__glibc_likely (outbuf + 4 <= outend)) \
|
||||
{ \
|
||||
/* Write out the last character. */ \
|
||||
put32u (outbuf, ch); \
|
||||
outbuf += 4; \
|
||||
data->__statep->__count &= 7; \
|
||||
data->__statep->__count |= ASCII_set; \
|
||||
} \
|
||||
else \
|
||||
/* We don't have enough room in the output buffer. */ \
|
||||
status = __GCONV_FULL_OUTPUT; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
data->__statep->__count &= 7; \
|
||||
data->__statep->__count |= ASCII_set; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
@@ -151,7 +174,21 @@ enum
|
||||
#define LOOPFCT FROM_LOOP
|
||||
#define BODY \
|
||||
{ \
|
||||
uint32_t ch = *inptr; \
|
||||
uint32_t ch; \
|
||||
\
|
||||
/* Output any pending character. */ \
|
||||
ch = set >> 6; \
|
||||
if (__glibc_unlikely (ch != 0)) \
|
||||
{ \
|
||||
put32 (outptr, ch); \
|
||||
outptr += 4; \
|
||||
/* Remove the pending character, but preserve state bits. */ \
|
||||
set &= (1 << 6) - 1; \
|
||||
continue; \
|
||||
} \
|
||||
\
|
||||
/* Otherwise read the next input byte. */ \
|
||||
ch = *inptr; \
|
||||
\
|
||||
/* Recognize escape sequences. */ \
|
||||
if (__glibc_unlikely (ch == ESC)) \
|
||||
@@ -297,21 +334,25 @@ enum
|
||||
uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0]; \
|
||||
uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1]; \
|
||||
\
|
||||
inptr += 2; \
|
||||
\
|
||||
put32 (outptr, u1); \
|
||||
outptr += 4; \
|
||||
\
|
||||
/* See whether we have room for two characters. */ \
|
||||
if (outptr + 8 <= outend) \
|
||||
if (outptr + 4 <= outend) \
|
||||
{ \
|
||||
inptr += 2; \
|
||||
put32 (outptr, u1); \
|
||||
outptr += 4; \
|
||||
put32 (outptr, u2); \
|
||||
outptr += 4; \
|
||||
continue; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
result = __GCONV_FULL_OUTPUT; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
/* Otherwise store only the first character now, and \
|
||||
put the second one into the queue. */ \
|
||||
set |= u2 << 6; \
|
||||
/* Tell the caller why we terminate the loop. */ \
|
||||
result = __GCONV_FULL_OUTPUT; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
inptr += 2; \
|
||||
|
||||
+3
-3
@@ -50,15 +50,15 @@ ksc5601_to_ucs4 (const unsigned char **s, size_t avail, unsigned char offset)
|
||||
unsigned char ch2;
|
||||
int idx;
|
||||
|
||||
if (avail < 2)
|
||||
return 0;
|
||||
|
||||
/* row 94(0x7e) and row 41(0x49) are user-defined area in KS C 5601 */
|
||||
|
||||
if (ch < offset || (ch - offset) <= 0x20 || (ch - offset) >= 0x7e
|
||||
|| (ch - offset) == 0x49)
|
||||
return __UNKNOWN_10646_CHAR;
|
||||
|
||||
if (avail < 2)
|
||||
return 0;
|
||||
|
||||
ch2 = (*s)[1];
|
||||
if (ch2 < offset || (ch2 - offset) <= 0x20 || (ch2 - offset) >= 0x7f)
|
||||
return __UNKNOWN_10646_CHAR;
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/* Verify ISO-2022-CN-EXT does not write out of the bounds.
|
||||
Copyright (C) 2024 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 <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <iconv.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <support/xunistd.h>
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
|
||||
/* The test sets up a two memory page buffer with the second page marked
|
||||
PROT_NONE to trigger a fault if the conversion writes beyond the exact
|
||||
expected amount. Then we carry out various conversions and precisely
|
||||
place the start of the output buffer in order to trigger a SIGSEGV if the
|
||||
process writes anywhere between 1 and page sized bytes more (only one
|
||||
PROT_NONE page is setup as a canary) than expected. These tests exercise
|
||||
all three of the cases in ISO-2022-CN-EXT where the converter must switch
|
||||
character sets and may run out of buffer space while doing the
|
||||
operation. */
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
iconv_t cd = iconv_open ("ISO-2022-CN-EXT", "UTF-8");
|
||||
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
|
||||
|
||||
char *ntf;
|
||||
size_t ntfsize;
|
||||
char *outbufbase;
|
||||
{
|
||||
int pgz = getpagesize ();
|
||||
TEST_VERIFY_EXIT (pgz > 0);
|
||||
ntfsize = 2 * pgz;
|
||||
|
||||
ntf = xmmap (NULL, ntfsize, PROT_READ | PROT_WRITE, MAP_PRIVATE
|
||||
| MAP_ANONYMOUS, -1);
|
||||
xmprotect (ntf + pgz, pgz, PROT_NONE);
|
||||
|
||||
outbufbase = ntf + pgz;
|
||||
}
|
||||
|
||||
/* Check if SOdesignation escape sequence does not trigger an OOB write. */
|
||||
{
|
||||
char inbuf[] = "\xe4\xba\xa4\xe6\x8d\xa2";
|
||||
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
char *inp = inbuf;
|
||||
size_t inleft = sizeof (inbuf) - 1;
|
||||
|
||||
char *outp = outbufbase - i;
|
||||
size_t outleft = i;
|
||||
|
||||
TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
|
||||
== (size_t) -1);
|
||||
TEST_COMPARE (errno, E2BIG);
|
||||
|
||||
TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Same as before for SS2designation. */
|
||||
{
|
||||
char inbuf[] = "㴽 \xe3\xb4\xbd";
|
||||
|
||||
for (int i = 0; i < 14; i++)
|
||||
{
|
||||
char *inp = inbuf;
|
||||
size_t inleft = sizeof (inbuf) - 1;
|
||||
|
||||
char *outp = outbufbase - i;
|
||||
size_t outleft = i;
|
||||
|
||||
TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
|
||||
== (size_t) -1);
|
||||
TEST_COMPARE (errno, E2BIG);
|
||||
|
||||
TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Same as before for SS3designation. */
|
||||
{
|
||||
char inbuf[] = "劄 \xe5\x8a\x84";
|
||||
|
||||
for (int i = 0; i < 14; i++)
|
||||
{
|
||||
char *inp = inbuf;
|
||||
size_t inleft = sizeof (inbuf) - 1;
|
||||
|
||||
char *outp = outbufbase - i;
|
||||
size_t outleft = i;
|
||||
|
||||
TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
|
||||
== (size_t) -1);
|
||||
TEST_COMPARE (errno, E2BIG);
|
||||
|
||||
TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_VERIFY_EXIT (iconv_close (cd) != -1);
|
||||
|
||||
xmunmap (ntf, ntfsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+13
-13
@@ -59,6 +59,19 @@
|
||||
# define IN_MODULE (-1)
|
||||
#endif
|
||||
|
||||
/* Use symbol_version_reference to specify the version a symbol
|
||||
reference should link to. Use symbol_version or
|
||||
default_symbol_version for the definition of a versioned symbol.
|
||||
The difference is that the latter is a no-op in non-shared
|
||||
builds. */
|
||||
#ifdef __ASSEMBLER__
|
||||
# define symbol_version_reference(real, name, version) \
|
||||
.symver real, name##@##version
|
||||
#else /* !__ASSEMBLER__ */
|
||||
# define symbol_version_reference(real, name, version) \
|
||||
__asm__ (".symver " #real "," #name "@" #version)
|
||||
#endif
|
||||
|
||||
#ifndef _ISOMAC
|
||||
|
||||
/* This is defined for the compilation of all C library code. features.h
|
||||
@@ -396,19 +409,6 @@ for linking")
|
||||
past the last element in SET. */
|
||||
#define symbol_set_end_p(set, ptr) ((ptr) >= (void *const *) &__stop_##set)
|
||||
|
||||
/* Use symbol_version_reference to specify the version a symbol
|
||||
reference should link to. Use symbol_version or
|
||||
default_symbol_version for the definition of a versioned symbol.
|
||||
The difference is that the latter is a no-op in non-shared
|
||||
builds. */
|
||||
#ifdef __ASSEMBLER__
|
||||
# define symbol_version_reference(real, name, version) \
|
||||
.symver real, name##@##version
|
||||
#else /* !__ASSEMBLER__ */
|
||||
# define symbol_version_reference(real, name, version) \
|
||||
__asm__ (".symver " #real "," #name "@" #version)
|
||||
#endif
|
||||
|
||||
#ifdef SHARED
|
||||
# define symbol_version(real, name, version) \
|
||||
symbol_version_reference(real, name, version)
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
#include <socket/sys/un.h>
|
||||
|
||||
#ifndef _ISOMAC
|
||||
|
||||
/* Set ADDR->sun_family to AF_UNIX and ADDR->sun_path to PATHNAME.
|
||||
Return 0 on success or -1 on failure (due to overlong PATHNAME).
|
||||
The caller should always use sizeof (struct sockaddr_un) as the
|
||||
socket address length, disregaring the length of PATHNAME.
|
||||
Only concrete (non-abstract) pathnames are supported. */
|
||||
int __sockaddr_un_set (struct sockaddr_un *addr, const char *pathname)
|
||||
attribute_hidden;
|
||||
|
||||
#endif /* _ISOMAC */
|
||||
|
||||
+10
-7
@@ -1120,15 +1120,18 @@ _nl_find_msg (struct loaded_l10nfile *domain_file,
|
||||
|
||||
# ifdef _LIBC
|
||||
|
||||
struct gconv_spec conv_spec
|
||||
= { .fromcode = norm_add_slashes (charset, ""),
|
||||
.tocode = norm_add_slashes (outcharset, ""),
|
||||
/* We always want to use transliteration. */
|
||||
.translit = true,
|
||||
.ignore = false
|
||||
};
|
||||
struct gconv_spec conv_spec;
|
||||
|
||||
__gconv_create_spec (&conv_spec, charset, outcharset);
|
||||
|
||||
/* We always want to use transliteration. */
|
||||
conv_spec.translit = true;
|
||||
|
||||
int r = __gconv_open (&conv_spec, &convd->conv,
|
||||
GCONV_AVOID_NOCONV);
|
||||
|
||||
__gconv_destroy_spec (&conv_spec);
|
||||
|
||||
if (__builtin_expect (r != __GCONV_OK, 0))
|
||||
{
|
||||
/* If the output encoding is the same there is
|
||||
|
||||
+14
-20
@@ -22,13 +22,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char *s;
|
||||
int result = 0;
|
||||
|
||||
unsetenv ("LANGUAGE");
|
||||
unsetenv ("OUTPUT_CHARSET");
|
||||
setlocale (LC_ALL, "de_DE.ISO-8859-1");
|
||||
@@ -36,25 +34,21 @@ do_test (void)
|
||||
bindtextdomain ("codeset", OBJPFX "domaindir");
|
||||
|
||||
/* Here we expect output in ISO-8859-1. */
|
||||
s = gettext ("cheese");
|
||||
if (strcmp (s, "K\344se"))
|
||||
{
|
||||
printf ("call 1 returned: %s\n", s);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
bind_textdomain_codeset ("codeset", "UTF-8");
|
||||
TEST_COMPARE_STRING (gettext ("cheese"), "K\344se");
|
||||
|
||||
/* Here we expect output in UTF-8. */
|
||||
s = gettext ("cheese");
|
||||
if (strcmp (s, "K\303\244se"))
|
||||
{
|
||||
printf ("call 2 returned: %s\n", s);
|
||||
result = 1;
|
||||
}
|
||||
bind_textdomain_codeset ("codeset", "UTF-8");
|
||||
TEST_COMPARE_STRING (gettext ("cheese"), "K\303\244se");
|
||||
|
||||
return result;
|
||||
/* `a with umlaut' is transliterated to `ae'. */
|
||||
bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT");
|
||||
TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
|
||||
|
||||
/* Transliteration also works by default even if not set. */
|
||||
bind_textdomain_codeset ("codeset", "ASCII");
|
||||
TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
#include <support/test-driver.c>
|
||||
|
||||
@@ -62,6 +62,16 @@ endif
|
||||
tests += $(tests-static)
|
||||
test-srcs = tst-mtrace
|
||||
|
||||
# These tests either are run with MALLOC_CHECK_=3 by default or do not work
|
||||
# with MALLOC_CHECK_=3 because they expect a specific failure.
|
||||
tests-exclude-mcheck = tst-mcheck tst-malloc-usable \
|
||||
tst-interpose-nothread tst-interpose-static-nothread \
|
||||
tst-interpose-static-thread tst-malloc-too-large \
|
||||
tst-mxfast tst-safe-linking
|
||||
|
||||
# Run all tests with MALLOC_CHECK_=3
|
||||
tests-mcheck = $(filter-out $(tests-exclude-mcheck),$(tests))
|
||||
|
||||
routines = malloc morecore mcheck mtrace obstack reallocarray \
|
||||
scratch_buffer_grow scratch_buffer_grow_preserve \
|
||||
scratch_buffer_set_array_size \
|
||||
@@ -100,6 +110,11 @@ $(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-stats-cancellation: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-backtrace-mcheck: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-exit-mcheck: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-fail-mcheck: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-fork-deadlock-mcheck: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-stats-cancellation-mcheck: $(shared-thread-library)
|
||||
|
||||
# Export the __malloc_initialize_hook variable to libc.so.
|
||||
LDFLAGS-tst-mallocstate = -rdynamic
|
||||
@@ -239,6 +254,8 @@ $(tests:%=$(objpfx)%.o): CPPFLAGS += -DTEST_NO_MALLOPT
|
||||
$(objpfx)tst-interpose-nothread: $(objpfx)tst-interpose-aux-nothread.o
|
||||
$(objpfx)tst-interpose-thread: \
|
||||
$(objpfx)tst-interpose-aux-thread.o $(shared-thread-library)
|
||||
$(objpfx)tst-interpose-thread-mcheck: \
|
||||
$(objpfx)tst-interpose-aux-thread.o $(shared-thread-library)
|
||||
$(objpfx)tst-interpose-static-nothread: $(objpfx)tst-interpose-aux-nothread.o
|
||||
$(objpfx)tst-interpose-static-thread: \
|
||||
$(objpfx)tst-interpose-aux-thread.o $(static-thread-library)
|
||||
@@ -256,3 +273,6 @@ $(objpfx)tst-dynarray-fail-mem.out: $(objpfx)tst-dynarray-fail.out
|
||||
$(objpfx)tst-malloc-tcache-leak: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc_info: $(shared-thread-library)
|
||||
$(objpfx)tst-mallocfork2: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-tcache-leak-mcheck: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc_info-mcheck: $(shared-thread-library)
|
||||
$(objpfx)tst-mallocfork2-mcheck: $(shared-thread-library)
|
||||
|
||||
+5
-3
@@ -4705,7 +4705,7 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
|
||||
|
||||
|
||||
|
||||
if (!checked_request2size (bytes, &nb))
|
||||
if (!checked_request2size (bytes, &nb) || alignment > PTRDIFF_MAX)
|
||||
{
|
||||
__set_errno (ENOMEM);
|
||||
return NULL;
|
||||
@@ -4716,8 +4716,10 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
|
||||
request, and then possibly free the leading and trailing space.
|
||||
*/
|
||||
|
||||
/* Call malloc with worst case padding to hit alignment. */
|
||||
|
||||
/* Call malloc with worst case padding to hit alignment. ALIGNMENT is a
|
||||
power of 2, so it tops out at (PTRDIFF_MAX >> 1) + 1, leaving plenty of
|
||||
space to add MINSIZE and whatever checked_request2size adds to BYTES to
|
||||
get NB. Consequently, total below also does not overflow. */
|
||||
m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
|
||||
|
||||
if (m == 0)
|
||||
|
||||
@@ -127,7 +127,6 @@ test_large_allocations (size_t size)
|
||||
}
|
||||
|
||||
|
||||
static long pagesize;
|
||||
|
||||
/* This function tests the following aligned memory allocation functions
|
||||
using several valid alignments and precedes each allocation test with a
|
||||
@@ -146,8 +145,8 @@ test_large_aligned_allocations (size_t size)
|
||||
|
||||
/* All aligned memory allocation functions expect an alignment that is a
|
||||
power of 2. Given this, we test each of them with every valid
|
||||
alignment from 1 thru PAGESIZE. */
|
||||
for (align = 1; align <= pagesize; align *= 2)
|
||||
alignment for the type of ALIGN, i.e. until it wraps to 0. */
|
||||
for (align = 1; align > 0; align <<= 1)
|
||||
{
|
||||
test_setup ();
|
||||
#if __GNUC_PREREQ (7, 0)
|
||||
@@ -240,11 +239,6 @@ do_test (void)
|
||||
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
|
||||
#endif
|
||||
|
||||
/* Aligned memory allocation functions need to be tested up to alignment
|
||||
size equivalent to page size, which should be a power of 2. */
|
||||
pagesize = sysconf (_SC_PAGESIZE);
|
||||
TEST_VERIFY_EXIT (powerof2 (pagesize));
|
||||
|
||||
/* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e.
|
||||
in the range (SIZE_MAX - 2^14, SIZE_MAX], fail.
|
||||
|
||||
|
||||
@@ -432,7 +432,11 @@ set shared cache size in bytes for use in memory and string routines.
|
||||
|
||||
@deftp Tunable glibc.cpu.x86_non_temporal_threshold
|
||||
The @code{glibc.cpu.x86_non_temporal_threshold} tunable allows the user
|
||||
to set threshold in bytes for non temporal store.
|
||||
to set threshold in bytes for non temporal store. Non temporal stores
|
||||
give a hint to the hardware to move data directly to memory without
|
||||
displacing other data from the cache. This tunable is used by some
|
||||
platforms to determine when to use non temporal stores in operations
|
||||
like memmove and memcpy.
|
||||
|
||||
This tunable is specific to i386 and x86-64.
|
||||
@end deftp
|
||||
|
||||
@@ -124,13 +124,10 @@
|
||||
#define __bos0(ptr) __builtin_object_size (ptr, 0)
|
||||
|
||||
#if __GNUC_PREREQ (4,3)
|
||||
# define __warndecl(name, msg) \
|
||||
extern void name (void) __attribute__((__warning__ (msg)))
|
||||
# define __warnattr(msg) __attribute__((__warning__ (msg)))
|
||||
# define __errordecl(name, msg) \
|
||||
extern void name (void) __attribute__((__error__ (msg)))
|
||||
#else
|
||||
# define __warndecl(name, msg) extern void name (void)
|
||||
# define __warnattr(msg)
|
||||
# define __errordecl(name, msg) extern void name (void)
|
||||
#endif
|
||||
|
||||
@@ -416,8 +416,6 @@ START_THREAD_DEFN
|
||||
unwind_buf.priv.data.prev = NULL;
|
||||
unwind_buf.priv.data.cleanup = NULL;
|
||||
|
||||
__libc_signal_restore_set (&pd->sigmask);
|
||||
|
||||
/* Allow setxid from now onwards. */
|
||||
if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2))
|
||||
futex_wake (&pd->setxid_futex, 1, FUTEX_PRIVATE);
|
||||
@@ -427,6 +425,8 @@ START_THREAD_DEFN
|
||||
/* Store the new cleanup handler info. */
|
||||
THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
|
||||
|
||||
__libc_signal_restore_set (&pd->sigmask);
|
||||
|
||||
/* We are either in (a) or (b), and in either case we either own
|
||||
PD already (2) or are about to own PD (1), and so our only
|
||||
restriction would be that we can't free PD until we know we
|
||||
|
||||
@@ -57,7 +57,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lll_trylock (mutex->__data.__lock) == 0)
|
||||
if (atomic_load_relaxed (&(mutex->__data.__lock)) == 0
|
||||
&& lll_trylock (mutex->__data.__lock) == 0)
|
||||
{
|
||||
/* Record the ownership. */
|
||||
mutex->__data.__owner = id;
|
||||
@@ -80,7 +81,10 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
|
||||
/*FALL THROUGH*/
|
||||
case PTHREAD_MUTEX_ADAPTIVE_NP:
|
||||
case PTHREAD_MUTEX_ERRORCHECK_NP:
|
||||
if (lll_trylock (mutex->__data.__lock) != 0)
|
||||
/* Mutex type is already loaded, lock check overhead should
|
||||
be minimal. */
|
||||
if (atomic_load_relaxed (&(mutex->__data.__lock)) != 0
|
||||
|| lll_trylock (mutex->__data.__lock) != 0)
|
||||
break;
|
||||
|
||||
/* Record the ownership. */
|
||||
|
||||
+137
-112
@@ -24,6 +24,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <scratch_buffer.h>
|
||||
|
||||
#include "../inet/netgroup.h"
|
||||
#include "nscd.h"
|
||||
@@ -66,6 +67,16 @@ struct dataset
|
||||
char strdata[0];
|
||||
};
|
||||
|
||||
/* Send a notfound response to FD. Always returns -1 to indicate an
|
||||
ephemeral error. */
|
||||
static time_t
|
||||
send_notfound (int fd)
|
||||
{
|
||||
if (fd != -1)
|
||||
TEMP_FAILURE_RETRY (send (fd, ¬found, sizeof (notfound), MSG_NOSIGNAL));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Sends a notfound message and prepares a notfound dataset to write to the
|
||||
cache. Returns true if there was enough memory to allocate the dataset and
|
||||
returns the dataset in DATASETP, total bytes to write in TOTALP and the
|
||||
@@ -84,8 +95,7 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
|
||||
total = sizeof (notfound);
|
||||
timeout = time (NULL) + db->negtimeout;
|
||||
|
||||
if (fd != -1)
|
||||
TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL));
|
||||
send_notfound (fd);
|
||||
|
||||
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
|
||||
/* If we cannot permanently store the result, so be it. */
|
||||
@@ -110,11 +120,78 @@ do_notfound (struct database_dyn *db, int fd, request_header *req,
|
||||
return cacheable;
|
||||
}
|
||||
|
||||
struct addgetnetgrentX_scratch
|
||||
{
|
||||
/* This is the result that the caller should use. It can be NULL,
|
||||
point into buffer, or it can be in the cache. */
|
||||
struct dataset *dataset;
|
||||
|
||||
struct scratch_buffer buffer;
|
||||
|
||||
/* Used internally in addgetnetgrentX as a staging area. */
|
||||
struct scratch_buffer tmp;
|
||||
|
||||
/* Number of bytes in buffer that are actually used. */
|
||||
size_t buffer_used;
|
||||
};
|
||||
|
||||
static void
|
||||
addgetnetgrentX_scratch_init (struct addgetnetgrentX_scratch *scratch)
|
||||
{
|
||||
scratch->dataset = NULL;
|
||||
scratch_buffer_init (&scratch->buffer);
|
||||
scratch_buffer_init (&scratch->tmp);
|
||||
|
||||
/* Reserve space for the header. */
|
||||
scratch->buffer_used = sizeof (struct dataset);
|
||||
static_assert (sizeof (struct dataset) < sizeof (scratch->tmp.__space),
|
||||
"initial buffer space");
|
||||
memset (scratch->tmp.data, 0, sizeof (struct dataset));
|
||||
}
|
||||
|
||||
static void
|
||||
addgetnetgrentX_scratch_free (struct addgetnetgrentX_scratch *scratch)
|
||||
{
|
||||
scratch_buffer_free (&scratch->buffer);
|
||||
scratch_buffer_free (&scratch->tmp);
|
||||
}
|
||||
|
||||
/* Copy LENGTH bytes from S into SCRATCH. Returns NULL if SCRATCH
|
||||
could not be resized, otherwise a pointer to the copy. */
|
||||
static char *
|
||||
addgetnetgrentX_append_n (struct addgetnetgrentX_scratch *scratch,
|
||||
const char *s, size_t length)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
size_t remaining = scratch->buffer.length - scratch->buffer_used;
|
||||
if (remaining >= length)
|
||||
break;
|
||||
if (!scratch_buffer_grow_preserve (&scratch->buffer))
|
||||
return NULL;
|
||||
}
|
||||
char *copy = scratch->buffer.data + scratch->buffer_used;
|
||||
memcpy (copy, s, length);
|
||||
scratch->buffer_used += length;
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* Copy S into SCRATCH, including its null terminator. Returns false
|
||||
if SCRATCH could not be resized. */
|
||||
static bool
|
||||
addgetnetgrentX_append (struct addgetnetgrentX_scratch *scratch, const char *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
s = "";
|
||||
return addgetnetgrentX_append_n (scratch, s, strlen (s) + 1) != NULL;
|
||||
}
|
||||
|
||||
/* Caller must initialize and free *SCRATCH. If the return value is
|
||||
negative, this function has sent a notfound response. */
|
||||
static time_t
|
||||
addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
const char *key, uid_t uid, struct hashentry *he,
|
||||
struct datahead *dh, struct dataset **resultp,
|
||||
void **tofreep)
|
||||
struct datahead *dh, struct addgetnetgrentX_scratch *scratch)
|
||||
{
|
||||
if (__glibc_unlikely (debug_level > 0))
|
||||
{
|
||||
@@ -133,14 +210,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
|
||||
char *key_copy = NULL;
|
||||
struct __netgrent data;
|
||||
size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
|
||||
size_t buffilled = sizeof (*dataset);
|
||||
char *buffer = NULL;
|
||||
size_t nentries = 0;
|
||||
size_t group_len = strlen (key) + 1;
|
||||
struct name_list *first_needed
|
||||
= alloca (sizeof (struct name_list) + group_len);
|
||||
*tofreep = NULL;
|
||||
|
||||
if (netgroup_database == NULL
|
||||
&& __nss_database_lookup2 ("netgroup", NULL, NULL, &netgroup_database))
|
||||
@@ -148,12 +221,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
/* No such service. */
|
||||
cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
|
||||
&key_copy);
|
||||
goto writeout;
|
||||
goto maybe_cache_add;
|
||||
}
|
||||
|
||||
memset (&data, '\0', sizeof (data));
|
||||
buffer = xmalloc (buflen);
|
||||
*tofreep = buffer;
|
||||
first_needed->next = first_needed;
|
||||
memcpy (first_needed->name, key, group_len);
|
||||
data.needed_groups = first_needed;
|
||||
@@ -196,8 +267,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
while (1)
|
||||
{
|
||||
int e;
|
||||
status = getfct.f (&data, buffer + buffilled,
|
||||
buflen - buffilled - req->key_len, &e);
|
||||
status = getfct.f (&data, scratch->tmp.data,
|
||||
scratch->tmp.length, &e);
|
||||
if (status == NSS_STATUS_SUCCESS)
|
||||
{
|
||||
if (data.type == triple_val)
|
||||
@@ -205,68 +276,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
const char *nhost = data.val.triple.host;
|
||||
const char *nuser = data.val.triple.user;
|
||||
const char *ndomain = data.val.triple.domain;
|
||||
|
||||
size_t hostlen = strlen (nhost ?: "") + 1;
|
||||
size_t userlen = strlen (nuser ?: "") + 1;
|
||||
size_t domainlen = strlen (ndomain ?: "") + 1;
|
||||
|
||||
if (nhost == NULL || nuser == NULL || ndomain == NULL
|
||||
|| nhost > nuser || nuser > ndomain)
|
||||
{
|
||||
const char *last = nhost;
|
||||
if (last == NULL
|
||||
|| (nuser != NULL && nuser > last))
|
||||
last = nuser;
|
||||
if (last == NULL
|
||||
|| (ndomain != NULL && ndomain > last))
|
||||
last = ndomain;
|
||||
|
||||
size_t bufused
|
||||
= (last == NULL
|
||||
? buffilled
|
||||
: last + strlen (last) + 1 - buffer);
|
||||
|
||||
/* We have to make temporary copies. */
|
||||
size_t needed = hostlen + userlen + domainlen;
|
||||
|
||||
if (buflen - req->key_len - bufused < needed)
|
||||
{
|
||||
buflen += MAX (buflen, 2 * needed);
|
||||
/* Save offset in the old buffer. We don't
|
||||
bother with the NULL check here since
|
||||
we'll do that later anyway. */
|
||||
size_t nhostdiff = nhost - buffer;
|
||||
size_t nuserdiff = nuser - buffer;
|
||||
size_t ndomaindiff = ndomain - buffer;
|
||||
|
||||
char *newbuf = xrealloc (buffer, buflen);
|
||||
/* Fix up the triplet pointers into the new
|
||||
buffer. */
|
||||
nhost = (nhost ? newbuf + nhostdiff
|
||||
: NULL);
|
||||
nuser = (nuser ? newbuf + nuserdiff
|
||||
: NULL);
|
||||
ndomain = (ndomain ? newbuf + ndomaindiff
|
||||
: NULL);
|
||||
buffer = newbuf;
|
||||
}
|
||||
|
||||
nhost = memcpy (buffer + bufused,
|
||||
nhost ?: "", hostlen);
|
||||
nuser = memcpy ((char *) nhost + hostlen,
|
||||
nuser ?: "", userlen);
|
||||
ndomain = memcpy ((char *) nuser + userlen,
|
||||
ndomain ?: "", domainlen);
|
||||
}
|
||||
|
||||
char *wp = buffer + buffilled;
|
||||
wp = memmove (wp, nhost ?: "", hostlen);
|
||||
wp += hostlen;
|
||||
wp = memmove (wp, nuser ?: "", userlen);
|
||||
wp += userlen;
|
||||
wp = memmove (wp, ndomain ?: "", domainlen);
|
||||
wp += domainlen;
|
||||
buffilled = wp - buffer;
|
||||
if (!(addgetnetgrentX_append (scratch, nhost)
|
||||
&& addgetnetgrentX_append (scratch, nuser)
|
||||
&& addgetnetgrentX_append (scratch, ndomain)))
|
||||
return send_notfound (fd);
|
||||
++nentries;
|
||||
}
|
||||
else
|
||||
@@ -318,8 +331,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
}
|
||||
else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
|
||||
{
|
||||
buflen *= 2;
|
||||
buffer = xrealloc (buffer, buflen);
|
||||
if (!scratch_buffer_grow (&scratch->tmp))
|
||||
return send_notfound (fd);
|
||||
}
|
||||
else if (status == NSS_STATUS_RETURN
|
||||
|| status == NSS_STATUS_NOTFOUND
|
||||
@@ -349,13 +362,20 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
{
|
||||
cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout,
|
||||
&key_copy);
|
||||
goto writeout;
|
||||
goto maybe_cache_add;
|
||||
}
|
||||
|
||||
total = buffilled;
|
||||
/* Capture the result size without the key appended. */
|
||||
total = scratch->buffer_used;
|
||||
|
||||
/* Make a copy of the key. The scratch buffer must not move after
|
||||
this point. */
|
||||
key_copy = addgetnetgrentX_append_n (scratch, key, req->key_len);
|
||||
if (key_copy == NULL)
|
||||
return send_notfound (fd);
|
||||
|
||||
/* Fill in the dataset. */
|
||||
dataset = (struct dataset *) buffer;
|
||||
dataset = scratch->buffer.data;
|
||||
timeout = datahead_init_pos (&dataset->head, total + req->key_len,
|
||||
total - offsetof (struct dataset, resp),
|
||||
he == NULL ? 0 : dh->nreloads + 1,
|
||||
@@ -364,11 +384,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
dataset->resp.version = NSCD_VERSION;
|
||||
dataset->resp.found = 1;
|
||||
dataset->resp.nresults = nentries;
|
||||
dataset->resp.result_len = buffilled - sizeof (*dataset);
|
||||
|
||||
assert (buflen - buffilled >= req->key_len);
|
||||
key_copy = memcpy (buffer + buffilled, key, req->key_len);
|
||||
buffilled += req->key_len;
|
||||
dataset->resp.result_len = total - sizeof (*dataset);
|
||||
|
||||
/* Now we can determine whether on refill we have to create a new
|
||||
record or not. */
|
||||
@@ -399,7 +415,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
if (__glibc_likely (newp != NULL))
|
||||
{
|
||||
/* Adjust pointer into the memory block. */
|
||||
key_copy = (char *) newp + (key_copy - buffer);
|
||||
key_copy = (char *) newp + (key_copy - (char *) dataset);
|
||||
|
||||
dataset = memcpy (newp, dataset, total + req->key_len);
|
||||
cacheable = true;
|
||||
@@ -411,14 +427,12 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
}
|
||||
|
||||
if (he == NULL && fd != -1)
|
||||
{
|
||||
/* We write the dataset before inserting it to the database
|
||||
since while inserting this thread might block and so would
|
||||
unnecessarily let the receiver wait. */
|
||||
writeout:
|
||||
/* We write the dataset before inserting it to the database since
|
||||
while inserting this thread might block and so would
|
||||
unnecessarily let the receiver wait. */
|
||||
writeall (fd, &dataset->resp, dataset->head.recsize);
|
||||
}
|
||||
|
||||
maybe_cache_add:
|
||||
if (cacheable)
|
||||
{
|
||||
/* If necessary, we also propagate the data to disk. */
|
||||
@@ -442,7 +456,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||
}
|
||||
|
||||
out:
|
||||
*resultp = dataset;
|
||||
scratch->dataset = dataset;
|
||||
|
||||
return timeout;
|
||||
}
|
||||
@@ -463,6 +477,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
if (user != NULL)
|
||||
key = (char *) rawmemchr (key, '\0') + 1;
|
||||
const char *domain = *key++ ? key : NULL;
|
||||
struct addgetnetgrentX_scratch scratch;
|
||||
|
||||
addgetnetgrentX_scratch_init (&scratch);
|
||||
|
||||
if (__glibc_unlikely (debug_level > 0))
|
||||
{
|
||||
@@ -478,12 +495,8 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
group, group_len,
|
||||
db, uid);
|
||||
time_t timeout;
|
||||
void *tofree;
|
||||
if (result != NULL)
|
||||
{
|
||||
timeout = result->head.timeout;
|
||||
tofree = NULL;
|
||||
}
|
||||
timeout = result->head.timeout;
|
||||
else
|
||||
{
|
||||
request_header req_get =
|
||||
@@ -492,7 +505,10 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
.key_len = group_len
|
||||
};
|
||||
timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
|
||||
&result, &tofree);
|
||||
&scratch);
|
||||
result = scratch.dataset;
|
||||
if (timeout < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
struct indataset
|
||||
@@ -503,24 +519,26 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
= (struct indataset *) mempool_alloc (db,
|
||||
sizeof (*dataset) + req->key_len,
|
||||
1);
|
||||
struct indataset dataset_mem;
|
||||
bool cacheable = true;
|
||||
if (__glibc_unlikely (dataset == NULL))
|
||||
{
|
||||
cacheable = false;
|
||||
dataset = &dataset_mem;
|
||||
/* The alloca is safe because nscd_run_worker verfies that
|
||||
key_len is not larger than MAXKEYLEN. */
|
||||
dataset = alloca (sizeof (*dataset) + req->key_len);
|
||||
}
|
||||
|
||||
datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len,
|
||||
sizeof (innetgroup_response_header),
|
||||
he == NULL ? 0 : dh->nreloads + 1, result->head.ttl);
|
||||
he == NULL ? 0 : dh->nreloads + 1,
|
||||
result == NULL ? db->negtimeout : result->head.ttl);
|
||||
/* Set the notfound status and timeout based on the result from
|
||||
getnetgrent. */
|
||||
dataset->head.notfound = result->head.notfound;
|
||||
dataset->head.notfound = result == NULL || result->head.notfound;
|
||||
dataset->head.timeout = timeout;
|
||||
|
||||
dataset->resp.version = NSCD_VERSION;
|
||||
dataset->resp.found = result->resp.found;
|
||||
dataset->resp.found = result != NULL && result->resp.found;
|
||||
/* Until we find a matching entry the result is 0. */
|
||||
dataset->resp.result = 0;
|
||||
|
||||
@@ -568,7 +586,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (he == NULL)
|
||||
/* addgetnetgrentX may have already sent a notfound response. Do
|
||||
not send another one. */
|
||||
if (he == NULL && dataset->resp.found)
|
||||
{
|
||||
/* We write the dataset before inserting it to the database
|
||||
since while inserting this thread might block and so would
|
||||
@@ -602,7 +622,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||
}
|
||||
|
||||
out:
|
||||
free (tofree);
|
||||
addgetnetgrentX_scratch_free (&scratch);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
@@ -612,11 +632,12 @@ addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req,
|
||||
const char *key, uid_t uid, struct hashentry *he,
|
||||
struct datahead *dh)
|
||||
{
|
||||
struct dataset *ignore;
|
||||
void *tofree;
|
||||
time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh,
|
||||
&ignore, &tofree);
|
||||
free (tofree);
|
||||
struct addgetnetgrentX_scratch scratch;
|
||||
addgetnetgrentX_scratch_init (&scratch);
|
||||
time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, &scratch);
|
||||
addgetnetgrentX_scratch_free (&scratch);
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
return timeout;
|
||||
}
|
||||
|
||||
@@ -660,5 +681,9 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he,
|
||||
.key_len = he->len
|
||||
};
|
||||
|
||||
return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
|
||||
time_t timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner,
|
||||
he, dh);
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
return timeout;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
hosts: files
|
||||
+14
-4
@@ -102,7 +102,9 @@ tests := test-errno tstgetopt testfnm runtests runptests \
|
||||
tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
|
||||
tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
|
||||
bug-regex38 tst-regcomp-truncated tst-spawn-chdir \
|
||||
tst-wordexp-nocmd
|
||||
tst-wordexp-nocmd tst-regcomp-bracket-free \
|
||||
tst-wordexp-reuse
|
||||
|
||||
tests-internal := bug-regex5 bug-regex20 bug-regex33 \
|
||||
tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \
|
||||
tst-glob_lstat_compat tst-spawn4-compat
|
||||
@@ -135,11 +137,13 @@ generated += $(addprefix wordexp-test-result, 1 2 3 4 5 6 7 8 9 10) \
|
||||
bug-glob2.mtrace bug-glob2-mem.out tst-vfork3-mem.out \
|
||||
tst-vfork3.mtrace getconf.speclist tst-fnmatch-mem.out \
|
||||
tst-fnmatch.mtrace bug-regex36.mtrace \
|
||||
testcases.h ptestcases.h
|
||||
testcases.h ptestcases.h tst-wordexp-reuse-mem.out \
|
||||
tst-wordexp-reuse.mtrace
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
ifeq (yes,$(build-shared))
|
||||
tests-special += $(objpfx)globtest.out $(objpfx)wordexp-tst.out
|
||||
tests-special += $(objpfx)globtest.out $(objpfx)wordexp-tst.out \
|
||||
$(objpfx)wordexp-tst.out
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -153,7 +157,7 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
|
||||
$(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
|
||||
$(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
|
||||
$(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \
|
||||
$(objpfx)tst-glob-tilde-mem.out
|
||||
$(objpfx)tst-glob-tilde-mem.out $(objpfx)tst-wordexp-reuse.out
|
||||
xtests-special += $(objpfx)bug-ga2-mem.out
|
||||
endif
|
||||
|
||||
@@ -398,3 +402,9 @@ $(objpfx)posix-conf-vars-def.h: $(..)scripts/gen-posix-conf-vars.awk \
|
||||
$(make-target-directory)
|
||||
$(AWK) -f $(filter-out Makefile, $^) > $@.tmp
|
||||
mv -f $@.tmp $@
|
||||
|
||||
tst-wordexp-reuse-ENV += MALLOC_TRACE=$(objpfx)tst-wordexp-reuse.mtrace
|
||||
|
||||
$(objpfx)tst-wordexp-reuse-mem.out: $(objpfx)tst-wordexp-reuse.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-wordexp-reuse.mtrace > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
+2
-3
@@ -193,10 +193,9 @@ __NTH (readlinkat (int __fd, const char *__restrict __path,
|
||||
#endif
|
||||
|
||||
extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen)
|
||||
__THROW __wur __attr_access ((__write_only__, 1, 2));
|
||||
__THROW __wur;
|
||||
extern char *__REDIRECT_NTH (__getcwd_alias,
|
||||
(char *__buf, size_t __size), getcwd)
|
||||
__wur __attr_access ((__write_only__, 1, 2));
|
||||
(char *__buf, size_t __size), getcwd) __wur;
|
||||
extern char *__REDIRECT_NTH (__getcwd_chk_warn,
|
||||
(char *__buf, size_t __size, size_t __buflen),
|
||||
__getcwd_chk)
|
||||
|
||||
+3
-1
@@ -3367,6 +3367,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
|
||||
{
|
||||
#ifdef RE_ENABLE_I18N
|
||||
free_charset (mbcset);
|
||||
mbcset = NULL;
|
||||
#endif
|
||||
/* Build a tree for simple bracket. */
|
||||
br_token.type = SIMPLE_BRACKET;
|
||||
@@ -3382,7 +3383,8 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
|
||||
parse_bracket_exp_free_return:
|
||||
re_free (sbcset);
|
||||
#ifdef RE_ENABLE_I18N
|
||||
free_charset (mbcset);
|
||||
if (__glibc_likely (mbcset != NULL))
|
||||
free_charset (mbcset);
|
||||
#endif /* RE_ENABLE_I18N */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/* Test regcomp bracket parsing with injected allocation failures (bug 33185).
|
||||
Copyright (C) 2025 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/>. */
|
||||
|
||||
/* This test invokes regcomp multiple times, failing one memory
|
||||
allocation in each call. The function call should fail with
|
||||
REG_ESPACE (or succeed if it can recover from the allocation
|
||||
failure). Previously, there was double-free bug. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/namespace.h>
|
||||
#include <support/support.h>
|
||||
|
||||
/* Data structure allocated via MAP_SHARED, so that writes from the
|
||||
subprocess are visible. */
|
||||
struct shared_data
|
||||
{
|
||||
/* Number of tracked allocations performed so far. */
|
||||
volatile unsigned int allocation_count;
|
||||
|
||||
/* If this number is reached, one allocation fails. */
|
||||
volatile unsigned int failing_allocation;
|
||||
|
||||
/* The subprocess stores the expected name here. */
|
||||
char name[100];
|
||||
};
|
||||
|
||||
/* Allocation count in shared mapping. */
|
||||
static struct shared_data *shared;
|
||||
|
||||
/* Returns true if a failure should be injected for this allocation. */
|
||||
static bool
|
||||
fail_this_allocation (void)
|
||||
{
|
||||
if (shared != NULL)
|
||||
{
|
||||
unsigned int count = shared->allocation_count;
|
||||
shared->allocation_count = count + 1;
|
||||
return count == shared->failing_allocation;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Failure-injecting wrappers for allocation functions used by glibc. */
|
||||
|
||||
void *
|
||||
malloc (size_t size)
|
||||
{
|
||||
if (fail_this_allocation ())
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
extern __typeof (malloc) __libc_malloc;
|
||||
return __libc_malloc (size);
|
||||
}
|
||||
|
||||
void *
|
||||
calloc (size_t a, size_t b)
|
||||
{
|
||||
if (fail_this_allocation ())
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
extern __typeof (calloc) __libc_calloc;
|
||||
return __libc_calloc (a, b);
|
||||
}
|
||||
|
||||
void *
|
||||
realloc (void *ptr, size_t size)
|
||||
{
|
||||
if (fail_this_allocation ())
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
extern __typeof (realloc) __libc_realloc;
|
||||
return __libc_realloc (ptr, size);
|
||||
}
|
||||
|
||||
/* No-op subprocess to verify that support_isolate_in_subprocess does
|
||||
not perform any heap allocations. */
|
||||
static void
|
||||
no_op (void *ignored)
|
||||
{
|
||||
}
|
||||
|
||||
/* Perform a regcomp call in a subprocess. Used to count its
|
||||
allocations. */
|
||||
static void
|
||||
initialize (void *regexp1)
|
||||
{
|
||||
const char *regexp = regexp1;
|
||||
|
||||
shared->allocation_count = 0;
|
||||
|
||||
regex_t reg;
|
||||
TEST_COMPARE (regcomp (®, regexp, 0), 0);
|
||||
}
|
||||
|
||||
/* Perform regcomp in a subprocess with fault injection. */
|
||||
static void
|
||||
test_in_subprocess (void *regexp1)
|
||||
{
|
||||
const char *regexp = regexp1;
|
||||
unsigned int inject_at = shared->failing_allocation;
|
||||
|
||||
regex_t reg;
|
||||
int ret = regcomp (®, regexp, 0);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
TEST_COMPARE (ret, REG_ESPACE);
|
||||
printf ("info: allocation %u failure results in return value %d,"
|
||||
" error %s (%d)\n",
|
||||
inject_at, ret, strerrorname_np (errno), errno);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char regexp[] = "[:alpha:]";
|
||||
|
||||
shared = support_shared_allocate (sizeof (*shared));
|
||||
|
||||
/* Disable fault injection. */
|
||||
shared->failing_allocation = ~0U;
|
||||
|
||||
support_isolate_in_subprocess (no_op, NULL);
|
||||
TEST_COMPARE (shared->allocation_count, 0);
|
||||
|
||||
support_isolate_in_subprocess (initialize, regexp);
|
||||
|
||||
/* The number of allocations in the successful case, plus some
|
||||
slack. Once the number of expected allocations is exceeded,
|
||||
injecting further failures does not make a difference. */
|
||||
unsigned int maximum_allocation_count = shared->allocation_count;
|
||||
printf ("info: successful call performs %u allocations\n",
|
||||
maximum_allocation_count);
|
||||
maximum_allocation_count += 10;
|
||||
|
||||
for (unsigned int inject_at = 0; inject_at <= maximum_allocation_count;
|
||||
++inject_at)
|
||||
{
|
||||
shared->allocation_count = 0;
|
||||
shared->failing_allocation = inject_at;
|
||||
support_isolate_in_subprocess (test_in_subprocess, regexp);
|
||||
}
|
||||
|
||||
support_shared_free (shared);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,89 @@
|
||||
/* Test for wordexp with WRDE_REUSE flag.
|
||||
Copyright (C) 2026 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 <wordexp.h>
|
||||
#include <mcheck.h>
|
||||
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
mtrace ();
|
||||
|
||||
{
|
||||
wordexp_t p = { 0 };
|
||||
TEST_COMPARE (wordexp ("one", &p, 0), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[0], "one");
|
||||
TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[0], "two");
|
||||
wordfree (&p);
|
||||
}
|
||||
|
||||
{
|
||||
wordexp_t p = { .we_offs = 2 };
|
||||
TEST_COMPARE (wordexp ("one", &p, 0), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[0], "one");
|
||||
TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE | WRDE_DOOFFS), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
|
||||
wordfree (&p);
|
||||
}
|
||||
|
||||
{
|
||||
wordexp_t p = { 0 };
|
||||
TEST_COMPARE (wordexp ("one", &p, 0), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[0], "one");
|
||||
TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE | WRDE_APPEND), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[0], "two");
|
||||
wordfree (&p);
|
||||
}
|
||||
|
||||
{
|
||||
wordexp_t p = { .we_offs = 2 };
|
||||
TEST_COMPARE (wordexp ("one", &p, WRDE_DOOFFS), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "one");
|
||||
TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE
|
||||
| WRDE_DOOFFS), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
|
||||
wordfree (&p);
|
||||
}
|
||||
|
||||
{
|
||||
wordexp_t p = { .we_offs = 2 };
|
||||
TEST_COMPARE (wordexp ("one", &p, WRDE_DOOFFS), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "one");
|
||||
TEST_COMPARE (wordexp ("two", &p, WRDE_REUSE
|
||||
| WRDE_DOOFFS | WRDE_APPEND), 0);
|
||||
TEST_COMPARE (p.we_wordc, 1);
|
||||
TEST_COMPARE_STRING (p.we_wordv[p.we_offs + 0], "two");
|
||||
wordfree (&p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+2
-3
@@ -517,8 +517,7 @@ extern int fchdir (int __fd) __THROW __wur;
|
||||
an array is allocated with `malloc'; the array is SIZE
|
||||
bytes long, unless SIZE == 0, in which case it is as
|
||||
big as necessary. */
|
||||
extern char *getcwd (char *__buf, size_t __size) __THROW __wur
|
||||
__attr_access ((__write_only__, 1, 2));
|
||||
extern char *getcwd (char *__buf, size_t __size) __THROW __wur;
|
||||
|
||||
#ifdef __USE_GNU
|
||||
/* Return a malloc'd string containing the current directory name.
|
||||
@@ -831,7 +830,7 @@ extern int symlinkat (const char *__from, int __tofd,
|
||||
/* Like readlink but a relative PATH is interpreted relative to FD. */
|
||||
extern ssize_t readlinkat (int __fd, const char *__restrict __path,
|
||||
char *__restrict __buf, size_t __len)
|
||||
__THROW __nonnull ((2, 3)) __wur __attr_access ((__read_only__, 3, 4));
|
||||
__THROW __nonnull ((2, 3)) __wur __attr_access ((__write_only__, 3, 4));
|
||||
#endif
|
||||
|
||||
/* Remove the link NAME. */
|
||||
|
||||
@@ -183,6 +183,7 @@ struct test_case_struct
|
||||
{ 0, NULL, "$var", 0, 0, { NULL, }, IFS },
|
||||
{ 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS },
|
||||
{ 0, NULL, "", 0, 0, { NULL, }, IFS },
|
||||
{ 0, NULL, "${1234567890123456789012}", 0, 0, { NULL, }, IFS },
|
||||
|
||||
/* Flags not already covered (testit() has special handling for these) */
|
||||
{ 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS },
|
||||
|
||||
+3
-1
@@ -1399,7 +1399,7 @@ envsubst:
|
||||
/* Is it a numeric parameter? */
|
||||
else if (isdigit (env[0]))
|
||||
{
|
||||
int n = atoi (env);
|
||||
unsigned long n = strtoul (env, NULL, 10);
|
||||
|
||||
if (n >= __libc_argc)
|
||||
/* Substitute NULL. */
|
||||
@@ -2220,7 +2220,9 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
{
|
||||
/* Minimal implementation of WRDE_REUSE for now */
|
||||
wordfree (pwordexp);
|
||||
old_word.we_wordc = 0;
|
||||
old_word.we_wordv = NULL;
|
||||
pwordexp->we_wordc = 0;
|
||||
}
|
||||
|
||||
if ((flags & WRDE_APPEND) == 0)
|
||||
|
||||
@@ -61,6 +61,11 @@ tests += \
|
||||
tst-resolv-search \
|
||||
tst-resolv-trailing \
|
||||
|
||||
# This test calls __res_context_send directly, which is not exported
|
||||
# from libresolv.
|
||||
tests-internal += tst-resolv-txnid-collision
|
||||
tests-static += tst-resolv-txnid-collision
|
||||
|
||||
# These tests need libdl.
|
||||
ifeq (yes,$(build-shared))
|
||||
tests += \
|
||||
@@ -191,6 +196,8 @@ $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-threads: \
|
||||
$(libdl) $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \
|
||||
$(static-thread-library)
|
||||
$(objpfx)tst-resolv-canonname: \
|
||||
$(libdl) $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-trustad: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
|
||||
@@ -209,6 +209,10 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
|
||||
sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
|
||||
net_bytes[1], net_bytes[0]);
|
||||
break;
|
||||
default:
|
||||
/* Default network (net is originally zero). */
|
||||
strcpy (qbuf, "0.0.0.0.in-addr.arpa");
|
||||
break;
|
||||
}
|
||||
|
||||
net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
|
||||
|
||||
+20
-20
@@ -1342,15 +1342,6 @@ send_dg(res_state statp,
|
||||
*terrno = EMSGSIZE;
|
||||
return close_and_return_error (statp, resplen2);
|
||||
}
|
||||
if ((recvresp1 || hp->id != anhp->id)
|
||||
&& (recvresp2 || hp2->id != anhp->id)) {
|
||||
/*
|
||||
* response from old query, ignore it.
|
||||
* XXX - potential security hazard could
|
||||
* be detected here.
|
||||
*/
|
||||
goto wait;
|
||||
}
|
||||
|
||||
/* Paranoia check. Due to the connected UDP socket,
|
||||
the kernel has already filtered invalid addresses
|
||||
@@ -1360,15 +1351,24 @@ send_dg(res_state statp,
|
||||
|
||||
/* Check for the correct header layout and a matching
|
||||
question. */
|
||||
if ((recvresp1 || !res_queriesmatch(buf, buf + buflen,
|
||||
*thisansp,
|
||||
*thisansp
|
||||
+ *thisanssizp))
|
||||
&& (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
|
||||
*thisansp,
|
||||
*thisansp
|
||||
+ *thisanssizp)))
|
||||
goto wait;
|
||||
int matching_query = 0; /* Default to no matching query. */
|
||||
if (!recvresp1
|
||||
&& anhp->id == hp->id
|
||||
&& res_queriesmatch (buf, buf + buflen,
|
||||
*thisansp, *thisansp + *thisanssizp))
|
||||
matching_query = 1;
|
||||
if (!recvresp2
|
||||
&& anhp->id == hp2->id
|
||||
&& res_queriesmatch (buf2, buf2 + buflen2,
|
||||
*thisansp, *thisansp + *thisanssizp))
|
||||
matching_query = 2;
|
||||
if (matching_query == 0)
|
||||
/* Spurious UDP packet. Drop it and continue
|
||||
waiting. */
|
||||
{
|
||||
need_recompute = 1;
|
||||
goto wait;
|
||||
}
|
||||
|
||||
if (anhp->rcode == SERVFAIL ||
|
||||
anhp->rcode == NOTIMP ||
|
||||
@@ -1383,7 +1383,7 @@ send_dg(res_state statp,
|
||||
/* No data from the first reply. */
|
||||
resplen = 0;
|
||||
/* We are waiting for a possible second reply. */
|
||||
if (hp->id == anhp->id)
|
||||
if (matching_query == 1)
|
||||
recvresp1 = 1;
|
||||
else
|
||||
recvresp2 = 1;
|
||||
@@ -1414,7 +1414,7 @@ send_dg(res_state statp,
|
||||
return (1);
|
||||
}
|
||||
/* Mark which reply we received. */
|
||||
if (recvresp1 == 0 && hp->id == anhp->id)
|
||||
if (matching_query == 1)
|
||||
recvresp1 = 1;
|
||||
else
|
||||
recvresp2 = 1;
|
||||
|
||||
@@ -46,6 +46,9 @@ handle_code (const struct resolv_response_context *ctx,
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0:
|
||||
send_ptr (b, qname, qclass, qtype, "0.in-addr.arpa");
|
||||
break;
|
||||
case 1:
|
||||
send_ptr (b, qname, qclass, qtype, "1.in-addr.arpa");
|
||||
break;
|
||||
@@ -265,6 +268,9 @@ do_test (void)
|
||||
"error: TRY_AGAIN\n");
|
||||
|
||||
/* Lookup by address, success cases. */
|
||||
check_reverse (0,
|
||||
"name: 0.in-addr.arpa\n"
|
||||
"net: 0x00000000\n");
|
||||
check_reverse (1,
|
||||
"name: 1.in-addr.arpa\n"
|
||||
"net: 0x00000001\n");
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
/* Test parallel queries with transaction ID collisions.
|
||||
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 <arpa/nameser.h>
|
||||
#include <array_length.h>
|
||||
#include <resolv-internal.h>
|
||||
#include <resolv_context.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/check_nss.h>
|
||||
#include <support/resolv_test.h>
|
||||
#include <support/support.h>
|
||||
#include <support/test-driver.h>
|
||||
|
||||
/* Result of parsing a DNS question name.
|
||||
|
||||
A question name has the form reorder-N-M-rcode-C.example.net, where
|
||||
N and M are either 0 and 1, corresponding to the reorder member,
|
||||
and C is a number that will be stored in the rcode field.
|
||||
|
||||
Also see parse_qname below. */
|
||||
struct parsed_qname
|
||||
{
|
||||
/* The DNS response code requested from the first server. The
|
||||
second server always responds with RCODE zero. */
|
||||
int rcode;
|
||||
|
||||
/* Indicates whether to perform reordering in the responses from the
|
||||
respective server. */
|
||||
bool reorder[2];
|
||||
};
|
||||
|
||||
/* Fills *PARSED based on QNAME. */
|
||||
static void
|
||||
parse_qname (struct parsed_qname *parsed, const char *qname)
|
||||
{
|
||||
int reorder0;
|
||||
int reorder1;
|
||||
int rcode;
|
||||
char *suffix;
|
||||
if (sscanf (qname, "reorder-%d-%d.rcode-%d.%ms",
|
||||
&reorder0, &reorder1, &rcode, &suffix) == 4)
|
||||
{
|
||||
if (reorder0 != 0)
|
||||
TEST_COMPARE (reorder0, 1);
|
||||
if (reorder1 != 0)
|
||||
TEST_COMPARE (reorder1, 1);
|
||||
TEST_VERIFY (rcode >= 0 && rcode <= 15);
|
||||
TEST_COMPARE_STRING (suffix, "example.net");
|
||||
free (suffix);
|
||||
|
||||
parsed->rcode = rcode;
|
||||
parsed->reorder[0] = reorder0;
|
||||
parsed->reorder[1] = reorder1;
|
||||
}
|
||||
else
|
||||
FAIL_EXIT1 ("unexpected query: %s", qname);
|
||||
}
|
||||
|
||||
/* Used to construct a response. The first server responds with an
|
||||
error, the second server succeeds. */
|
||||
static void
|
||||
build_response (const struct resolv_response_context *ctx,
|
||||
struct resolv_response_builder *b,
|
||||
const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
{
|
||||
struct parsed_qname parsed;
|
||||
parse_qname (&parsed, qname);
|
||||
|
||||
switch (ctx->server_index)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
struct resolv_response_flags flags = { 0 };
|
||||
if (parsed.rcode == 0)
|
||||
/* Simulate a delegation in case a NODATA (RCODE zero)
|
||||
response is requested. */
|
||||
flags.clear_ra = true;
|
||||
else
|
||||
flags.rcode = parsed.rcode;
|
||||
|
||||
resolv_response_init (b, flags);
|
||||
resolv_response_add_question (b, qname, qclass, qtype);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
struct resolv_response_flags flags = { 0, };
|
||||
resolv_response_init (b, flags);
|
||||
resolv_response_add_question (b, qname, qclass, qtype);
|
||||
|
||||
resolv_response_section (b, ns_s_an);
|
||||
resolv_response_open_record (b, qname, qclass, qtype, 0);
|
||||
if (qtype == T_A)
|
||||
{
|
||||
char ipv4[4] = { 192, 0, 2, 1 };
|
||||
resolv_response_add_data (b, &ipv4, sizeof (ipv4));
|
||||
}
|
||||
else
|
||||
{
|
||||
char ipv6[16]
|
||||
= { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||
resolv_response_add_data (b, &ipv6, sizeof (ipv6));
|
||||
}
|
||||
resolv_response_close_record (b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Used to reorder responses. */
|
||||
struct resolv_response_context *previous_query;
|
||||
|
||||
/* Used to keep track of the queries received. */
|
||||
static int previous_server_index = -1;
|
||||
static uint16_t previous_qtype;
|
||||
|
||||
/* For each server, buffer the first query and then send both answers
|
||||
to the second query, reordered if requested. */
|
||||
static void
|
||||
response (const struct resolv_response_context *ctx,
|
||||
struct resolv_response_builder *b,
|
||||
const char *qname, uint16_t qclass, uint16_t qtype)
|
||||
{
|
||||
TEST_VERIFY (qtype == T_A || qtype == T_AAAA);
|
||||
if (ctx->server_index != 0)
|
||||
TEST_COMPARE (ctx->server_index, 1);
|
||||
|
||||
struct parsed_qname parsed;
|
||||
parse_qname (&parsed, qname);
|
||||
|
||||
if (previous_query == NULL)
|
||||
{
|
||||
/* No buffered query. Record this query and do not send a
|
||||
response. */
|
||||
TEST_COMPARE (previous_qtype, 0);
|
||||
previous_query = resolv_response_context_duplicate (ctx);
|
||||
previous_qtype = qtype;
|
||||
resolv_response_drop (b);
|
||||
previous_server_index = ctx->server_index;
|
||||
|
||||
if (test_verbose)
|
||||
printf ("info: buffering first query for: %s\n", qname);
|
||||
}
|
||||
else
|
||||
{
|
||||
TEST_VERIFY (previous_query != 0);
|
||||
TEST_COMPARE (ctx->server_index, previous_server_index);
|
||||
TEST_VERIFY (previous_qtype != qtype); /* Not a duplicate. */
|
||||
|
||||
/* If reordering, send a response for this query explicitly, and
|
||||
then skip the implicit send. */
|
||||
if (parsed.reorder[ctx->server_index])
|
||||
{
|
||||
if (test_verbose)
|
||||
printf ("info: sending reordered second response for: %s\n",
|
||||
qname);
|
||||
build_response (ctx, b, qname, qclass, qtype);
|
||||
resolv_response_send_udp (ctx, b);
|
||||
resolv_response_drop (b);
|
||||
}
|
||||
|
||||
/* Build a response for the previous query and send it, thus
|
||||
reordering the two responses. */
|
||||
{
|
||||
if (test_verbose)
|
||||
printf ("info: sending first response for: %s\n", qname);
|
||||
struct resolv_response_builder *btmp
|
||||
= resolv_response_builder_allocate (previous_query->query_buffer,
|
||||
previous_query->query_length);
|
||||
build_response (ctx, btmp, qname, qclass, previous_qtype);
|
||||
resolv_response_send_udp (ctx, btmp);
|
||||
resolv_response_builder_free (btmp);
|
||||
}
|
||||
|
||||
/* If not reordering, send the reply as usual. */
|
||||
if (!parsed.reorder[ctx->server_index])
|
||||
{
|
||||
if (test_verbose)
|
||||
printf ("info: sending non-reordered second response for: %s\n",
|
||||
qname);
|
||||
build_response (ctx, b, qname, qclass, qtype);
|
||||
}
|
||||
|
||||
/* Unbuffer the response and prepare for the next query. */
|
||||
resolv_response_context_free (previous_query);
|
||||
previous_query = NULL;
|
||||
previous_qtype = 0;
|
||||
previous_server_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Runs a query for QNAME and checks for the expected reply. See
|
||||
struct parsed_qname for the expected format for QNAME. */
|
||||
static void
|
||||
test_qname (const char *qname, int rcode)
|
||||
{
|
||||
struct resolv_context *ctx = __resolv_context_get ();
|
||||
TEST_VERIFY_EXIT (ctx != NULL);
|
||||
|
||||
unsigned char q1[512];
|
||||
int q1len = res_mkquery (QUERY, qname, C_IN, T_A, NULL, 0, NULL,
|
||||
q1, sizeof (q1));
|
||||
TEST_VERIFY_EXIT (q1len > 12);
|
||||
|
||||
unsigned char q2[512];
|
||||
int q2len = res_mkquery (QUERY, qname, C_IN, T_AAAA, NULL, 0, NULL,
|
||||
q2, sizeof (q2));
|
||||
TEST_VERIFY_EXIT (q2len > 12);
|
||||
|
||||
/* Produce a transaction ID collision. */
|
||||
memcpy (q2, q1, 2);
|
||||
|
||||
unsigned char ans1[512];
|
||||
unsigned char *ans1p = ans1;
|
||||
unsigned char *ans2p = NULL;
|
||||
int nans2p = 0;
|
||||
int resplen2 = 0;
|
||||
int ans2p_malloced = 0;
|
||||
|
||||
/* Perform a parallel A/AAAA query. */
|
||||
int resplen1 = __res_context_send (ctx, q1, q1len, q2, q2len,
|
||||
ans1, sizeof (ans1), &ans1p,
|
||||
&ans2p, &nans2p,
|
||||
&resplen2, &ans2p_malloced);
|
||||
|
||||
TEST_VERIFY (resplen1 > 12);
|
||||
TEST_VERIFY (resplen2 > 12);
|
||||
if (resplen1 <= 12 || resplen2 <= 12)
|
||||
return;
|
||||
|
||||
if (rcode == 1 || rcode == 3)
|
||||
{
|
||||
/* Format Error and Name Error responses does not trigger
|
||||
switching to the next server. */
|
||||
TEST_COMPARE (ans1p[3] & 0x0f, rcode);
|
||||
TEST_COMPARE (ans2p[3] & 0x0f, rcode);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The response should be successful. */
|
||||
TEST_COMPARE (ans1p[3] & 0x0f, 0);
|
||||
TEST_COMPARE (ans2p[3] & 0x0f, 0);
|
||||
|
||||
/* Due to bug 19691, the answer may not be in the slot matching the
|
||||
query. Assume that the AAAA response is the longer one. */
|
||||
unsigned char *a_answer;
|
||||
int a_answer_length;
|
||||
unsigned char *aaaa_answer;
|
||||
int aaaa_answer_length;
|
||||
if (resplen2 > resplen1)
|
||||
{
|
||||
a_answer = ans1p;
|
||||
a_answer_length = resplen1;
|
||||
aaaa_answer = ans2p;
|
||||
aaaa_answer_length = resplen2;
|
||||
}
|
||||
else
|
||||
{
|
||||
a_answer = ans2p;
|
||||
a_answer_length = resplen2;
|
||||
aaaa_answer = ans1p;
|
||||
aaaa_answer_length = resplen1;
|
||||
}
|
||||
|
||||
{
|
||||
char *expected = xasprintf ("name: %s\n"
|
||||
"address: 192.0.2.1\n",
|
||||
qname);
|
||||
check_dns_packet (qname, a_answer, a_answer_length, expected);
|
||||
free (expected);
|
||||
}
|
||||
{
|
||||
char *expected = xasprintf ("name: %s\n"
|
||||
"address: 2001:db8::1\n",
|
||||
qname);
|
||||
check_dns_packet (qname, aaaa_answer, aaaa_answer_length, expected);
|
||||
free (expected);
|
||||
}
|
||||
|
||||
if (ans2p_malloced)
|
||||
free (ans2p);
|
||||
|
||||
__resolv_context_put (ctx);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
struct resolv_test *aux = resolv_test_start
|
||||
((struct resolv_redirect_config)
|
||||
{
|
||||
.response_callback = response,
|
||||
|
||||
/* The response callback use global state (the previous_*
|
||||
variables), and query processing must therefore be
|
||||
serialized. */
|
||||
.single_thread_udp = true,
|
||||
});
|
||||
|
||||
for (int rcode = 0; rcode <= 5; ++rcode)
|
||||
for (int do_reorder_0 = 0; do_reorder_0 < 2; ++do_reorder_0)
|
||||
for (int do_reorder_1 = 0; do_reorder_1 < 2; ++do_reorder_1)
|
||||
{
|
||||
char *qname = xasprintf ("reorder-%d-%d.rcode-%d.example.net",
|
||||
do_reorder_0, do_reorder_1, rcode);
|
||||
test_qname (qname, rcode);
|
||||
free (qname);
|
||||
}
|
||||
|
||||
resolv_test_end (aux);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -44,6 +44,7 @@ tests := tst-shm tst-timer tst-timer2 \
|
||||
tst-aio7 tst-aio8 tst-aio9 tst-aio10 \
|
||||
tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
|
||||
tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
|
||||
tst-bz28213 \
|
||||
tst-timer3 tst-timer4 tst-timer5 \
|
||||
tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \
|
||||
tst-shm-cancel
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/* Bug 28213: test for NULL pointer dereference in mq_notify.
|
||||
Copyright (C) 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/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <mqueue.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static mqd_t m = -1;
|
||||
static const char msg[] = "hello";
|
||||
|
||||
static void
|
||||
check_bz28213_cb (union sigval sv)
|
||||
{
|
||||
char buf[sizeof (msg)];
|
||||
|
||||
(void) sv;
|
||||
|
||||
TEST_VERIFY_EXIT ((size_t) mq_receive (m, buf, sizeof (buf), NULL)
|
||||
== sizeof (buf));
|
||||
TEST_VERIFY_EXIT (memcmp (buf, msg, sizeof (buf)) == 0);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static void
|
||||
check_bz28213 (void)
|
||||
{
|
||||
struct sigevent sev;
|
||||
|
||||
memset (&sev, '\0', sizeof (sev));
|
||||
sev.sigev_notify = SIGEV_THREAD;
|
||||
sev.sigev_notify_function = check_bz28213_cb;
|
||||
|
||||
/* Step 1: Register & unregister notifier.
|
||||
Helper thread should receive NOTIFY_REMOVED notification.
|
||||
In a vulnerable version of glibc, NULL pointer dereference follows. */
|
||||
TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
|
||||
TEST_VERIFY_EXIT (mq_notify (m, NULL) == 0);
|
||||
|
||||
/* Step 2: Once again, register notification.
|
||||
Try to send one message.
|
||||
Test is considered successful, if the callback does exit (0). */
|
||||
TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
|
||||
TEST_VERIFY_EXIT (mq_send (m, msg, sizeof (msg), 1) == 0);
|
||||
|
||||
/* Wait... */
|
||||
pause ();
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
static const char m_name[] = "/bz28213_queue";
|
||||
struct mq_attr m_attr;
|
||||
|
||||
memset (&m_attr, '\0', sizeof (m_attr));
|
||||
m_attr.mq_maxmsg = 1;
|
||||
m_attr.mq_msgsize = sizeof (msg);
|
||||
|
||||
m = mq_open (m_name,
|
||||
O_RDWR | O_CREAT | O_EXCL,
|
||||
0600,
|
||||
&m_attr);
|
||||
|
||||
if (m < 0)
|
||||
{
|
||||
if (errno == ENOSYS)
|
||||
FAIL_UNSUPPORTED ("POSIX message queues are not implemented\n");
|
||||
FAIL_EXIT1 ("Failed to create POSIX message queue: %m\n");
|
||||
}
|
||||
|
||||
TEST_VERIFY_EXIT (mq_unlink (m_name) == 0);
|
||||
|
||||
check_bz28213 ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+5
-1
@@ -29,10 +29,14 @@ headers := sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \
|
||||
routines := accept bind connect getpeername getsockname getsockopt \
|
||||
listen recv recvfrom recvmsg send sendmsg sendto \
|
||||
setsockopt shutdown socket socketpair isfdtype opensock \
|
||||
sockatmark accept4 recvmmsg sendmmsg
|
||||
sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set
|
||||
|
||||
tests := tst-accept4
|
||||
|
||||
tests-internal := \
|
||||
tst-sockaddr_un_set \
|
||||
# tests-internal
|
||||
|
||||
aux := sa_len
|
||||
|
||||
include ../Rules
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Set the sun_path member of struct sockaddr_un.
|
||||
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 <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
int
|
||||
__sockaddr_un_set (struct sockaddr_un *addr, const char *pathname)
|
||||
{
|
||||
size_t name_length = strlen (pathname);
|
||||
|
||||
/* The kernel supports names of exactly sizeof (addr->sun_path)
|
||||
bytes, without a null terminator, but userspace does not; see the
|
||||
SUN_LEN macro. */
|
||||
if (name_length >= sizeof (addr->sun_path))
|
||||
{
|
||||
__set_errno (EINVAL); /* Error code used by the kernel. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr->sun_family = AF_UNIX;
|
||||
memcpy (addr->sun_path, pathname, name_length + 1);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Test the __sockaddr_un_set function.
|
||||
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/>. */
|
||||
|
||||
/* Re-compile the function because the version in libc is not
|
||||
exported. */
|
||||
#include "sockaddr_un_set.c"
|
||||
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
struct sockaddr_un sun;
|
||||
|
||||
memset (&sun, 0xcc, sizeof (sun));
|
||||
__sockaddr_un_set (&sun, "");
|
||||
TEST_COMPARE (sun.sun_family, AF_UNIX);
|
||||
TEST_COMPARE (__sockaddr_un_set (&sun, ""), 0);
|
||||
|
||||
memset (&sun, 0xcc, sizeof (sun));
|
||||
TEST_COMPARE (__sockaddr_un_set (&sun, "/example"), 0);
|
||||
TEST_COMPARE_STRING (sun.sun_path, "/example");
|
||||
|
||||
{
|
||||
char pathname[108]; /* Length of sun_path (ABI constant). */
|
||||
memset (pathname, 'x', sizeof (pathname));
|
||||
pathname[sizeof (pathname) - 1] = '\0';
|
||||
memset (&sun, 0xcc, sizeof (sun));
|
||||
TEST_COMPARE (__sockaddr_un_set (&sun, pathname), 0);
|
||||
TEST_COMPARE (sun.sun_family, AF_UNIX);
|
||||
TEST_COMPARE_STRING (sun.sun_path, pathname);
|
||||
}
|
||||
|
||||
{
|
||||
char pathname[109];
|
||||
memset (pathname, 'x', sizeof (pathname));
|
||||
pathname[sizeof (pathname) - 1] = '\0';
|
||||
memset (&sun, 0xcc, sizeof (sun));
|
||||
errno = 0;
|
||||
TEST_COMPARE (__sockaddr_un_set (&sun, pathname), -1);
|
||||
TEST_COMPARE (errno, EINVAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -69,7 +69,8 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
|
||||
tst-printf-bz25691 \
|
||||
tst-vfprintf-width-prec-alloc \
|
||||
tst-printf-fp-free \
|
||||
tst-printf-fp-leak
|
||||
tst-printf-fp-leak \
|
||||
test-strerr
|
||||
|
||||
|
||||
test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
|
||||
|
||||
@@ -20,9 +20,13 @@
|
||||
#include <libintl.h>
|
||||
#include <array_length.h>
|
||||
|
||||
#ifndef ERR_MAP
|
||||
# define ERR_MAP(n) n
|
||||
#endif
|
||||
|
||||
const char *const _sys_errlist_internal[] =
|
||||
{
|
||||
#define _S(n, str) [n] = str,
|
||||
#define _S(n, str) [ERR_MAP(n)] = str,
|
||||
#include <errlist.h>
|
||||
#undef _S
|
||||
};
|
||||
@@ -41,20 +45,21 @@ static const union sys_errname_t
|
||||
{
|
||||
#define MSGSTRFIELD1(line) str##line
|
||||
#define MSGSTRFIELD(line) MSGSTRFIELD1(line)
|
||||
#define _S(n, str) char MSGSTRFIELD(__LINE__)[sizeof(str)];
|
||||
#define _S(n, str) char MSGSTRFIELD(__LINE__)[sizeof(#n)];
|
||||
#include <errlist.h>
|
||||
#undef _S
|
||||
};
|
||||
char str[0];
|
||||
} _sys_errname = { {
|
||||
#define _S(n, s) s,
|
||||
#define _S(n, s) #n,
|
||||
#include <errlist.h>
|
||||
#undef _S
|
||||
} };
|
||||
|
||||
static const unsigned short _sys_errnameidx[] =
|
||||
{
|
||||
#define _S(n, s) [n] = offsetof(union sys_errname_t, MSGSTRFIELD(__LINE__)),
|
||||
#define _S(n, s) \
|
||||
[ERR_MAP(n)] = offsetof(union sys_errname_t, MSGSTRFIELD(__LINE__)),
|
||||
#include <errlist.h>
|
||||
#undef _S
|
||||
};
|
||||
|
||||
+658
-32
@@ -18,46 +18,672 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <array_length.h>
|
||||
|
||||
#include <support/support.h>
|
||||
#include <support/check.h>
|
||||
|
||||
#define N_(name) name
|
||||
|
||||
static const char *const errlist[] =
|
||||
{
|
||||
/* This file is auto-generated from errlist.def. */
|
||||
#include <errlist.h>
|
||||
};
|
||||
|
||||
#define MSGSTR_T errname_t
|
||||
#define MSGSTR errname
|
||||
#define MSGIDX errnameidx
|
||||
#include <errlist-name.h>
|
||||
#undef MSGSTR
|
||||
#undef MSGIDX
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
TEST_VERIFY (strerrordesc_np (-1) == NULL);
|
||||
TEST_VERIFY (strerrordesc_np (array_length (errlist)) == NULL);
|
||||
for (size_t i = 0; i < array_length (errlist); i++)
|
||||
{
|
||||
if (errlist[i] == NULL)
|
||||
continue;
|
||||
TEST_COMPARE_STRING (strerrordesc_np (i), errlist[i]);
|
||||
}
|
||||
TEST_COMPARE_STRING (strerrordesc_np (0), "Success");
|
||||
TEST_COMPARE_STRING (strerrorname_np (0), "0");
|
||||
|
||||
TEST_VERIFY (strerrorname_np (-1) == NULL);
|
||||
TEST_VERIFY (strerrorname_np (array_length (errlist)) == NULL);
|
||||
for (size_t i = 0; i < array_length (errlist); i++)
|
||||
{
|
||||
if (errlist[i] == NULL)
|
||||
continue;
|
||||
TEST_COMPARE_STRING (strerrorname_np (i), errname.str + errnameidx[i]);
|
||||
}
|
||||
#ifdef EPERM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPERM), "Operation not permitted");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPERM), "EPERM");
|
||||
#endif
|
||||
#ifdef ENOENT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOENT),
|
||||
"No such file or directory");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOENT), "ENOENT");
|
||||
#endif
|
||||
#ifdef ESRCH
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ESRCH), "No such process");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ESRCH), "ESRCH");
|
||||
#endif
|
||||
#ifdef EINTR
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EINTR), "Interrupted system call");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EINTR), "EINTR");
|
||||
#endif
|
||||
#ifdef EIO
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EIO), "Input/output error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EIO), "EIO");
|
||||
#endif
|
||||
#ifdef ENXIO
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENXIO), "No such device or address");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENXIO), "ENXIO");
|
||||
#endif
|
||||
#ifdef E2BIG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (E2BIG), "Argument list too long");
|
||||
TEST_COMPARE_STRING (strerrorname_np (E2BIG), "E2BIG");
|
||||
#endif
|
||||
#ifdef ENOEXEC
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOEXEC), "Exec format error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOEXEC), "ENOEXEC");
|
||||
#endif
|
||||
#ifdef EBADF
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBADF), "Bad file descriptor");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBADF), "EBADF");
|
||||
#endif
|
||||
#ifdef ECHILD
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ECHILD), "No child processes");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ECHILD), "ECHILD");
|
||||
#endif
|
||||
#ifdef EDEADLK
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EDEADLK),
|
||||
"Resource deadlock avoided");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EDEADLK), "EDEADLK");
|
||||
#endif
|
||||
#ifdef ENOMEM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOMEM), "Cannot allocate memory");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOMEM), "ENOMEM");
|
||||
#endif
|
||||
#ifdef EACCES
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EACCES), "Permission denied");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EACCES), "EACCES");
|
||||
#endif
|
||||
#ifdef EFAULT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EFAULT), "Bad address");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EFAULT), "EFAULT");
|
||||
#endif
|
||||
#ifdef ENOTBLK
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTBLK), "Block device required");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTBLK), "ENOTBLK");
|
||||
#endif
|
||||
#ifdef EBUSY
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBUSY), "Device or resource busy");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBUSY), "EBUSY");
|
||||
#endif
|
||||
#ifdef EEXIST
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EEXIST), "File exists");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EEXIST), "EEXIST");
|
||||
#endif
|
||||
#ifdef EXDEV
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EXDEV), "Invalid cross-device link");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EXDEV), "EXDEV");
|
||||
#endif
|
||||
#ifdef ENODEV
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENODEV), "No such device");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENODEV), "ENODEV");
|
||||
#endif
|
||||
#ifdef ENOTDIR
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTDIR), "Not a directory");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTDIR), "ENOTDIR");
|
||||
#endif
|
||||
#ifdef EISDIR
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EISDIR), "Is a directory");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EISDIR), "EISDIR");
|
||||
#endif
|
||||
#ifdef EINVAL
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EINVAL), "Invalid argument");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EINVAL), "EINVAL");
|
||||
#endif
|
||||
#ifdef EMFILE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EMFILE), "Too many open files");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EMFILE), "EMFILE");
|
||||
#endif
|
||||
#ifdef ENFILE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENFILE),
|
||||
"Too many open files in system");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENFILE), "ENFILE");
|
||||
#endif
|
||||
#ifdef ENOTTY
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTTY),
|
||||
"Inappropriate ioctl for device");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTTY), "ENOTTY");
|
||||
#endif
|
||||
#ifdef ETXTBSY
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ETXTBSY), "Text file busy");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ETXTBSY), "ETXTBSY");
|
||||
#endif
|
||||
#ifdef EFBIG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EFBIG), "File too large");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EFBIG), "EFBIG");
|
||||
#endif
|
||||
#ifdef ENOSPC
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOSPC), "No space left on device");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOSPC), "ENOSPC");
|
||||
#endif
|
||||
#ifdef ESPIPE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ESPIPE), "Illegal seek");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ESPIPE), "ESPIPE");
|
||||
#endif
|
||||
#ifdef EROFS
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EROFS), "Read-only file system");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EROFS), "EROFS");
|
||||
#endif
|
||||
#ifdef EMLINK
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EMLINK), "Too many links");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EMLINK), "EMLINK");
|
||||
#endif
|
||||
#ifdef EPIPE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPIPE), "Broken pipe");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPIPE), "EPIPE");
|
||||
#endif
|
||||
#ifdef EDOM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EDOM),
|
||||
"Numerical argument out of domain");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EDOM), "EDOM");
|
||||
#endif
|
||||
#ifdef ERANGE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ERANGE),
|
||||
"Numerical result out of range");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ERANGE), "ERANGE");
|
||||
#endif
|
||||
#ifdef EAGAIN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EAGAIN),
|
||||
"Resource temporarily unavailable");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EAGAIN), "EAGAIN");
|
||||
#endif
|
||||
#ifdef EINPROGRESS
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EINPROGRESS),
|
||||
"Operation now in progress");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EINPROGRESS), "EINPROGRESS");
|
||||
#endif
|
||||
#ifdef EALREADY
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EALREADY),
|
||||
"Operation already in progress");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EALREADY), "EALREADY");
|
||||
#endif
|
||||
#ifdef ENOTSOCK
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTSOCK),
|
||||
"Socket operation on non-socket");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTSOCK), "ENOTSOCK");
|
||||
#endif
|
||||
#ifdef EMSGSIZE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EMSGSIZE), "Message too long");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EMSGSIZE), "EMSGSIZE");
|
||||
#endif
|
||||
#ifdef EPROTOTYPE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPROTOTYPE),
|
||||
"Protocol wrong type for socket");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPROTOTYPE), "EPROTOTYPE");
|
||||
#endif
|
||||
#ifdef ENOPROTOOPT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOPROTOOPT),
|
||||
"Protocol not available");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOPROTOOPT), "ENOPROTOOPT");
|
||||
#endif
|
||||
#ifdef EPROTONOSUPPORT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPROTONOSUPPORT),
|
||||
"Protocol not supported");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPROTONOSUPPORT), "EPROTONOSUPPORT");
|
||||
#endif
|
||||
#ifdef ESOCKTNOSUPPORT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ESOCKTNOSUPPORT),
|
||||
"Socket type not supported");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ESOCKTNOSUPPORT), "ESOCKTNOSUPPORT");
|
||||
#endif
|
||||
#ifdef EOPNOTSUPP
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EOPNOTSUPP),
|
||||
"Operation not supported");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EOPNOTSUPP), "EOPNOTSUPP");
|
||||
#endif
|
||||
#ifdef EPFNOSUPPORT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPFNOSUPPORT),
|
||||
"Protocol family not supported");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPFNOSUPPORT), "EPFNOSUPPORT");
|
||||
#endif
|
||||
#ifdef EAFNOSUPPORT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EAFNOSUPPORT),
|
||||
"Address family not supported by protocol");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EAFNOSUPPORT), "EAFNOSUPPORT");
|
||||
#endif
|
||||
#ifdef EADDRINUSE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EADDRINUSE),
|
||||
"Address already in use");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EADDRINUSE), "EADDRINUSE");
|
||||
#endif
|
||||
#ifdef EADDRNOTAVAIL
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EADDRNOTAVAIL),
|
||||
"Cannot assign requested address");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EADDRNOTAVAIL), "EADDRNOTAVAIL");
|
||||
#endif
|
||||
#ifdef ENETDOWN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENETDOWN), "Network is down");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENETDOWN), "ENETDOWN");
|
||||
#endif
|
||||
#ifdef ENETUNREACH
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENETUNREACH),
|
||||
"Network is unreachable");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENETUNREACH), "ENETUNREACH");
|
||||
#endif
|
||||
#ifdef ENETRESET
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENETRESET),
|
||||
"Network dropped connection on reset");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENETRESET), "ENETRESET");
|
||||
#endif
|
||||
#ifdef ECONNABORTED
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ECONNABORTED),
|
||||
"Software caused connection abort");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ECONNABORTED), "ECONNABORTED");
|
||||
#endif
|
||||
#ifdef ECONNRESET
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ECONNRESET),
|
||||
"Connection reset by peer");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ECONNRESET), "ECONNRESET");
|
||||
#endif
|
||||
#ifdef ENOBUFS
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOBUFS),
|
||||
"No buffer space available");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOBUFS), "ENOBUFS");
|
||||
#endif
|
||||
#ifdef EISCONN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EISCONN),
|
||||
"Transport endpoint is already connected");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EISCONN), "EISCONN");
|
||||
#endif
|
||||
#ifdef ENOTCONN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTCONN),
|
||||
"Transport endpoint is not connected");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTCONN), "ENOTCONN");
|
||||
#endif
|
||||
#ifdef EDESTADDRREQ
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EDESTADDRREQ),
|
||||
"Destination address required");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EDESTADDRREQ), "EDESTADDRREQ");
|
||||
#endif
|
||||
#ifdef ESHUTDOWN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ESHUTDOWN),
|
||||
"Cannot send after transport endpoint shutdown");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ESHUTDOWN), "ESHUTDOWN");
|
||||
#endif
|
||||
#ifdef ETOOMANYREFS
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ETOOMANYREFS),
|
||||
"Too many references: cannot splice");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ETOOMANYREFS), "ETOOMANYREFS");
|
||||
#endif
|
||||
#ifdef ETIMEDOUT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ETIMEDOUT), "Connection timed out");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ETIMEDOUT), "ETIMEDOUT");
|
||||
#endif
|
||||
#ifdef ECONNREFUSED
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ECONNREFUSED), "Connection refused");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ECONNREFUSED), "ECONNREFUSED");
|
||||
#endif
|
||||
#ifdef ELOOP
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ELOOP),
|
||||
"Too many levels of symbolic links");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ELOOP), "ELOOP");
|
||||
#endif
|
||||
#ifdef ENAMETOOLONG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENAMETOOLONG), "File name too long");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENAMETOOLONG), "ENAMETOOLONG");
|
||||
#endif
|
||||
#ifdef EHOSTDOWN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EHOSTDOWN), "Host is down");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EHOSTDOWN), "EHOSTDOWN");
|
||||
#endif
|
||||
#ifdef EHOSTUNREACH
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EHOSTUNREACH), "No route to host");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EHOSTUNREACH), "EHOSTUNREACH");
|
||||
#endif
|
||||
#ifdef ENOTEMPTY
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTEMPTY), "Directory not empty");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTEMPTY), "ENOTEMPTY");
|
||||
#endif
|
||||
#ifdef EUSERS
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EUSERS), "Too many users");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EUSERS), "EUSERS");
|
||||
#endif
|
||||
#ifdef EDQUOT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EDQUOT), "Disk quota exceeded");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EDQUOT), "EDQUOT");
|
||||
#endif
|
||||
#ifdef ESTALE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ESTALE), "Stale file handle");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ESTALE), "ESTALE");
|
||||
#endif
|
||||
#ifdef EREMOTE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EREMOTE), "Object is remote");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EREMOTE), "EREMOTE");
|
||||
#endif
|
||||
#ifdef ENOLCK
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOLCK), "No locks available");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOLCK), "ENOLCK");
|
||||
#endif
|
||||
#ifdef ENOSYS
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOSYS), "Function not implemented");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOSYS), "ENOSYS");
|
||||
#endif
|
||||
#ifdef EILSEQ
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EILSEQ),
|
||||
"Invalid or incomplete multibyte or wide character");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EILSEQ), "EILSEQ");
|
||||
#endif
|
||||
#ifdef EBADMSG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBADMSG), "Bad message");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBADMSG), "EBADMSG");
|
||||
#endif
|
||||
#ifdef EIDRM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EIDRM), "Identifier removed");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EIDRM), "EIDRM");
|
||||
#endif
|
||||
#ifdef EMULTIHOP
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EMULTIHOP), "Multihop attempted");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EMULTIHOP), "EMULTIHOP");
|
||||
#endif
|
||||
#ifdef ENODATA
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENODATA), "No data available");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENODATA), "ENODATA");
|
||||
#endif
|
||||
#ifdef ENOLINK
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOLINK), "Link has been severed");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOLINK), "ENOLINK");
|
||||
#endif
|
||||
#ifdef ENOMSG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOMSG),
|
||||
"No message of desired type");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOMSG), "ENOMSG");
|
||||
#endif
|
||||
#ifdef ENOSR
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOSR), "Out of streams resources");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOSR), "ENOSR");
|
||||
#endif
|
||||
#ifdef ENOSTR
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOSTR), "Device not a stream");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOSTR), "ENOSTR");
|
||||
#endif
|
||||
#ifdef EOVERFLOW
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EOVERFLOW),
|
||||
"Value too large for defined data type");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EOVERFLOW), "EOVERFLOW");
|
||||
#endif
|
||||
#ifdef EPROTO
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPROTO), "Protocol error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPROTO), "EPROTO");
|
||||
#endif
|
||||
#ifdef ETIME
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ETIME), "Timer expired");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ETIME), "ETIME");
|
||||
#endif
|
||||
#ifdef ECANCELED
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ECANCELED), "Operation canceled");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ECANCELED), "ECANCELED");
|
||||
#endif
|
||||
#ifdef EOWNERDEAD
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EOWNERDEAD), "Owner died");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EOWNERDEAD), "EOWNERDEAD");
|
||||
#endif
|
||||
#ifdef ENOTRECOVERABLE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTRECOVERABLE),
|
||||
"State not recoverable");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTRECOVERABLE), "ENOTRECOVERABLE");
|
||||
#endif
|
||||
#ifdef ERESTART
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ERESTART),
|
||||
"Interrupted system call should be restarted");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ERESTART), "ERESTART");
|
||||
#endif
|
||||
#ifdef ECHRNG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ECHRNG),
|
||||
"Channel number out of range");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ECHRNG), "ECHRNG");
|
||||
#endif
|
||||
#ifdef EL2NSYNC
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EL2NSYNC),
|
||||
"Level 2 not synchronized");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EL2NSYNC), "EL2NSYNC");
|
||||
#endif
|
||||
#ifdef EL3HLT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EL3HLT), "Level 3 halted");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EL3HLT), "EL3HLT");
|
||||
#endif
|
||||
#ifdef EL3RST
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EL3RST), "Level 3 reset");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EL3RST), "EL3RST");
|
||||
#endif
|
||||
#ifdef ELNRNG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ELNRNG), "Link number out of range");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ELNRNG), "ELNRNG");
|
||||
#endif
|
||||
#ifdef EUNATCH
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EUNATCH),
|
||||
"Protocol driver not attached");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EUNATCH), "EUNATCH");
|
||||
#endif
|
||||
#ifdef ENOCSI
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOCSI),
|
||||
"No CSI structure available");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOCSI), "ENOCSI");
|
||||
#endif
|
||||
#ifdef EL2HLT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EL2HLT), "Level 2 halted");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EL2HLT), "EL2HLT");
|
||||
#endif
|
||||
#ifdef EBADE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBADE), "Invalid exchange");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBADE), "EBADE");
|
||||
#endif
|
||||
#ifdef EBADR
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBADR),
|
||||
"Invalid request descriptor");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBADR), "EBADR");
|
||||
#endif
|
||||
#ifdef EXFULL
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EXFULL), "Exchange full");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EXFULL), "EXFULL");
|
||||
#endif
|
||||
#ifdef ENOANO
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOANO), "No anode");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOANO), "ENOANO");
|
||||
#endif
|
||||
#ifdef EBADRQC
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBADRQC), "Invalid request code");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBADRQC), "EBADRQC");
|
||||
#endif
|
||||
#ifdef EBADSLT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBADSLT), "Invalid slot");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBADSLT), "EBADSLT");
|
||||
#endif
|
||||
#ifdef EBFONT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBFONT), "Bad font file format");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBFONT), "EBFONT");
|
||||
#endif
|
||||
#ifdef ENONET
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENONET),
|
||||
"Machine is not on the network");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENONET), "ENONET");
|
||||
#endif
|
||||
#ifdef ENOPKG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOPKG), "Package not installed");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOPKG), "ENOPKG");
|
||||
#endif
|
||||
#ifdef EADV
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EADV), "Advertise error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EADV), "EADV");
|
||||
#endif
|
||||
#ifdef ESRMNT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ESRMNT), "Srmount error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ESRMNT), "ESRMNT");
|
||||
#endif
|
||||
#ifdef ECOMM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ECOMM),
|
||||
"Communication error on send");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ECOMM), "ECOMM");
|
||||
#endif
|
||||
#ifdef EDOTDOT
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EDOTDOT), "RFS specific error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EDOTDOT), "EDOTDOT");
|
||||
#endif
|
||||
#ifdef ENOTUNIQ
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTUNIQ),
|
||||
"Name not unique on network");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTUNIQ), "ENOTUNIQ");
|
||||
#endif
|
||||
#ifdef EBADFD
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBADFD),
|
||||
"File descriptor in bad state");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBADFD), "EBADFD");
|
||||
#endif
|
||||
#ifdef EREMCHG
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EREMCHG), "Remote address changed");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EREMCHG), "EREMCHG");
|
||||
#endif
|
||||
#ifdef ELIBACC
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ELIBACC),
|
||||
"Can not access a needed shared library");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ELIBACC), "ELIBACC");
|
||||
#endif
|
||||
#ifdef ELIBBAD
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ELIBBAD),
|
||||
"Accessing a corrupted shared library");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ELIBBAD), "ELIBBAD");
|
||||
#endif
|
||||
#ifdef ELIBSCN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ELIBSCN),
|
||||
".lib section in a.out corrupted");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ELIBSCN), "ELIBSCN");
|
||||
#endif
|
||||
#ifdef ELIBMAX
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ELIBMAX),
|
||||
"Attempting to link in too many shared libraries");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ELIBMAX), "ELIBMAX");
|
||||
#endif
|
||||
#ifdef ELIBEXEC
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ELIBEXEC),
|
||||
"Cannot exec a shared library directly");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ELIBEXEC), "ELIBEXEC");
|
||||
#endif
|
||||
#ifdef ESTRPIPE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ESTRPIPE), "Streams pipe error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ESTRPIPE), "ESTRPIPE");
|
||||
#endif
|
||||
#ifdef EUCLEAN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EUCLEAN),
|
||||
"Structure needs cleaning");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EUCLEAN), "EUCLEAN");
|
||||
#endif
|
||||
#ifdef ENOTNAM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTNAM),
|
||||
"Not a XENIX named type file");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTNAM), "ENOTNAM");
|
||||
#endif
|
||||
#ifdef ENAVAIL
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENAVAIL),
|
||||
"No XENIX semaphores available");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENAVAIL), "ENAVAIL");
|
||||
#endif
|
||||
#ifdef EISNAM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EISNAM), "Is a named type file");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EISNAM), "EISNAM");
|
||||
#endif
|
||||
#ifdef EREMOTEIO
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EREMOTEIO), "Remote I/O error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EREMOTEIO), "EREMOTEIO");
|
||||
#endif
|
||||
#ifdef ENOMEDIUM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOMEDIUM), "No medium found");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOMEDIUM), "ENOMEDIUM");
|
||||
#endif
|
||||
#ifdef EMEDIUMTYPE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EMEDIUMTYPE), "Wrong medium type");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EMEDIUMTYPE), "EMEDIUMTYPE");
|
||||
#endif
|
||||
#ifdef ENOKEY
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOKEY),
|
||||
"Required key not available");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOKEY), "ENOKEY");
|
||||
#endif
|
||||
#ifdef EKEYEXPIRED
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EKEYEXPIRED), "Key has expired");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EKEYEXPIRED), "EKEYEXPIRED");
|
||||
#endif
|
||||
#ifdef EKEYREVOKED
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EKEYREVOKED),
|
||||
"Key has been revoked");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EKEYREVOKED), "EKEYREVOKED");
|
||||
#endif
|
||||
#ifdef EKEYREJECTED
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EKEYREJECTED),
|
||||
"Key was rejected by service");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EKEYREJECTED), "EKEYREJECTED");
|
||||
#endif
|
||||
#ifdef ERFKILL
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ERFKILL),
|
||||
"Operation not possible due to RF-kill");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ERFKILL), "ERFKILL");
|
||||
#endif
|
||||
#ifdef EHWPOISON
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EHWPOISON),
|
||||
"Memory page has hardware error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EHWPOISON), "EHWPOISON");
|
||||
#endif
|
||||
#ifdef EBADRPC
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBADRPC), "RPC struct is bad");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBADRPC), "EBADRPC");
|
||||
#endif
|
||||
#ifdef EFTYPE
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EFTYPE),
|
||||
"Inappropriate file type or format");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EFTYPE), "EFTYPE");
|
||||
#endif
|
||||
#ifdef EPROCUNAVAIL
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPROCUNAVAIL),
|
||||
"RPC bad procedure for program");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPROCUNAVAIL), "EPROCUNAVAIL");
|
||||
#endif
|
||||
#ifdef EAUTH
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EAUTH), "Authentication error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EAUTH), "EAUTH");
|
||||
#endif
|
||||
#ifdef EDIED
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EDIED), "Translator died");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EDIED), "EDIED");
|
||||
#endif
|
||||
#ifdef ERPCMISMATCH
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ERPCMISMATCH), "RPC version wrong");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ERPCMISMATCH), "ERPCMISMATCH");
|
||||
#endif
|
||||
#ifdef EGREGIOUS
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EGREGIOUS),
|
||||
"You really blew it this time");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EGREGIOUS), "EGREGIOUS");
|
||||
#endif
|
||||
#ifdef EPROCLIM
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPROCLIM), "Too many processes");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPROCLIM), "EPROCLIM");
|
||||
#endif
|
||||
#ifdef EGRATUITOUS
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EGRATUITOUS), "Gratuitous error");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EGRATUITOUS), "EGRATUITOUS");
|
||||
#endif
|
||||
#if defined (ENOTSUP) && ENOTSUP != EOPNOTSUPP
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENOTSUP), "Not supported");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENOTSUP), "ENOTSUP");
|
||||
#endif
|
||||
#ifdef EPROGMISMATCH
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPROGMISMATCH),
|
||||
"RPC program version wrong");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPROGMISMATCH), "EPROGMISMATCH");
|
||||
#endif
|
||||
#ifdef EBACKGROUND
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EBACKGROUND),
|
||||
"Inappropriate operation for background process");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EBACKGROUND), "EBACKGROUND");
|
||||
#endif
|
||||
#ifdef EIEIO
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EIEIO), "Computer bought the farm");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EIEIO), "EIEIO");
|
||||
#endif
|
||||
#if defined (EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EWOULDBLOCK),
|
||||
"Operation would block");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EWOULDBLOCK), "EWOULDBLOCK");
|
||||
#endif
|
||||
#ifdef ENEEDAUTH
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ENEEDAUTH), "Need authenticator");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ENEEDAUTH), "ENEEDAUTH");
|
||||
#endif
|
||||
#ifdef ED
|
||||
TEST_COMPARE_STRING (strerrordesc_np (ED), "?");
|
||||
TEST_COMPARE_STRING (strerrorname_np (ED), "ED");
|
||||
#endif
|
||||
#ifdef EPROGUNAVAIL
|
||||
TEST_COMPARE_STRING (strerrordesc_np (EPROGUNAVAIL),
|
||||
"RPC program not available");
|
||||
TEST_COMPARE_STRING (strerrorname_np (EPROGUNAVAIL), "EPROGUNAVAIL");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
#endif
|
||||
{
|
||||
va_list arg;
|
||||
const CHAR_T *f = format;
|
||||
const UCHAR_T *f = (const UCHAR_T *) format;
|
||||
UCHAR_T fc; /* Current character of the format. */
|
||||
WINT_T done = 0; /* Assignments done. */
|
||||
size_t read_in = 0; /* Chars read in. */
|
||||
@@ -415,10 +415,11 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
#endif
|
||||
|
||||
#ifndef COMPILE_WSCANF
|
||||
if (!isascii ((unsigned char) *f))
|
||||
if (!isascii (*f))
|
||||
{
|
||||
/* Non-ASCII, may be a multibyte. */
|
||||
int len = __mbrlen (f, strlen (f), &state);
|
||||
int len = __mbrlen ((const char *) f, strlen ((const char *) f),
|
||||
&state);
|
||||
if (len > 0)
|
||||
{
|
||||
do
|
||||
@@ -426,7 +427,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
c = inchar ();
|
||||
if (__glibc_unlikely (c == EOF))
|
||||
input_error ();
|
||||
else if (c != (unsigned char) *f++)
|
||||
else if (c != *f++)
|
||||
{
|
||||
ungetc_not_eof (c, s);
|
||||
conv_error ();
|
||||
@@ -484,9 +485,9 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
char_buffer_rewind (&charbuf);
|
||||
|
||||
/* Check for a positional parameter specification. */
|
||||
if (ISDIGIT ((UCHAR_T) *f))
|
||||
if (ISDIGIT (*f))
|
||||
{
|
||||
argpos = read_int ((const UCHAR_T **) &f);
|
||||
argpos = read_int (&f);
|
||||
if (*f == L_('$'))
|
||||
++f;
|
||||
else
|
||||
@@ -521,8 +522,8 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
|
||||
/* Find the maximum field width. */
|
||||
width = 0;
|
||||
if (ISDIGIT ((UCHAR_T) *f))
|
||||
width = read_int ((const UCHAR_T **) &f);
|
||||
if (ISDIGIT (*f))
|
||||
width = read_int (&f);
|
||||
got_width:
|
||||
if (width == 0)
|
||||
width = -1;
|
||||
@@ -2522,12 +2523,11 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
|
||||
}
|
||||
|
||||
while ((fc = *f++) != '\0' && fc != ']')
|
||||
if (fc == '-' && *f != '\0' && *f != ']'
|
||||
&& (unsigned char) f[-2] <= (unsigned char) *f)
|
||||
if (fc == '-' && *f != '\0' && *f != ']' && f[-2] <= *f)
|
||||
{
|
||||
/* Add all characters from the one before the '-'
|
||||
up to (but not including) the next format char. */
|
||||
for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
|
||||
for (fc = f[-2]; fc < *f; ++fc)
|
||||
((char *)charbuf.scratch.data)[fc] = 1;
|
||||
}
|
||||
else
|
||||
|
||||
+18
-181
@@ -30,167 +30,12 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/test-driver.h>
|
||||
|
||||
static char MAGIC_ARGUMENT[] = "run-actual-test";
|
||||
#define MAGIC_STATUS 19
|
||||
|
||||
/* Return a GID which is not our current GID, but is present in the
|
||||
supplementary group list. */
|
||||
static gid_t
|
||||
choose_gid (void)
|
||||
{
|
||||
int count = getgroups (0, NULL);
|
||||
if (count < 0)
|
||||
{
|
||||
printf ("getgroups: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
gid_t *groups;
|
||||
groups = xcalloc (count, sizeof (*groups));
|
||||
int ret = getgroups (count, groups);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf ("getgroups: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
gid_t current = getgid ();
|
||||
gid_t not_current = 0;
|
||||
for (int i = 0; i < ret; ++i)
|
||||
{
|
||||
if (groups[i] != current)
|
||||
{
|
||||
not_current = groups[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
free (groups);
|
||||
return not_current;
|
||||
}
|
||||
|
||||
|
||||
/* Copies the executable into a restricted directory, so that we can
|
||||
safely make it SGID with the TARGET group ID. Then runs the
|
||||
executable. */
|
||||
static int
|
||||
run_executable_sgid (gid_t target)
|
||||
{
|
||||
char *dirname = xasprintf ("%s/secure-getenv.%jd",
|
||||
test_dir, (intmax_t) getpid ());
|
||||
char *execname = xasprintf ("%s/bin", dirname);
|
||||
int infd = -1;
|
||||
int outfd = -1;
|
||||
int ret = -1;
|
||||
if (mkdir (dirname, 0700) < 0)
|
||||
{
|
||||
printf ("mkdir: %m\n");
|
||||
goto err;
|
||||
}
|
||||
infd = open ("/proc/self/exe", O_RDONLY);
|
||||
if (infd < 0)
|
||||
{
|
||||
printf ("open (/proc/self/exe): %m\n");
|
||||
goto err;
|
||||
}
|
||||
outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
|
||||
if (outfd < 0)
|
||||
{
|
||||
printf ("open (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
char buf[4096];
|
||||
for (;;)
|
||||
{
|
||||
ssize_t rdcount = read (infd, buf, sizeof (buf));
|
||||
if (rdcount < 0)
|
||||
{
|
||||
printf ("read: %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (rdcount == 0)
|
||||
break;
|
||||
char *p = buf;
|
||||
char *end = buf + rdcount;
|
||||
while (p != end)
|
||||
{
|
||||
ssize_t wrcount = write (outfd, buf, end - p);
|
||||
if (wrcount == 0)
|
||||
errno = ENOSPC;
|
||||
if (wrcount <= 0)
|
||||
{
|
||||
printf ("write: %m\n");
|
||||
goto err;
|
||||
}
|
||||
p += wrcount;
|
||||
}
|
||||
}
|
||||
if (fchown (outfd, getuid (), target) < 0)
|
||||
{
|
||||
printf ("fchown (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
if (fchmod (outfd, 02750) < 0)
|
||||
{
|
||||
printf ("fchmod (%s): %m\n", execname);
|
||||
goto err;
|
||||
}
|
||||
if (close (outfd) < 0)
|
||||
{
|
||||
printf ("close (outfd): %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (close (infd) < 0)
|
||||
{
|
||||
printf ("close (infd): %m\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
int kid = fork ();
|
||||
if (kid < 0)
|
||||
{
|
||||
printf ("fork: %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (kid == 0)
|
||||
{
|
||||
/* Child process. */
|
||||
char *args[] = { execname, MAGIC_ARGUMENT, NULL };
|
||||
execve (execname, args, environ);
|
||||
printf ("execve (%s): %m\n", execname);
|
||||
_exit (1);
|
||||
}
|
||||
int status;
|
||||
if (waitpid (kid, &status, 0) < 0)
|
||||
{
|
||||
printf ("waitpid: %m\n");
|
||||
goto err;
|
||||
}
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS)
|
||||
{
|
||||
printf ("Unexpected exit status %d from child process\n",
|
||||
status);
|
||||
goto err;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
if (outfd >= 0)
|
||||
close (outfd);
|
||||
if (infd >= 0)
|
||||
close (infd);
|
||||
if (execname)
|
||||
{
|
||||
unlink (execname);
|
||||
free (execname);
|
||||
}
|
||||
if (dirname)
|
||||
{
|
||||
rmdir (dirname);
|
||||
free (dirname);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
@@ -212,15 +57,15 @@ do_test (void)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
gid_t target = choose_gid ();
|
||||
if (target == 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Could not find a suitable GID for user %jd, skipping test\n",
|
||||
(intmax_t) getuid ());
|
||||
exit (0);
|
||||
}
|
||||
return run_executable_sgid (target);
|
||||
int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
|
||||
|
||||
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
if (!WIFEXITED (status))
|
||||
FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -229,23 +74,15 @@ alternative_main (int argc, char **argv)
|
||||
if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0)
|
||||
{
|
||||
if (getgid () == getegid ())
|
||||
{
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
exit (MAGIC_STATUS);
|
||||
}
|
||||
/* This can happen if the file system is mounted nosuid. */
|
||||
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
|
||||
(intmax_t) getgid ());
|
||||
if (getenv ("PATH") == NULL)
|
||||
{
|
||||
printf ("PATH variable not present\n");
|
||||
exit (3);
|
||||
}
|
||||
FAIL_EXIT (3, "PATH variable not present\n");
|
||||
if (secure_getenv ("PATH") != NULL)
|
||||
{
|
||||
printf ("PATH variable not filtered out\n");
|
||||
exit (4);
|
||||
}
|
||||
exit (MAGIC_STATUS);
|
||||
FAIL_EXIT (4, "PATH variable not filtered out\n");
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
# error "Never use <bits/string_fortified.h> directly; include <string.h> instead."
|
||||
#endif
|
||||
|
||||
#if !__GNUC_PREREQ (5,0)
|
||||
__warndecl (__warn_memset_zero_len,
|
||||
"memset used with constant zero length parameter; this could be due to transposed parameters");
|
||||
#endif
|
||||
|
||||
__fortify_function void *
|
||||
__NTH (memcpy (void *__restrict __dest, const void *__restrict __src,
|
||||
size_t __len))
|
||||
@@ -58,16 +53,6 @@ __NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
|
||||
__fortify_function void *
|
||||
__NTH (memset (void *__dest, int __ch, size_t __len))
|
||||
{
|
||||
/* GCC-5.0 and newer implements these checks in the compiler, so we don't
|
||||
need them here. */
|
||||
#if !__GNUC_PREREQ (5,0)
|
||||
if (__builtin_constant_p (__len) && __len == 0
|
||||
&& (!__builtin_constant_p (__ch) || __ch != 0))
|
||||
{
|
||||
__warn_memset_zero_len ();
|
||||
return __dest;
|
||||
}
|
||||
#endif
|
||||
return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
|
||||
}
|
||||
|
||||
|
||||
+36
-3
@@ -65,8 +65,8 @@ do_one_test (impl_t *impl, const CHAR *s, int c, size_t n, CHAR *exp_res)
|
||||
CHAR *res = CALL (impl, s, c, n);
|
||||
if (res != exp_res)
|
||||
{
|
||||
error (0, 0, "Wrong result in function %s %p %p", impl->name,
|
||||
res, exp_res);
|
||||
error (0, 0, "Wrong result in function %s (%p, %d, %zu) -> %p != %p",
|
||||
impl->name, s, c, n, res, exp_res);
|
||||
ret = 1;
|
||||
return;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ do_test (size_t align, size_t pos, size_t len, size_t n, int seek_char)
|
||||
}
|
||||
buf[align + len] = 0;
|
||||
|
||||
if (pos < len)
|
||||
if (pos < MIN(n, len))
|
||||
{
|
||||
buf[align + pos] = seek_char;
|
||||
buf[align + len] = -seek_char;
|
||||
@@ -107,6 +107,38 @@ do_test (size_t align, size_t pos, size_t len, size_t n, int seek_char)
|
||||
do_one_test (impl, (CHAR *) (buf + align), seek_char, n, result);
|
||||
}
|
||||
|
||||
static void
|
||||
do_overflow_tests (void)
|
||||
{
|
||||
size_t i, j, len;
|
||||
const size_t one = 1;
|
||||
uintptr_t buf_addr = (uintptr_t) buf1;
|
||||
|
||||
for (i = 0; i < 750; ++i)
|
||||
{
|
||||
do_test (0, i, 751, SIZE_MAX - i, BIG_CHAR);
|
||||
do_test (0, i, 751, i - buf_addr, BIG_CHAR);
|
||||
do_test (0, i, 751, -buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, 751, SIZE_MAX - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, 751, SIZE_MAX - buf_addr + i, BIG_CHAR);
|
||||
|
||||
len = 0;
|
||||
for (j = 8 * sizeof(size_t) - 1; j ; --j)
|
||||
{
|
||||
len |= one << j;
|
||||
do_test (0, i, 751, len - i, BIG_CHAR);
|
||||
do_test (0, i, 751, len + i, BIG_CHAR);
|
||||
do_test (0, i, 751, len - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, 751, len - buf_addr + i, BIG_CHAR);
|
||||
|
||||
do_test (0, i, 751, ~len - i, BIG_CHAR);
|
||||
do_test (0, i, 751, ~len + i, BIG_CHAR);
|
||||
do_test (0, i, 751, ~len - buf_addr - i, BIG_CHAR);
|
||||
do_test (0, i, 751, ~len - buf_addr + i, BIG_CHAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_random_tests (void)
|
||||
{
|
||||
@@ -221,6 +253,7 @@ test_main (void)
|
||||
do_test (page_size / 2 - i, i, i, 1, 0x9B);
|
||||
|
||||
do_random_tests ();
|
||||
do_overflow_tests ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,66 @@ do_test (size_t align1, size_t align2, size_t len1, size_t len2,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_overflow_tests (void)
|
||||
{
|
||||
size_t i, j, len;
|
||||
const size_t one = 1;
|
||||
CHAR *s1, *s2;
|
||||
uintptr_t s1_addr;
|
||||
s1 = (CHAR *) buf1;
|
||||
s2 = (CHAR *) buf2;
|
||||
s1_addr = (uintptr_t)s1;
|
||||
for (j = 0; j < 200; ++j)
|
||||
s2[j] = 32 + 23 * j % (BIG_CHAR - 32);
|
||||
s2[200] = 0;
|
||||
for (i = 0; i < 750; ++i) {
|
||||
for (j = 0; j < i; ++j)
|
||||
s1[j] = 32 + 23 * j % (BIG_CHAR - 32);
|
||||
s1[i] = '\0';
|
||||
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, SIZE_MAX - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, i - s1_addr);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, -s1_addr - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, SIZE_MAX - s1_addr - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, SIZE_MAX - s1_addr + i);
|
||||
}
|
||||
|
||||
len = 0;
|
||||
for (j = 8 * sizeof(size_t) - 1; j ; --j)
|
||||
{
|
||||
len |= one << j;
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, len - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, len + i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, len - s1_addr - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, len - s1_addr + i);
|
||||
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, ~len - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, ~len + i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, ~len - s1_addr - i);
|
||||
s2[200] = '\0';
|
||||
do_one_test (impl, s2, s1, ~len - s1_addr + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_random_tests (void)
|
||||
{
|
||||
@@ -316,6 +376,7 @@ test_main (void)
|
||||
}
|
||||
|
||||
do_random_tests ();
|
||||
do_overflow_tests ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -403,6 +403,18 @@ check2 (void)
|
||||
free (s2);
|
||||
}
|
||||
|
||||
static void
|
||||
check3 (void)
|
||||
{
|
||||
const CHAR *s1 = L ("abc");
|
||||
CHAR *s2 = STRDUP (s1);
|
||||
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
check_result (impl, s1, s2, SIZE_MAX, 0);
|
||||
|
||||
free (s2);
|
||||
}
|
||||
|
||||
int
|
||||
test_main (void)
|
||||
{
|
||||
@@ -412,6 +424,7 @@ test_main (void)
|
||||
|
||||
check1 ();
|
||||
check2 ();
|
||||
check3 ();
|
||||
|
||||
printf ("%23s", "");
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
|
||||
+85
-2
@@ -27,6 +27,7 @@
|
||||
|
||||
#ifndef WIDE
|
||||
# define STRNLEN strnlen
|
||||
# define MEMSET memset
|
||||
# define CHAR char
|
||||
# define BIG_CHAR CHAR_MAX
|
||||
# define MIDDLE_CHAR 127
|
||||
@@ -34,6 +35,7 @@
|
||||
#else
|
||||
# include <wchar.h>
|
||||
# define STRNLEN wcsnlen
|
||||
# define MEMSET wmemset
|
||||
# define CHAR wchar_t
|
||||
# define BIG_CHAR WCHAR_MAX
|
||||
# define MIDDLE_CHAR 1121
|
||||
@@ -73,7 +75,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
align &= 63;
|
||||
align &= (getpagesize () / sizeof (CHAR) - 1);
|
||||
if ((align + len) * sizeof (CHAR) >= page_size)
|
||||
return;
|
||||
|
||||
@@ -87,6 +89,56 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
|
||||
do_one_test (impl, (CHAR *) (buf + align), maxlen, MIN (len, maxlen));
|
||||
}
|
||||
|
||||
static void
|
||||
do_overflow_tests (void)
|
||||
{
|
||||
size_t i, j, al_idx, repeats, len;
|
||||
const size_t one = 1;
|
||||
uintptr_t buf_addr = (uintptr_t) buf1;
|
||||
const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 };
|
||||
|
||||
for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]);
|
||||
al_idx++)
|
||||
{
|
||||
for (repeats = 0; repeats < 2; ++repeats)
|
||||
{
|
||||
size_t align = repeats ? (getpagesize () - alignments[al_idx])
|
||||
: alignments[al_idx];
|
||||
align /= sizeof (CHAR);
|
||||
for (i = 0; i < 750; ++i)
|
||||
{
|
||||
do_test (align, i, SIZE_MAX, BIG_CHAR);
|
||||
|
||||
do_test (align, i, SIZE_MAX - i, BIG_CHAR);
|
||||
do_test (align, i, i - buf_addr, BIG_CHAR);
|
||||
do_test (align, i, -buf_addr - i, BIG_CHAR);
|
||||
do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
|
||||
do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
|
||||
|
||||
len = 0;
|
||||
for (j = 8 * sizeof (size_t) - 1; j; --j)
|
||||
{
|
||||
len |= one << j;
|
||||
do_test (align, i, len, BIG_CHAR);
|
||||
do_test (align, i, len - i, BIG_CHAR);
|
||||
do_test (align, i, len + i, BIG_CHAR);
|
||||
do_test (align, i, len - buf_addr - i, BIG_CHAR);
|
||||
do_test (align, i, len - buf_addr + i, BIG_CHAR);
|
||||
|
||||
do_test (align, i, ~len - i, BIG_CHAR);
|
||||
do_test (align, i, ~len + i, BIG_CHAR);
|
||||
do_test (align, i, ~len - buf_addr - i, BIG_CHAR);
|
||||
do_test (align, i, ~len - buf_addr + i, BIG_CHAR);
|
||||
|
||||
do_test (align, i, -buf_addr, BIG_CHAR);
|
||||
do_test (align, i, j - buf_addr, BIG_CHAR);
|
||||
do_test (align, i, -buf_addr - j, BIG_CHAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_random_tests (void)
|
||||
{
|
||||
@@ -153,7 +205,7 @@ do_page_tests (void)
|
||||
size_t last_offset = (page_size / sizeof (CHAR)) - 1;
|
||||
|
||||
CHAR *s = (CHAR *) buf2;
|
||||
memset (s, 65, (last_offset - 1));
|
||||
MEMSET (s, 65, (last_offset - 1));
|
||||
s[last_offset] = 0;
|
||||
|
||||
/* Place short strings ending at page boundary. */
|
||||
@@ -196,6 +248,35 @@ do_page_tests (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Tests meant to unveil fail on implementations that access bytes
|
||||
beyond the maxium length. */
|
||||
|
||||
static void
|
||||
do_page_2_tests (void)
|
||||
{
|
||||
size_t i, exp_len, offset;
|
||||
size_t last_offset = page_size / sizeof (CHAR);
|
||||
|
||||
CHAR *s = (CHAR *) buf2;
|
||||
MEMSET (s, 65, last_offset);
|
||||
|
||||
/* Place short strings ending at page boundary without the null
|
||||
byte. */
|
||||
offset = last_offset;
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
/* Decrease offset to stress several sizes and alignments. */
|
||||
offset--;
|
||||
exp_len = last_offset - offset;
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
/* If an implementation goes beyond EXP_LEN, it will trigger
|
||||
the segfault. */
|
||||
do_one_test (impl, (CHAR *) (s + offset), exp_len, exp_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
test_main (void)
|
||||
{
|
||||
@@ -242,6 +323,8 @@ test_main (void)
|
||||
|
||||
do_random_tests ();
|
||||
do_page_tests ();
|
||||
do_page_2_tests ();
|
||||
do_overflow_tests ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -65,7 +65,8 @@ shared-only-routines = $(routines)
|
||||
endif
|
||||
|
||||
tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \
|
||||
tst-udp-nonblocking
|
||||
tst-udp-nonblocking tst-bug22542 tst-bug28768
|
||||
|
||||
xtests := tst-getmyaddr
|
||||
|
||||
ifeq ($(have-thread-library),yes)
|
||||
@@ -111,6 +112,8 @@ $(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so
|
||||
$(objpfx)tst-udp-garbage: \
|
||||
$(common-objpfx)linkobj/libc.so $(shared-thread-library)
|
||||
|
||||
$(objpfx)tst-bug22542: $(common-objpfx)linkobj/libc.so
|
||||
|
||||
else # !have-GLIBC_2.31
|
||||
|
||||
routines = $(routines-for-nss)
|
||||
|
||||
+7
-3
@@ -57,9 +57,13 @@ clnt_create (const char *hostname, u_long prog, u_long vers,
|
||||
|
||||
if (strcmp (proto, "unix") == 0)
|
||||
{
|
||||
memset ((char *)&sun, 0, sizeof (sun));
|
||||
sun.sun_family = AF_UNIX;
|
||||
strcpy (sun.sun_path, hostname);
|
||||
if (__sockaddr_un_set (&sun, hostname) < 0)
|
||||
{
|
||||
struct rpc_createerr *ce = &get_rpc_createerr ();
|
||||
ce->cf_stat = RPC_SYSTEMERROR;
|
||||
ce->cf_error.re_errno = errno;
|
||||
return NULL;
|
||||
}
|
||||
sock = RPC_ANYSOCK;
|
||||
client = clntunix_create (&sun, prog, vers, &sock, 0, 0);
|
||||
if (client == NULL)
|
||||
|
||||
+4
-7
@@ -154,7 +154,10 @@ svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
|
||||
SVCXPRT *xprt;
|
||||
struct unix_rendezvous *r;
|
||||
struct sockaddr_un addr;
|
||||
socklen_t len = sizeof (struct sockaddr_in);
|
||||
socklen_t len = sizeof (addr);
|
||||
|
||||
if (__sockaddr_un_set (&addr, path) < 0)
|
||||
return NULL;
|
||||
|
||||
if (sock == RPC_ANYSOCK)
|
||||
{
|
||||
@@ -165,12 +168,6 @@ svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
|
||||
}
|
||||
madesock = TRUE;
|
||||
}
|
||||
memset (&addr, '\0', sizeof (addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
len = strlen (path) + 1;
|
||||
memcpy (addr.sun_path, path, len);
|
||||
len += sizeof (addr.sun_family);
|
||||
|
||||
__bind (sock, (struct sockaddr *) &addr, len);
|
||||
|
||||
if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Test to verify that overlong hostname is rejected by clnt_create
|
||||
and doesn't cause a buffer overflow (bug 22542).
|
||||
|
||||
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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <rpc/clnt.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Create an arbitrary hostname that's longer than fits in sun_path. */
|
||||
char name [sizeof ((struct sockaddr_un*)0)->sun_path * 2];
|
||||
memset (name, 'x', sizeof name - 1);
|
||||
name [sizeof name - 1] = '\0';
|
||||
|
||||
errno = 0;
|
||||
CLIENT *clnt = clnt_create (name, 0, 0, "unix");
|
||||
|
||||
TEST_VERIFY (clnt == NULL);
|
||||
TEST_COMPARE (errno, EINVAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Test to verify that long path is rejected by svcunix_create (bug 28768).
|
||||
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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <rpc/svc.h>
|
||||
#include <shlib-compat.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
|
||||
/* svcunix_create does not have a default version in linkobj/libc.so. */
|
||||
compat_symbol_reference (libc, svcunix_create, svcunix_create, GLIBC_2_1);
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char pathname[109];
|
||||
memset (pathname, 'x', sizeof (pathname));
|
||||
pathname[sizeof (pathname) - 1] = '\0';
|
||||
|
||||
errno = 0;
|
||||
TEST_VERIFY (svcunix_create (RPC_ANYSOCK, 4096, 4096, pathname) == NULL);
|
||||
TEST_COMPARE (errno, EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -35,6 +35,8 @@ libsupport-routines = \
|
||||
ignore_stderr \
|
||||
next_to_fault \
|
||||
oom_error \
|
||||
resolv_response_context_duplicate \
|
||||
resolv_response_context_free \
|
||||
resolv_test \
|
||||
set_fortify_handler \
|
||||
support-xfstat \
|
||||
@@ -133,6 +135,7 @@ libsupport-routines = \
|
||||
xpthread_join \
|
||||
xpthread_key_create \
|
||||
xpthread_key_delete \
|
||||
xpthread_kill \
|
||||
xpthread_mutex_consistent \
|
||||
xpthread_mutex_destroy \
|
||||
xpthread_mutex_init \
|
||||
|
||||
@@ -41,6 +41,12 @@ struct support_capture_subprocess support_capture_subprocess
|
||||
struct support_capture_subprocess support_capture_subprogram
|
||||
(const char *file, char *const argv[]);
|
||||
|
||||
/* Copy the running program into a setgid binary and run it with CHILD_ID
|
||||
argument. If execution is successful, return the exit status of the child
|
||||
program, otherwise return a non-zero failure exit code. */
|
||||
int support_capture_subprogram_self_sgid
|
||||
(char *child_id);
|
||||
|
||||
/* Deallocate the subprocess data captured by
|
||||
support_capture_subprocess. */
|
||||
void support_capture_subprocess_free (struct support_capture_subprocess *);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Duplicate a response context used in DNS resolver tests.
|
||||
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 <string.h>
|
||||
#include <support/resolv_test.h>
|
||||
#include <support/support.h>
|
||||
|
||||
struct resolv_response_context *
|
||||
resolv_response_context_duplicate (const struct resolv_response_context *ctx)
|
||||
{
|
||||
struct resolv_response_context *result = xmalloc (sizeof (*result));
|
||||
memcpy (result, ctx, sizeof (*result));
|
||||
if (result->client_address != NULL)
|
||||
{
|
||||
result->client_address = xmalloc (result->client_address_length);
|
||||
memcpy (result->client_address, ctx->client_address,
|
||||
result->client_address_length);
|
||||
}
|
||||
result->query_buffer = xmalloc (result->query_length);
|
||||
memcpy (result->query_buffer, ctx->query_buffer, result->query_length);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Free a response context used in DNS resolver tests.
|
||||
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 <stdlib.h>
|
||||
#include <support/resolv_test.h>
|
||||
|
||||
void
|
||||
resolv_response_context_free (struct resolv_response_context *ctx)
|
||||
{
|
||||
free (ctx->query_buffer);
|
||||
free (ctx->client_address);
|
||||
free (ctx);
|
||||
}
|
||||
+39
-24
@@ -181,7 +181,9 @@ resolv_response_init (struct resolv_response_builder *b,
|
||||
b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */
|
||||
if (flags.tc)
|
||||
b->buffer[2] |= 0x02;
|
||||
b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */
|
||||
b->buffer[3] = flags.rcode;
|
||||
if (!flags.clear_ra)
|
||||
b->buffer[3] |= 0x80;
|
||||
if (flags.ad)
|
||||
b->buffer[3] |= 0x20;
|
||||
|
||||
@@ -434,9 +436,9 @@ resolv_response_buffer (const struct resolv_response_builder *b)
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct resolv_response_builder *
|
||||
response_builder_allocate
|
||||
(const unsigned char *query_buffer, size_t query_length)
|
||||
struct resolv_response_builder *
|
||||
resolv_response_builder_allocate (const unsigned char *query_buffer,
|
||||
size_t query_length)
|
||||
{
|
||||
struct resolv_response_builder *b = xmalloc (sizeof (*b));
|
||||
memset (b, 0, offsetof (struct resolv_response_builder, buffer));
|
||||
@@ -445,8 +447,8 @@ response_builder_allocate
|
||||
return b;
|
||||
}
|
||||
|
||||
static void
|
||||
response_builder_free (struct resolv_response_builder *b)
|
||||
void
|
||||
resolv_response_builder_free (struct resolv_response_builder *b)
|
||||
{
|
||||
tdestroy (b->compression_offsets, free);
|
||||
free (b);
|
||||
@@ -661,13 +663,17 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
|
||||
|
||||
struct resolv_response_context ctx =
|
||||
{
|
||||
.test = obj,
|
||||
.client_address = &peer,
|
||||
.client_address_length = peerlen,
|
||||
.query_buffer = query,
|
||||
.query_length = length,
|
||||
.server_index = server_index,
|
||||
.tcp = false,
|
||||
.edns = qinfo.edns,
|
||||
};
|
||||
struct resolv_response_builder *b = response_builder_allocate (query, length);
|
||||
struct resolv_response_builder *b
|
||||
= resolv_response_builder_allocate (query, length);
|
||||
obj->config.response_callback
|
||||
(&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
|
||||
|
||||
@@ -684,7 +690,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
|
||||
if (b->offset >= 12)
|
||||
printf ("info: UDP server %d: sending response:"
|
||||
" %zu bytes, RCODE %d (for %s/%u/%u)\n",
|
||||
server_index, b->offset, b->buffer[3] & 0x0f,
|
||||
ctx.server_index, b->offset, b->buffer[3] & 0x0f,
|
||||
qinfo.qname, qinfo.qclass, qinfo.qtype);
|
||||
else
|
||||
printf ("info: UDP server %d: sending response: %zu bytes"
|
||||
@@ -694,23 +700,31 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
|
||||
if (b->truncate_bytes > 0)
|
||||
printf ("info: truncated by %u bytes\n", b->truncate_bytes);
|
||||
}
|
||||
size_t to_send = b->offset;
|
||||
if (to_send < b->truncate_bytes)
|
||||
to_send = 0;
|
||||
else
|
||||
to_send -= b->truncate_bytes;
|
||||
|
||||
/* Ignore most errors here because the other end may have closed
|
||||
the socket. */
|
||||
if (sendto (obj->servers[server_index].socket_udp,
|
||||
b->buffer, to_send, 0,
|
||||
(struct sockaddr *) &peer, peerlen) < 0)
|
||||
TEST_VERIFY_EXIT (errno != EBADF);
|
||||
resolv_response_send_udp (&ctx, b);
|
||||
}
|
||||
response_builder_free (b);
|
||||
resolv_response_builder_free (b);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
resolv_response_send_udp (const struct resolv_response_context *ctx,
|
||||
struct resolv_response_builder *b)
|
||||
{
|
||||
TEST_VERIFY_EXIT (!ctx->tcp);
|
||||
size_t to_send = b->offset;
|
||||
if (to_send < b->truncate_bytes)
|
||||
to_send = 0;
|
||||
else
|
||||
to_send -= b->truncate_bytes;
|
||||
|
||||
/* Ignore most errors here because the other end may have closed
|
||||
the socket. */
|
||||
if (sendto (ctx->test->servers[ctx->server_index].socket_udp,
|
||||
b->buffer, to_send, 0,
|
||||
ctx->client_address, ctx->client_address_length) < 0)
|
||||
TEST_VERIFY_EXIT (errno != EBADF);
|
||||
}
|
||||
|
||||
/* UDP thread_callback function. Variant for one thread per
|
||||
server. */
|
||||
static void
|
||||
@@ -897,14 +911,15 @@ server_thread_tcp_client (void *arg)
|
||||
|
||||
struct resolv_response_context ctx =
|
||||
{
|
||||
.test = closure->obj,
|
||||
.query_buffer = query_buffer,
|
||||
.query_length = query_length,
|
||||
.server_index = closure->server_index,
|
||||
.tcp = true,
|
||||
.edns = qinfo.edns,
|
||||
};
|
||||
struct resolv_response_builder *b = response_builder_allocate
|
||||
(query_buffer, query_length);
|
||||
struct resolv_response_builder *b
|
||||
= resolv_response_builder_allocate (query_buffer, query_length);
|
||||
closure->obj->config.response_callback
|
||||
(&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
|
||||
|
||||
@@ -936,7 +951,7 @@ server_thread_tcp_client (void *arg)
|
||||
writev_fully (closure->client_socket, buffers, 2);
|
||||
}
|
||||
bool close_flag = b->close;
|
||||
response_builder_free (b);
|
||||
resolv_response_builder_free (b);
|
||||
free (query_buffer);
|
||||
if (close_flag)
|
||||
break;
|
||||
|
||||
+36
-5
@@ -35,25 +35,36 @@ struct resolv_edns_info
|
||||
uint16_t payload_size;
|
||||
};
|
||||
|
||||
/* This opaque struct collects information about the resolver testing
|
||||
currently in progress. */
|
||||
struct resolv_test;
|
||||
|
||||
/* This struct provides context information when the response callback
|
||||
specified in struct resolv_redirect_config is invoked. */
|
||||
struct resolv_response_context
|
||||
{
|
||||
const unsigned char *query_buffer;
|
||||
struct resolv_test *test;
|
||||
void *client_address;
|
||||
size_t client_address_length;
|
||||
unsigned char *query_buffer;
|
||||
size_t query_length;
|
||||
int server_index;
|
||||
bool tcp;
|
||||
struct resolv_edns_info edns;
|
||||
};
|
||||
|
||||
/* Produces a deep copy of the context. */
|
||||
struct resolv_response_context *
|
||||
resolv_response_context_duplicate (const struct resolv_response_context *);
|
||||
|
||||
/* Frees the copy. For the context passed to the response function,
|
||||
this happens implicitly. */
|
||||
void resolv_response_context_free (struct resolv_response_context *);
|
||||
|
||||
/* This opaque struct is used to construct responses from within the
|
||||
response callback function. */
|
||||
struct resolv_response_builder;
|
||||
|
||||
/* This opaque struct collects information about the resolver testing
|
||||
currently in progress. */
|
||||
struct resolv_test;
|
||||
|
||||
enum
|
||||
{
|
||||
/* Maximum number of test servers supported by the framework. */
|
||||
@@ -137,6 +148,10 @@ struct resolv_response_flags
|
||||
/* If true, the AD (authenticated data) flag will be set. */
|
||||
bool ad;
|
||||
|
||||
/* If true, do not set the RA (recursion available) flag in the
|
||||
response. */
|
||||
bool clear_ra;
|
||||
|
||||
/* Initial section count values. Can be used to artificially
|
||||
increase the counts, for malformed packet testing.*/
|
||||
unsigned short qdcount;
|
||||
@@ -188,6 +203,22 @@ void resolv_response_close (struct resolv_response_builder *);
|
||||
/* The size of the response packet built so far. */
|
||||
size_t resolv_response_length (const struct resolv_response_builder *);
|
||||
|
||||
/* Allocates a response builder tied to a specific query packet,
|
||||
starting at QUERY_BUFFER, containing QUERY_LENGTH bytes. */
|
||||
struct resolv_response_builder *
|
||||
resolv_response_builder_allocate (const unsigned char *query_buffer,
|
||||
size_t query_length);
|
||||
|
||||
/* Deallocates a response buffer. */
|
||||
void resolv_response_builder_free (struct resolv_response_builder *);
|
||||
|
||||
/* Sends a UDP response using a specific context. This can be used to
|
||||
reorder or duplicate responses, along with
|
||||
resolv_response_context_duplicate and
|
||||
response_builder_allocate. */
|
||||
void resolv_response_send_udp (const struct resolv_response_context *,
|
||||
struct resolv_response_builder *);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* SUPPORT_RESOLV_TEST_H */
|
||||
|
||||
@@ -38,6 +38,11 @@ struct support_subprocess support_subprocess
|
||||
struct support_subprocess support_subprogram
|
||||
(const char *file, char *const argv[]);
|
||||
|
||||
/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it
|
||||
to complete. Return program exit status. */
|
||||
int support_subprogram_wait
|
||||
(const char *file, char *const argv[]);
|
||||
|
||||
/* Wait for the subprocess indicated by PROC::PID. Return the status
|
||||
indicate by waitpid call. */
|
||||
int support_process_wait (struct support_subprocess *proc);
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
#include <support/capture_subprocess.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <support/xsocket.h>
|
||||
#include <support/xspawn.h>
|
||||
#include <support/support.h>
|
||||
#include <support/test-driver.h>
|
||||
|
||||
static void
|
||||
transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
|
||||
@@ -36,7 +39,7 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
|
||||
if (ret < 0)
|
||||
{
|
||||
support_record_failure ();
|
||||
printf ("error: reading from subprocess %s: %m", what);
|
||||
printf ("error: reading from subprocess %s: %m\n", what);
|
||||
pfd->events = 0;
|
||||
pfd->revents = 0;
|
||||
}
|
||||
@@ -102,6 +105,129 @@ support_capture_subprogram (const char *file, char *const argv[])
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Copies the executable into a restricted directory, so that we can
|
||||
safely make it SGID with the TARGET group ID. Then runs the
|
||||
executable. */
|
||||
static int
|
||||
copy_and_spawn_sgid (char *child_id, gid_t gid)
|
||||
{
|
||||
char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
|
||||
test_dir, (intmax_t) getpid ());
|
||||
char *execname = xasprintf ("%s/bin", dirname);
|
||||
int infd = -1;
|
||||
int outfd = -1;
|
||||
int ret = 1, status = 1;
|
||||
|
||||
TEST_VERIFY (mkdir (dirname, 0700) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
|
||||
infd = open ("/proc/self/exe", O_RDONLY);
|
||||
if (infd < 0)
|
||||
FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n");
|
||||
|
||||
outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
|
||||
TEST_VERIFY (outfd >= 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
|
||||
char buf[4096];
|
||||
for (;;)
|
||||
{
|
||||
ssize_t rdcount = read (infd, buf, sizeof (buf));
|
||||
TEST_VERIFY (rdcount >= 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
if (rdcount == 0)
|
||||
break;
|
||||
char *p = buf;
|
||||
char *end = buf + rdcount;
|
||||
while (p != end)
|
||||
{
|
||||
ssize_t wrcount = write (outfd, buf, end - p);
|
||||
if (wrcount == 0)
|
||||
errno = ENOSPC;
|
||||
TEST_VERIFY (wrcount > 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
p += wrcount;
|
||||
}
|
||||
}
|
||||
TEST_VERIFY (fchown (outfd, getuid (), gid) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
TEST_VERIFY (fchmod (outfd, 02750) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
TEST_VERIFY (close (outfd) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
TEST_VERIFY (close (infd) == 0);
|
||||
if (support_record_failure_is_failed ())
|
||||
goto err;
|
||||
|
||||
/* We have the binary, now spawn the subprocess. Avoid using
|
||||
support_subprogram because we only want the program exit status, not the
|
||||
contents. */
|
||||
ret = 0;
|
||||
|
||||
char * const args[] = {execname, child_id, NULL};
|
||||
|
||||
status = support_subprogram_wait (args[0], args);
|
||||
|
||||
err:
|
||||
if (outfd >= 0)
|
||||
close (outfd);
|
||||
if (infd >= 0)
|
||||
close (infd);
|
||||
if (execname != NULL)
|
||||
{
|
||||
unlink (execname);
|
||||
free (execname);
|
||||
}
|
||||
if (dirname != NULL)
|
||||
{
|
||||
rmdir (dirname);
|
||||
free (dirname);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
FAIL_EXIT1("Failed to make sgid executable for test\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int
|
||||
support_capture_subprogram_self_sgid (char *child_id)
|
||||
{
|
||||
gid_t target = 0;
|
||||
const int count = 64;
|
||||
gid_t groups[count];
|
||||
|
||||
/* Get a GID which is not our current GID, but is present in the
|
||||
supplementary group list. */
|
||||
int ret = getgroups (count, groups);
|
||||
if (ret < 0)
|
||||
FAIL_UNSUPPORTED("Could not get group list for user %jd\n",
|
||||
(intmax_t) getuid ());
|
||||
|
||||
gid_t current = getgid ();
|
||||
for (int i = 0; i < ret; ++i)
|
||||
{
|
||||
if (groups[i] != current)
|
||||
{
|
||||
target = groups[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == 0)
|
||||
FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
|
||||
(intmax_t) getuid ());
|
||||
|
||||
return copy_and_spawn_sgid (child_id, target);
|
||||
}
|
||||
|
||||
void
|
||||
support_capture_subprocess_free (struct support_capture_subprocess *p)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <support/subprocess.h>
|
||||
|
||||
static struct support_subprocess
|
||||
support_suprocess_init (void)
|
||||
support_subprocess_init (void)
|
||||
{
|
||||
struct support_subprocess result;
|
||||
|
||||
@@ -48,7 +48,7 @@ support_suprocess_init (void)
|
||||
struct support_subprocess
|
||||
support_subprocess (void (*callback) (void *), void *closure)
|
||||
{
|
||||
struct support_subprocess result = support_suprocess_init ();
|
||||
struct support_subprocess result = support_subprocess_init ();
|
||||
|
||||
result.pid = xfork ();
|
||||
if (result.pid == 0)
|
||||
@@ -71,7 +71,7 @@ support_subprocess (void (*callback) (void *), void *closure)
|
||||
struct support_subprocess
|
||||
support_subprogram (const char *file, char *const argv[])
|
||||
{
|
||||
struct support_subprocess result = support_suprocess_init ();
|
||||
struct support_subprocess result = support_subprocess_init ();
|
||||
|
||||
posix_spawn_file_actions_t fa;
|
||||
/* posix_spawn_file_actions_init does not fail. */
|
||||
@@ -84,7 +84,7 @@ support_subprogram (const char *file, char *const argv[])
|
||||
xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
|
||||
xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
|
||||
|
||||
result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
|
||||
result.pid = xposix_spawn (file, &fa, NULL, argv, environ);
|
||||
|
||||
xclose (result.stdout_pipe[1]);
|
||||
xclose (result.stderr_pipe[1]);
|
||||
@@ -92,6 +92,19 @@ support_subprogram (const char *file, char *const argv[])
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
support_subprogram_wait (const char *file, char *const argv[])
|
||||
{
|
||||
posix_spawn_file_actions_t fa;
|
||||
|
||||
posix_spawn_file_actions_init (&fa);
|
||||
struct support_subprocess res = support_subprocess_init ();
|
||||
|
||||
res.pid = xposix_spawn (file, &fa, NULL, argv, environ);
|
||||
|
||||
return support_process_wait (&res);
|
||||
}
|
||||
|
||||
int
|
||||
support_process_wait (struct support_subprocess *proc)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/* pthread_kill with error checking.
|
||||
Copyright (C) 2021 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 <support/xthread.h>
|
||||
|
||||
void
|
||||
xpthread_kill (pthread_t thr, int signo)
|
||||
{
|
||||
xpthread_check_return ("pthread_kill", pthread_kill (thr, signo));
|
||||
}
|
||||
@@ -75,6 +75,8 @@ void xpthread_attr_setstacksize (pthread_attr_t *attr,
|
||||
void xpthread_attr_setguardsize (pthread_attr_t *attr,
|
||||
size_t guardsize);
|
||||
|
||||
void xpthread_kill (pthread_t thr, int signo);
|
||||
|
||||
/* Set the stack size in ATTR to a small value, but still large enough
|
||||
to cover most internal glibc stack usage. */
|
||||
void support_set_small_thread_stack_size (pthread_attr_t *attr);
|
||||
|
||||
@@ -46,7 +46,7 @@ ENTRY (__longjmp)
|
||||
cfi_offset(d14, JB_D14<<3)
|
||||
cfi_offset(d15, JB_D15<<3)
|
||||
|
||||
DELOUSE (0)
|
||||
PTR_ARG (0)
|
||||
|
||||
ldp x19, x20, [x0, #JB_X19<<3]
|
||||
ldp x21, x22, [x0, #JB_X21<<3]
|
||||
|
||||
+52
-19
@@ -19,43 +19,76 @@
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
static int
|
||||
enable_bti (struct link_map *map, const char *program)
|
||||
/* See elf/dl-load.h. */
|
||||
#ifndef MAP_COPY
|
||||
# define MAP_COPY (MAP_PRIVATE | MAP_DENYWRITE)
|
||||
#endif
|
||||
|
||||
/* Enable BTI protection for MAP. */
|
||||
|
||||
void
|
||||
_dl_bti_protect (struct link_map *map, int fd)
|
||||
{
|
||||
const size_t pagesz = GLRO(dl_pagesize);
|
||||
const ElfW(Phdr) *phdr;
|
||||
unsigned prot;
|
||||
|
||||
for (phdr = map->l_phdr; phdr < &map->l_phdr[map->l_phnum]; ++phdr)
|
||||
if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X))
|
||||
{
|
||||
void *start = (void *) (phdr->p_vaddr + map->l_addr);
|
||||
size_t len = phdr->p_memsz;
|
||||
size_t vstart = ALIGN_DOWN (phdr->p_vaddr, pagesz);
|
||||
size_t vend = ALIGN_UP (phdr->p_vaddr + phdr->p_filesz, pagesz);
|
||||
off_t off = ALIGN_DOWN (phdr->p_offset, pagesz);
|
||||
void *start = (void *) (vstart + map->l_addr);
|
||||
size_t len = vend - vstart;
|
||||
|
||||
prot = PROT_EXEC | PROT_BTI;
|
||||
unsigned prot = PROT_EXEC | PROT_BTI;
|
||||
if (phdr->p_flags & PF_R)
|
||||
prot |= PROT_READ;
|
||||
if (phdr->p_flags & PF_W)
|
||||
prot |= PROT_WRITE;
|
||||
|
||||
if (__mprotect (start, len, prot) < 0)
|
||||
{
|
||||
if (program)
|
||||
_dl_fatal_printf ("%s: mprotect failed to turn on BTI\n",
|
||||
map->l_name);
|
||||
else
|
||||
_dl_signal_error (errno, map->l_name, "dlopen",
|
||||
N_("mprotect failed to turn on BTI"));
|
||||
}
|
||||
if (fd == -1)
|
||||
/* Ignore failures for kernel mapped binaries. */
|
||||
__mprotect (start, len, prot);
|
||||
else
|
||||
map->l_mach.bti_fail = __mmap (start, len, prot,
|
||||
MAP_FIXED|MAP_COPY|MAP_FILE,
|
||||
fd, off) == MAP_FAILED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enable BTI for L if required. */
|
||||
|
||||
static void
|
||||
bti_failed (struct link_map *l, const char *program)
|
||||
{
|
||||
if (program)
|
||||
_dl_fatal_printf ("%s: %s: failed to turn on BTI protection\n",
|
||||
program, l->l_name);
|
||||
else
|
||||
/* Note: the errno value is not available any more. */
|
||||
_dl_signal_error (0, l->l_name, "dlopen",
|
||||
N_("failed to turn on BTI protection"));
|
||||
}
|
||||
|
||||
|
||||
/* Enable BTI for L and its dependencies. */
|
||||
|
||||
void
|
||||
_dl_bti_check (struct link_map *l, const char *program)
|
||||
{
|
||||
if (GLRO(dl_aarch64_cpu_features).bti && l->l_mach.bti)
|
||||
enable_bti (l, program);
|
||||
if (!GLRO(dl_aarch64_cpu_features).bti)
|
||||
return;
|
||||
|
||||
if (l->l_mach.bti_fail)
|
||||
bti_failed (l, program);
|
||||
|
||||
unsigned int i = l->l_searchlist.r_nlist;
|
||||
while (i-- > 0)
|
||||
{
|
||||
struct link_map *dep = l->l_initfini[i];
|
||||
if (dep->l_mach.bti_fail)
|
||||
bti_failed (dep, program);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,13 +395,6 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
/* Check for unexpected PLT reloc type. */
|
||||
if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
|
||||
{
|
||||
if (map->l_mach.plt == 0)
|
||||
{
|
||||
/* Prelinking. */
|
||||
*reloc_addr += l_addr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL))
|
||||
{
|
||||
/* Check the symbol table for variant PCS symbols. */
|
||||
@@ -425,7 +418,10 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
}
|
||||
}
|
||||
|
||||
*reloc_addr = map->l_mach.plt;
|
||||
if (map->l_mach.plt == 0)
|
||||
*reloc_addr += l_addr;
|
||||
else
|
||||
*reloc_addr = map->l_mach.plt;
|
||||
}
|
||||
else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
|
||||
{
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#ifndef _DL_PROP_H
|
||||
#define _DL_PROP_H
|
||||
|
||||
extern void _dl_bti_protect (struct link_map *, int) attribute_hidden;
|
||||
|
||||
extern void _dl_bti_check (struct link_map *, const char *)
|
||||
attribute_hidden;
|
||||
|
||||
@@ -35,14 +37,18 @@ _dl_open_check (struct link_map *m)
|
||||
}
|
||||
|
||||
static inline void __attribute__ ((always_inline))
|
||||
_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
|
||||
_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int
|
||||
_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz,
|
||||
void *data)
|
||||
_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type,
|
||||
uint32_t datasz, void *data)
|
||||
{
|
||||
if (!GLRO(dl_aarch64_cpu_features).bti)
|
||||
/* Skip note processing. */
|
||||
return 0;
|
||||
|
||||
if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
|
||||
{
|
||||
/* Stop if the property note is ill-formed. */
|
||||
@@ -51,7 +57,7 @@ _dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz,
|
||||
|
||||
unsigned int feature_1 = *(unsigned int *) data;
|
||||
if (feature_1 & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
|
||||
l->l_mach.bti = true;
|
||||
_dl_bti_protect (l, fd);
|
||||
|
||||
/* Stop if we processed the property note. */
|
||||
return 0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user