mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-08 23:58:31 +08:00
Compare commits
227
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33cb9de5cb | ||
|
|
47e61ba772 | ||
|
|
b63904f34f | ||
|
|
807b692012 | ||
|
|
bbce0c75f3 | ||
|
|
dc23cc8021 | ||
|
|
da7a5b5f4d | ||
|
|
7701243cce | ||
|
|
1861652b2e | ||
|
|
ae90dd111b | ||
|
|
c38427f52d | ||
|
|
de51f7328e | ||
|
|
bd8fac4e28 | ||
|
|
d7d9ee6edc | ||
|
|
32c64139ee | ||
|
|
e0bde77854 | ||
|
|
a05a3def72 | ||
|
|
1eb01283dd | ||
|
|
f1d4e42835 | ||
|
|
4661ab7a69 | ||
|
|
eb7d21e59b | ||
|
|
36d565f7e3 | ||
|
|
5e606fb79c | ||
|
|
040bc860fe | ||
|
|
abb1d6bb41 | ||
|
|
3e833b93fd | ||
|
|
9d6a71514d | ||
|
|
44388a14fc | ||
|
|
4deaee41ce | ||
|
|
cf6c44c38c | ||
|
|
3715670ec0 | ||
|
|
096943551e | ||
|
|
b9af312764 | ||
|
|
d94c03efc5 | ||
|
|
24071d2e2f | ||
|
|
d0cc3969d4 | ||
|
|
681ddc91e1 | ||
|
|
647e35b6ab | ||
|
|
046ce0eb11 | ||
|
|
82f650eec8 | ||
|
|
025e8cb8d9 | ||
|
|
10247e0d2f | ||
|
|
c14096c2d3 | ||
|
|
e252e5f082 | ||
|
|
81c2de89c6 | ||
|
|
0b5f254b4d | ||
|
|
0946809134 | ||
|
|
b2b6a773fe | ||
|
|
42a7a4f7b8 | ||
|
|
41965d796f | ||
|
|
3fb3ff7f38 | ||
|
|
2f33e8ec62 | ||
|
|
adf9bd54e9 | ||
|
|
8b79bc92fa | ||
|
|
3244a1fc19 | ||
|
|
0f2a4c9573 | ||
|
|
cd345f5c03 | ||
|
|
c0ba8ad1fe | ||
|
|
cf95053a83 | ||
|
|
bcc70e4b2b | ||
|
|
1b8d019265 | ||
|
|
8f6565fa27 | ||
|
|
8e860da0db | ||
|
|
cb78f7d9d3 | ||
|
|
83cc56b97a | ||
|
|
1ffce991bd | ||
|
|
0400bcd764 | ||
|
|
5042604a1e | ||
|
|
7cbc4d39fe | ||
|
|
faee37cd4c | ||
|
|
9bf00c58bc | ||
|
|
a5750ba400 | ||
|
|
90c5142f77 | ||
|
|
055042833f | ||
|
|
f70a0f9a14 | ||
|
|
607b660f89 | ||
|
|
4960cacb70 | ||
|
|
b4e28743ec | ||
|
|
7f6564cd80 | ||
|
|
871fb8be01 | ||
|
|
0b888aef9a | ||
|
|
60c96035ff | ||
|
|
4b5b494ecc | ||
|
|
c5a8ab5ffa | ||
|
|
93efaa5bdc | ||
|
|
4b0cb26b3b | ||
|
|
88e0b1d81b | ||
|
|
61de2a5e84 | ||
|
|
56d37dff38 | ||
|
|
d816620531 | ||
|
|
655faf81b2 | ||
|
|
ded659bdea | ||
|
|
fba741bfba | ||
|
|
a909a33a81 | ||
|
|
b811a41c57 | ||
|
|
2b0a2bff60 | ||
|
|
868b753880 | ||
|
|
04d2fec011 | ||
|
|
ea32619881 | ||
|
|
6642c41779 | ||
|
|
666bf6a0fa | ||
|
|
e1a82e3984 | ||
|
|
2d432f9815 | ||
|
|
8d8d807e96 | ||
|
|
780a9a68ba | ||
|
|
92800f675f | ||
|
|
1c3eed557e | ||
|
|
20829a45c1 | ||
|
|
479ccba5b1 | ||
|
|
1e3d999b59 | ||
|
|
f0170f034e | ||
|
|
ae42378808 | ||
|
|
595e1c3b2e | ||
|
|
0e0b1ae9d1 | ||
|
|
4ec714ea87 | ||
|
|
3ad99c9112 | ||
|
|
f750e14d55 | ||
|
|
69711df0c6 | ||
|
|
c7f259679a | ||
|
|
c75b4885df | ||
|
|
039f2bdd89 | ||
|
|
e5b22d23d1 | ||
|
|
58759a422f | ||
|
|
aef25bb30d | ||
|
|
3f6b5d8644 | ||
|
|
695bf0b81e | ||
|
|
76bf2cf7a5 | ||
|
|
e5dd73fc82 | ||
|
|
7381b20495 | ||
|
|
341b7670c8 | ||
|
|
78c03c7974 | ||
|
|
8d04c0e9e9 | ||
|
|
ad946943ce | ||
|
|
fe37bbda29 | ||
|
|
7ae55dc0aa | ||
|
|
d4a845daaf | ||
|
|
69ecb7b4a3 | ||
|
|
2a287534c1 | ||
|
|
65c576e7e5 | ||
|
|
44d649d3c4 | ||
|
|
4054cc2093 | ||
|
|
1e5c704ec7 | ||
|
|
eee747d8cc | ||
|
|
8491c1adc9 | ||
|
|
5ba5d609c1 | ||
|
|
17034ac2bf | ||
|
|
13de83e5cf | ||
|
|
6349c03d42 | ||
|
|
aecfbacba2 | ||
|
|
c505926c31 | ||
|
|
b8020168b5 | ||
|
|
26be8f8a56 | ||
|
|
1fb0a36902 | ||
|
|
5aa16bb318 | ||
|
|
2ba9801d9f | ||
|
|
0f90d6204d | ||
|
|
70410f2286 | ||
|
|
36cc06341a | ||
|
|
2fce85f67c | ||
|
|
dd4131c832 | ||
|
|
4c6a78adda | ||
|
|
a1dc0be03c | ||
|
|
7b7dfbb0cb | ||
|
|
9273b2d0e9 | ||
|
|
b357157361 | ||
|
|
19535f3b57 | ||
|
|
908454129d | ||
|
|
2681d38caf | ||
|
|
700d3281f9 | ||
|
|
3e27919274 | ||
|
|
2bd815d834 | ||
|
|
2d8ef784bd | ||
|
|
923c3f3c37 | ||
|
|
d9196d4f3f | ||
|
|
d8bf4388df | ||
|
|
29c577e0f5 | ||
|
|
7afbd1e56a | ||
|
|
46479e5d10 | ||
|
|
18bec23cbb | ||
|
|
cdc496eb55 | ||
|
|
d1d8379bff | ||
|
|
76e05613ee | ||
|
|
227c903587 | ||
|
|
2628500f5d | ||
|
|
52c037f357 | ||
|
|
da5f134f6d | ||
|
|
d1241cf001 | ||
|
|
7a3f8c8a7a | ||
|
|
4b95b6e8bb | ||
|
|
df51334828 | ||
|
|
5d885617ce | ||
|
|
a7fa604f30 | ||
|
|
c5cdb39c20 | ||
|
|
e2ec6a8db3 | ||
|
|
7a236dc44a | ||
|
|
78c8ef21fa | ||
|
|
5165080fec | ||
|
|
77f523c473 | ||
|
|
b714ab7e3c | ||
|
|
f0e9657067 | ||
|
|
adb69f8ffe | ||
|
|
20ec40a51d | ||
|
|
3c9b4004e2 | ||
|
|
bffc33e90e | ||
|
|
9d7eebde8f | ||
|
|
c399271c10 | ||
|
|
b46412fb17 | ||
|
|
645d94808a | ||
|
|
b3736d1a3c | ||
|
|
3c791f2031 | ||
|
|
924e4f3eaa | ||
|
|
b0e7888d1f | ||
|
|
3bd3c612e9 | ||
|
|
bb1e8b0ca9 | ||
|
|
d48813227b | ||
|
|
4dad97e2a2 | ||
|
|
1cc5513114 | ||
|
|
0062e7dd1c | ||
|
|
5c62874f42 | ||
|
|
d13a7a6f10 | ||
|
|
8b139cd4f1 | ||
|
|
e982657073 | ||
|
|
302bc33bc5 | ||
|
|
ac47d8f6cf | ||
|
|
c74bb93cfd | ||
|
|
33f1b4c145 | ||
|
|
c3fda489cf |
+17
-1
@@ -43,6 +43,22 @@ else
|
||||
$(error objdir must be defined by the build-directory Makefile)
|
||||
endif
|
||||
|
||||
# Did we request 'make -s' run? "yes" or "no".
|
||||
# Starting from make-4.4 MAKEFLAGS now contains long
|
||||
# options like '--shuffle'. To detect presence of 's'
|
||||
# we pick first word with short options. Long options
|
||||
# are guaranteed to come after whitespace. We use '-'
|
||||
# prefix to always have a word before long options
|
||||
# even if no short options were passed.
|
||||
# Typical MAKEFLAGS values to watch for:
|
||||
# "rs --shuffle=42" (silent)
|
||||
# " --shuffle" (not silent)
|
||||
ifeq ($(findstring s, $(firstword -$(MAKEFLAGS))),)
|
||||
silent-make := no
|
||||
else
|
||||
silent-make := yes
|
||||
endif
|
||||
|
||||
# Root of the sysdeps tree.
|
||||
sysdep_dir := $(..)sysdeps
|
||||
export sysdep_dir := $(sysdep_dir)
|
||||
@@ -917,7 +933,7 @@ endif
|
||||
# umpteen zillion filenames along with it (we use `...' instead)
|
||||
# but we don't want this echoing done when the user has said
|
||||
# he doesn't want to see commands echoed by using -s.
|
||||
ifneq "$(findstring s,$(MAKEFLAGS))" "" # if -s
|
||||
ifeq ($(silent-make),yes) # if -s
|
||||
+cmdecho := echo >/dev/null
|
||||
else # not -s
|
||||
+cmdecho := echo
|
||||
|
||||
@@ -794,7 +794,7 @@ endif
|
||||
# Maximize efficiency by minimizing the number of rules.
|
||||
.SUFFIXES: # Clear the suffix list. We don't use suffix rules.
|
||||
# Don't define any builtin rules.
|
||||
MAKEFLAGS := $(MAKEFLAGS)r
|
||||
MAKEFLAGS := $(MAKEFLAGS) -r
|
||||
|
||||
# Generic rule for making directories.
|
||||
%/:
|
||||
@@ -811,7 +811,7 @@ MAKEFLAGS := $(MAKEFLAGS)r
|
||||
.PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c))
|
||||
|
||||
# Use the verbose option of ar and tar when not running silently.
|
||||
ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s
|
||||
ifeq ($(silent-make),no) # if not -s
|
||||
verbose := v
|
||||
else # -s
|
||||
verbose :=
|
||||
@@ -1002,7 +1002,7 @@ endef
|
||||
define make-link-multidir
|
||||
$(patsubst %/,cd %,$(objpfx)); \
|
||||
$(addprefix $(abspath $(..)scripts/mkinstalldirs) ,$(dir $(multidir))); \
|
||||
$(LN_S) . $(multidir) 2> /dev/null; \
|
||||
$(SHELL) $(abspath $(..)scripts/rellns-sh) . $(multidir) 2> /dev/null; \
|
||||
test -L $(multidir)
|
||||
endef
|
||||
else
|
||||
|
||||
@@ -5,6 +5,49 @@ 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.36.1
|
||||
|
||||
Major new features:
|
||||
|
||||
* The getent tool now supports the --no-addrconfig option. The output of
|
||||
getent with --no-addrconfig may contain addresses of families not
|
||||
configured on the current host i.e. as-if you had not passed
|
||||
AI_ADDRCONFIG to getaddrinfo calls.
|
||||
|
||||
Security related changes:
|
||||
|
||||
CVE-2022-39046: When the syslog function is passed a crafted input
|
||||
string larger than 1024 bytes, it reads uninitialized memory from the
|
||||
heap and prints it to the target log file, potentially revealing a
|
||||
portion of the contents of the heap.
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[12154] Do not fail DNS resolution for CNAMEs which are not host names
|
||||
[24816] Fix tst-nss-files-hosts-long on single-stack hosts
|
||||
[28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning
|
||||
[29305] Conserve NSS buffer space during DNS packet parsing
|
||||
[29415] nscd: Fix netlink cache invalidation if epoll is used
|
||||
[28937] New DSO dependency sorter does not put new map first if in a cycle
|
||||
[29446] _dlopen now ignores dl_caller argument in static mode
|
||||
[29485] Linux: Terminate subprocess on late failure in tst-pidfd
|
||||
[29490] alpha: New __brk_call implementation is broken
|
||||
[29463] math/test-float128-y1 fails on x86_64
|
||||
[29488] test-ibm128-llround fails on ppc64el when built with gcc-12 and -O2
|
||||
or higher
|
||||
[29528] elf: Call __libc_early_init for reused namespaces
|
||||
[29537] libc: [2.34 regression]: Alignment issue on m68k when using
|
||||
[29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are
|
||||
[29583] Use 64-bit interfaces in gconv_parseconfdir
|
||||
[29600] Do not completely clear reused namespace in dlmopen
|
||||
[29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is
|
||||
enabled
|
||||
[29638] libc: stdlib: arc4random fallback is never used
|
||||
[29657] libc: Incorrect struct stat for 64-bit time on linux/generic
|
||||
platforms
|
||||
[29730] broken y2038 support in fstatat on MIPS N64
|
||||
[29771] Restore IPC_64 support in sysvipc *ctl functions
|
||||
|
||||
Version 2.36
|
||||
|
||||
Major new features:
|
||||
|
||||
+33
-7
@@ -245,6 +245,12 @@ struct cmsghdr
|
||||
+ CMSG_ALIGN (sizeof (struct cmsghdr)))
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
|
||||
|
||||
/* Given a length, return the additional padding necessary such that
|
||||
len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */
|
||||
#define __CMSG_PADDING(len) ((sizeof (size_t) \
|
||||
- ((len) & (sizeof (size_t) - 1))) \
|
||||
& (sizeof (size_t) - 1))
|
||||
|
||||
extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
struct cmsghdr *__cmsg) __THROW;
|
||||
#ifdef __USE_EXTERN_INLINES
|
||||
@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
|
||||
_EXTERN_INLINE struct cmsghdr *
|
||||
__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
|
||||
{
|
||||
/* We may safely assume that __cmsg lies between __mhdr->msg_control and
|
||||
__mhdr->msg_controllen because the user is required to obtain the first
|
||||
cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs
|
||||
via CMSG_NXTHDR, setting lengths along the way. However, we don't yet
|
||||
trust the value of __cmsg->cmsg_len and therefore do not use it in any
|
||||
pointer arithmetic until we check its value. */
|
||||
|
||||
unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control;
|
||||
unsigned char * __cmsg_ptr = (unsigned char *) __cmsg;
|
||||
|
||||
size_t __size_needed = sizeof (struct cmsghdr)
|
||||
+ __CMSG_PADDING (__cmsg->cmsg_len);
|
||||
|
||||
/* The current header is malformed, too small to be a full header. */
|
||||
if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
|
||||
/* The kernel header does this so there may be a reason. */
|
||||
return (struct cmsghdr *) 0;
|
||||
|
||||
/* There isn't enough space between __cmsg and the end of the buffer to
|
||||
hold the current cmsg *and* the next one. */
|
||||
if (((size_t)
|
||||
(__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr)
|
||||
< __size_needed)
|
||||
|| ((size_t)
|
||||
(__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr
|
||||
- __size_needed)
|
||||
< __cmsg->cmsg_len))
|
||||
|
||||
return (struct cmsghdr *) 0;
|
||||
|
||||
/* Now, we trust cmsg_len and can use it to find the next header. */
|
||||
__cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
|
||||
+ CMSG_ALIGN (__cmsg->cmsg_len));
|
||||
if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
|
||||
+ __mhdr->msg_controllen)
|
||||
|| ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
|
||||
> ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
|
||||
/* No more entries. */
|
||||
return (struct cmsghdr *) 0;
|
||||
return __cmsg;
|
||||
}
|
||||
#endif /* Use `extern inline'. */
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
#define __SYSCALL_ULONG_TYPE __ULONGWORD_TYPE
|
||||
#define __CPU_MASK_TYPE __ULONGWORD_TYPE
|
||||
|
||||
#ifdef __LP64__
|
||||
#if defined __LP64__ || defined __CHERI_PURE_CAPABILITY__
|
||||
/* Tell the libc code that off_t and off64_t are actually the same type
|
||||
for all ABI purposes, even if possibly expressed as different base types
|
||||
for C type-checking purposes. */
|
||||
|
||||
+19
-3
@@ -132,15 +132,15 @@ call_init (int argc, char **argv, char **env)
|
||||
the same file. */
|
||||
|
||||
if (ELF_INITFINI && l->l_info[DT_INIT] != NULL)
|
||||
DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr,
|
||||
DL_CALL_DT_INIT(l, dl_rx_ptr (l, l->l_info[DT_INIT]->d_un.d_ptr),
|
||||
argc, argv, env);
|
||||
|
||||
ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY];
|
||||
if (init_array != NULL)
|
||||
{
|
||||
unsigned int jm
|
||||
= l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
|
||||
ElfW(Addr) *addrs = (void *) (init_array->d_un.d_ptr + l->l_addr);
|
||||
= l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (elfptr_t);
|
||||
elfptr_t *addrs = (void *) dl_rx_ptr (l, init_array->d_un.d_ptr);
|
||||
for (unsigned int j = 0; j < jm; ++j)
|
||||
((dl_init_t) addrs[j]) (argc, argv, env);
|
||||
}
|
||||
@@ -210,11 +210,16 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
|
||||
MAIN_AUXVEC_DECL),
|
||||
int argc,
|
||||
char **argv,
|
||||
#ifdef LIBC_START_MAIN_ENVP_ARG
|
||||
char **envp,
|
||||
#endif
|
||||
#ifdef LIBC_START_MAIN_AUXVEC_ARG
|
||||
ElfW(auxv_t) *auxvec,
|
||||
#endif
|
||||
#ifndef LIBC_START_MAIN_NO_INITFINI_ARG
|
||||
__typeof (main) init,
|
||||
void (*fini) (void),
|
||||
#endif
|
||||
void (*rtld_fini) (void),
|
||||
void *stack_end)
|
||||
__attribute__ ((noreturn));
|
||||
@@ -233,15 +238,24 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
|
||||
STATIC int
|
||||
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||||
int argc, char **argv,
|
||||
#ifdef LIBC_START_MAIN_ENVP_ARG
|
||||
char **envp,
|
||||
#endif
|
||||
#ifdef LIBC_START_MAIN_AUXVEC_ARG
|
||||
ElfW(auxv_t) *auxvec,
|
||||
#endif
|
||||
#ifndef LIBC_START_MAIN_NO_INITFINI_ARG
|
||||
__typeof (main) init,
|
||||
void (*fini) (void),
|
||||
#endif
|
||||
void (*rtld_fini) (void), void *stack_end)
|
||||
{
|
||||
#ifndef SHARED
|
||||
#ifdef LIBC_START_MAIN_ENVP_ARG
|
||||
char **ev = envp;
|
||||
#else
|
||||
char **ev = &argv[argc + 1];
|
||||
#endif
|
||||
|
||||
__environ = ev;
|
||||
|
||||
@@ -358,11 +372,13 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||
GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
|
||||
|
||||
#ifndef LIBC_START_MAIN_NO_INITFINI_ARG
|
||||
if (init != NULL)
|
||||
/* This is a legacy program which supplied its own init
|
||||
routine. */
|
||||
(*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
|
||||
else
|
||||
#endif
|
||||
/* This is a current program. Use the dynamic segment to find
|
||||
constructors. */
|
||||
call_init (argc, argv, __environ);
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ __libc_setup_tls (void)
|
||||
/* Remember the values we need. */
|
||||
memsz = phdr->p_memsz;
|
||||
filesz = phdr->p_filesz;
|
||||
initimage = (void *) phdr->p_vaddr + main_map->l_addr;
|
||||
initimage = (void *) dl_rx_ptr (main_map, phdr->p_vaddr);
|
||||
align = phdr->p_align;
|
||||
if (phdr->p_align > max_align)
|
||||
max_align = phdr->p_align;
|
||||
|
||||
+1
-2
@@ -28,13 +28,12 @@ __wcpcpy_chk (wchar_t *dest, const wchar_t *src, size_t destlen)
|
||||
{
|
||||
wchar_t *wcp = (wchar_t *) dest - 1;
|
||||
wint_t c;
|
||||
const ptrdiff_t off = src - dest + 1;
|
||||
|
||||
do
|
||||
{
|
||||
if (__glibc_unlikely (destlen-- == 0))
|
||||
__chk_fail ();
|
||||
c = wcp[off];
|
||||
c = *src++;
|
||||
*++wcp = c;
|
||||
}
|
||||
while (c != L'\0');
|
||||
|
||||
+7
-27
@@ -24,36 +24,16 @@ wchar_t *
|
||||
__wcscpy_chk (wchar_t *dest, const wchar_t *src, size_t n)
|
||||
{
|
||||
wint_t c;
|
||||
wchar_t *wcp;
|
||||
wchar_t *wcp = dest;
|
||||
|
||||
if (__alignof__ (wchar_t) >= sizeof (wchar_t))
|
||||
do
|
||||
{
|
||||
const ptrdiff_t off = dest - src - 1;
|
||||
|
||||
wcp = (wchar_t *) src;
|
||||
|
||||
do
|
||||
{
|
||||
if (__glibc_unlikely (n-- == 0))
|
||||
__chk_fail ();
|
||||
c = *wcp++;
|
||||
wcp[off] = c;
|
||||
}
|
||||
while (c != L'\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
wcp = dest;
|
||||
|
||||
do
|
||||
{
|
||||
if (__glibc_unlikely (n-- == 0))
|
||||
__chk_fail ();
|
||||
c = *src++;
|
||||
*wcp++ = c;
|
||||
}
|
||||
while (c != L'\0');
|
||||
if (__glibc_unlikely (n-- == 0))
|
||||
__chk_fail ();
|
||||
c = *src++;
|
||||
*wcp++ = c;
|
||||
}
|
||||
while (c != L'\0');
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1);
|
||||
void *
|
||||
__dlopen (const char *file, int mode, void *dl_caller)
|
||||
{
|
||||
return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
|
||||
return dlopen_implementation (file, mode, dl_caller);
|
||||
}
|
||||
|
||||
void *
|
||||
|
||||
+32
-16
@@ -374,6 +374,8 @@ tests += \
|
||||
tst-align \
|
||||
tst-align2 \
|
||||
tst-align3 \
|
||||
tst-audit-tlsdesc \
|
||||
tst-audit-tlsdesc-dlopen \
|
||||
tst-audit1 \
|
||||
tst-audit2 \
|
||||
tst-audit8 \
|
||||
@@ -408,6 +410,7 @@ tests += \
|
||||
tst-dlmopen4 \
|
||||
tst-dlmopen-dlerror \
|
||||
tst-dlmopen-gethostbyname \
|
||||
tst-dlmopen-twice \
|
||||
tst-dlopenfail \
|
||||
tst-dlopenfail-2 \
|
||||
tst-dlopenrpath \
|
||||
@@ -765,6 +768,8 @@ modules-names += \
|
||||
tst-alignmod3 \
|
||||
tst-array2dep \
|
||||
tst-array5dep \
|
||||
tst-audit-tlsdesc-mod1 \
|
||||
tst-audit-tlsdesc-mod2 \
|
||||
tst-audit11mod1 \
|
||||
tst-audit11mod2 \
|
||||
tst-audit12mod1 \
|
||||
@@ -798,6 +803,7 @@ modules-names += \
|
||||
tst-auditmanymod7 \
|
||||
tst-auditmanymod8 \
|
||||
tst-auditmanymod9 \
|
||||
tst-auditmod-tlsdesc \
|
||||
tst-auditmod1 \
|
||||
tst-auditmod9a \
|
||||
tst-auditmod9b \
|
||||
@@ -834,6 +840,8 @@ modules-names += \
|
||||
tst-dlmopen1mod \
|
||||
tst-dlmopen-dlerror-mod \
|
||||
tst-dlmopen-gethostbyname-mod \
|
||||
tst-dlmopen-twice-mod1 \
|
||||
tst-dlmopen-twice-mod2 \
|
||||
tst-dlopenfaillinkmod \
|
||||
tst-dlopenfailmod1 \
|
||||
tst-dlopenfailmod2 \
|
||||
@@ -990,23 +998,8 @@ modules-names += tst-gnu2-tls1mod
|
||||
$(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so
|
||||
tst-gnu2-tls1mod.so-no-z-defs = yes
|
||||
CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2
|
||||
endif # $(have-mtls-dialect-gnu2)
|
||||
|
||||
tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen
|
||||
modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc
|
||||
$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
$(objpfx)tst-audit-tlsdesc-mod2.so \
|
||||
$(shared-thread-library)
|
||||
CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
|
||||
CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
$(objpfx)tst-audit-tlsdesc-mod2.so
|
||||
$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
|
||||
$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
endif
|
||||
ifeq (yes,$(have-protected-data))
|
||||
modules-names += tst-protected1moda tst-protected1modb
|
||||
tests += tst-protected1a tst-protected1b
|
||||
@@ -2967,3 +2960,26 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \
|
||||
grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \
|
||||
&& grep -q '^status: 127$$' $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
$(objpfx)tst-audit-tlsdesc-mod2.so \
|
||||
$(shared-thread-library)
|
||||
ifeq (yes,$(have-mtls-dialect-gnu2))
|
||||
# The test is valid for all TLS types, but we want to exercise GNU2
|
||||
# TLS if possible.
|
||||
CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2
|
||||
CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2
|
||||
endif
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library)
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \
|
||||
$(objpfx)tst-audit-tlsdesc-mod2.so
|
||||
$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so
|
||||
$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so
|
||||
tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so
|
||||
|
||||
tst-dlmopen-twice-ENV = GLIBC_TUNABLES=glibc.rtld.nns=10
|
||||
$(objpfx)tst-dlmopen-twice.out: \
|
||||
$(objpfx)tst-dlmopen-twice-mod1.so \
|
||||
$(objpfx)tst-dlmopen-twice-mod2.so
|
||||
|
||||
@@ -210,6 +210,9 @@ print_entry (const char *lib, int flag, uint64_t hwcap,
|
||||
case FLAG_AARCH64_LIB64:
|
||||
fputs (",AArch64", stdout);
|
||||
break;
|
||||
case FLAG_AARCH64_PURECAP:
|
||||
fputs (",purecap", stdout);
|
||||
break;
|
||||
/* Uses the ARM soft-float ABI. */
|
||||
case FLAG_ARM_LIBSF:
|
||||
fputs (",soft-float", stdout);
|
||||
|
||||
+3
-2
@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name)
|
||||
we are accessing. Therefore we must make the copy of the
|
||||
mapping data without using malloc. */
|
||||
char *temp;
|
||||
temp = alloca (strlen (best) + 1);
|
||||
strcpy (temp, best);
|
||||
size_t best_len = strlen (best) + 1;
|
||||
temp = alloca (best_len);
|
||||
memcpy (temp, best, best_len);
|
||||
return __strdup (temp);
|
||||
}
|
||||
|
||||
|
||||
+4
-6
@@ -119,11 +119,10 @@ call_destructors (void *closure)
|
||||
|
||||
if (map->l_info[DT_FINI_ARRAY] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (map->l_addr
|
||||
+ map->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
elfptr_t *array =
|
||||
(elfptr_t *) dl_rx_ptr (map, map->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
/ sizeof (ElfW(Addr)));
|
||||
/ sizeof (elfptr_t));
|
||||
|
||||
while (sz-- > 0)
|
||||
((fini_t) array[sz]) ();
|
||||
@@ -131,8 +130,7 @@ call_destructors (void *closure)
|
||||
|
||||
/* Next try the old-style destructor. */
|
||||
if (map->l_info[DT_FINI] != NULL)
|
||||
DL_CALL_DT_FINI (map, ((void *) map->l_addr
|
||||
+ map->l_info[DT_FINI]->d_un.d_ptr));
|
||||
DL_CALL_DT_FINI (map, dl_rx_ptr (map, map->l_info[DT_FINI]->d_un.d_ptr));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -105,7 +105,7 @@ _dl_find_object_from_map (struct link_map *l,
|
||||
if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
|
||||
{
|
||||
atomic_store_relaxed (&result->eh_frame,
|
||||
(void *) (ph->p_vaddr + l->l_addr));
|
||||
(void *) dl_rx_ptr (l, ph->p_vaddr));
|
||||
#if DLFO_STRUCT_HAS_EH_COUNT
|
||||
atomic_store_relaxed (&result->eh_count, ph->p_memsz / 8);
|
||||
#endif
|
||||
|
||||
+4
-5
@@ -133,11 +133,10 @@ _dl_fini (void)
|
||||
/* First see whether an array is given. */
|
||||
if (l->l_info[DT_FINI_ARRAY] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (l->l_addr
|
||||
+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
ElfW(Addr) v = l->l_info[DT_FINI_ARRAY]->d_un.d_ptr;
|
||||
elfptr_t *array = (elfptr_t *) dl_rx_ptr (l, v);
|
||||
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
/ sizeof (ElfW(Addr)));
|
||||
/ sizeof (elfptr_t));
|
||||
while (i-- > 0)
|
||||
((fini_t) array[i]) ();
|
||||
}
|
||||
@@ -145,7 +144,7 @@ _dl_fini (void)
|
||||
/* Next try the old-style destructor. */
|
||||
if (ELF_INITFINI && l->l_info[DT_FINI] != NULL)
|
||||
DL_CALL_DT_FINI
|
||||
(l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
|
||||
(l, dl_rx_ptr (l, l->l_info[DT_FINI]->d_un.d_ptr));
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
|
||||
+5
-3
@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||||
/* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix
|
||||
and a "/" suffix once stored in the result. */
|
||||
hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1;
|
||||
size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
|
||||
size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1)
|
||||
+ hwcaps_counts.total_length);
|
||||
|
||||
/* Count the number of bits set in the masked value. */
|
||||
@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||||
assert (m == cnt);
|
||||
|
||||
/* Determine the total size of all strings together. */
|
||||
size_t total;
|
||||
if (cnt == 1)
|
||||
total += temp[0].len + 1;
|
||||
total = temp[0].len + 1;
|
||||
else
|
||||
{
|
||||
total += temp[0].len + temp[cnt - 1].len + 2;
|
||||
total = temp[0].len + temp[cnt - 1].len + 2;
|
||||
if (cnt > 2)
|
||||
{
|
||||
total <<= 1;
|
||||
@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend,
|
||||
/* This is the overall result, including both glibc-hwcaps
|
||||
subdirectories and the legacy hwcaps subdirectories using the
|
||||
power set construction. */
|
||||
total += hwcaps_sz;
|
||||
struct r_strlenpair *overall_result
|
||||
= malloc (*sz * sizeof (*result) + total);
|
||||
if (overall_result == NULL)
|
||||
|
||||
+8
-7
@@ -53,7 +53,8 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
|
||||
- the others in the DT_INIT_ARRAY.
|
||||
*/
|
||||
if (ELF_INITFINI && l->l_info[DT_INIT] != NULL)
|
||||
DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr, argc, argv, env);
|
||||
DL_CALL_DT_INIT(l, dl_rx_ptr (l, l->l_info[DT_INIT]->d_un.d_ptr),
|
||||
argc, argv, env);
|
||||
|
||||
/* Next see whether there is an array with initialization functions. */
|
||||
ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY];
|
||||
@@ -61,11 +62,11 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int jm;
|
||||
ElfW(Addr) *addrs;
|
||||
elfptr_t *addrs;
|
||||
|
||||
jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
|
||||
jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (elfptr_t);
|
||||
|
||||
addrs = (ElfW(Addr) *) (init_array->d_un.d_ptr + l->l_addr);
|
||||
addrs = (elfptr_t *) dl_rx_ptr (l, init_array->d_un.d_ptr);
|
||||
for (j = 0; j < jm; ++j)
|
||||
((dl_init_t) addrs[j]) (argc, argv, env);
|
||||
}
|
||||
@@ -88,16 +89,16 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
|
||||
/* Don't do anything if there is no preinit array. */
|
||||
if (__builtin_expect (preinit_array != NULL, 0)
|
||||
&& preinit_array_size != NULL
|
||||
&& (i = preinit_array_size->d_un.d_val / sizeof (ElfW(Addr))) > 0)
|
||||
&& (i = preinit_array_size->d_un.d_val / sizeof (elfptr_t)) > 0)
|
||||
{
|
||||
ElfW(Addr) *addrs;
|
||||
elfptr_t *addrs;
|
||||
unsigned int cnt;
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
|
||||
_dl_debug_printf ("\ncalling preinit: %s\n\n",
|
||||
DSO_FILENAME (main_map->l_name));
|
||||
|
||||
addrs = (ElfW(Addr) *) (preinit_array->d_un.d_ptr + main_map->l_addr);
|
||||
addrs = (elfptr_t *) dl_rx_ptr (main_map, preinit_array->d_un.d_ptr);
|
||||
for (cnt = 0; cnt < i; ++cnt)
|
||||
((dl_init_t) addrs[cnt]) (argc, argv, env);
|
||||
}
|
||||
|
||||
@@ -61,9 +61,20 @@ __dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
|
||||
|
||||
for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
|
||||
{
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
info.dlpi_addr = l->l_real->l_addr == l->l_real->l_map_start
|
||||
? l->l_real->l_map_start
|
||||
: l->l_real->l_addr;
|
||||
#else
|
||||
info.dlpi_addr = l->l_real->l_addr;
|
||||
#endif
|
||||
info.dlpi_name = l->l_real->l_name;
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
ElfW(Addr) phdr = (ElfW(Addr)) l->l_real->l_phdr - l->l_real->l_addr;
|
||||
info.dlpi_phdr = (const void *) dl_rx_ptr (l->l_real, phdr);
|
||||
#else
|
||||
info.dlpi_phdr = l->l_real->l_phdr;
|
||||
#endif
|
||||
info.dlpi_phnum = l->l_real->l_phnum;
|
||||
info.dlpi_adds = GL(dl_load_adds);
|
||||
info.dlpi_subs = GL(dl_load_adds) - nloaded;
|
||||
|
||||
+8
-5
@@ -866,7 +866,7 @@ _dl_init_paths (const char *llp, const char *source,
|
||||
void
|
||||
_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(Nhdr) *note = (const void *) dl_rx_ptr (l, ph->p_vaddr);
|
||||
const ElfW(Addr) size = ph->p_memsz;
|
||||
const ElfW(Addr) align = ph->p_align;
|
||||
|
||||
@@ -1276,7 +1276,9 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
}
|
||||
|
||||
if (l->l_ld != 0)
|
||||
l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
|
||||
l->l_ld = (ElfW(Dyn) *) (l->l_ld_readonly
|
||||
? dl_rx_ptr (l, (elfptr_t) l->l_ld)
|
||||
: dl_rw_ptr (l, (elfptr_t) l->l_ld));
|
||||
|
||||
elf_get_dynamic_info (l, false, false);
|
||||
|
||||
@@ -1314,7 +1316,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
}
|
||||
else
|
||||
/* Adjust the PT_PHDR value by the runtime load address. */
|
||||
l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
|
||||
l->l_phdr = (ElfW(Phdr) *) dl_rx_ptr (l, (ElfW(Addr)) l->l_phdr);
|
||||
|
||||
if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
|
||||
{
|
||||
@@ -1369,7 +1371,8 @@ cannot enable executable stack as shared object requires");
|
||||
|
||||
/* Adjust the address of the TLS initialization image. */
|
||||
if (l->l_tls_initimage != NULL)
|
||||
l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
|
||||
l->l_tls_initimage
|
||||
= (void *) dl_rw_ptr (l, (ElfW(Addr)) l->l_tls_initimage);
|
||||
|
||||
/* Process program headers again after load segments are mapped in
|
||||
case processing requires accessing those segments. Scan program
|
||||
@@ -1402,7 +1405,7 @@ cannot enable executable stack as shared object requires");
|
||||
/* If this is ET_EXEC, we should have loaded it as lt_executable. */
|
||||
assert (type != ET_EXEC || l->l_type == lt_executable);
|
||||
|
||||
l->l_entry += l->l_addr;
|
||||
l->l_entry = dl_rx_ptr (l, l->l_entry);
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
|
||||
_dl_debug_printf ("\
|
||||
|
||||
@@ -854,6 +854,23 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
|
||||
if (__glibc_unlikely (current_value.m->l_used == 0))
|
||||
current_value.m->l_used = 1;
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS))
|
||||
{
|
||||
const char *reference_name = undef_map->l_name;
|
||||
|
||||
_dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
|
||||
DSO_FILENAME (reference_name),
|
||||
undef_map->l_ns,
|
||||
DSO_FILENAME (current_value.m->l_name),
|
||||
current_value.m->l_ns,
|
||||
protected ? "protected" : "normal", undef_name);
|
||||
if (version)
|
||||
_dl_debug_printf_c (" [%s]\n", version->name);
|
||||
else
|
||||
_dl_debug_printf_c ("\n");
|
||||
}
|
||||
|
||||
|
||||
*ref = current_value.s;
|
||||
return LOOKUP_VALUE (current_value.m);
|
||||
}
|
||||
|
||||
+71
-14
@@ -18,15 +18,26 @@
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <dl-load.h>
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
# include <cheri_perms.h>
|
||||
#endif
|
||||
|
||||
/* Allow RWX mprotect later, on CHERI this means RWX capability permission. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RWX PROT_MAX (PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
#else
|
||||
# define PROT_MAX_RWX 0
|
||||
#endif
|
||||
|
||||
/* Map a segment and align it properly. */
|
||||
|
||||
static __always_inline ElfW(Addr)
|
||||
static __always_inline elfptr_t
|
||||
_dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
|
||||
const size_t maplength, int fd)
|
||||
{
|
||||
if (__glibc_likely (c->mapalign <= GLRO(dl_pagesize)))
|
||||
return (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot,
|
||||
return (elfptr_t) __mmap ((void *) mappref, maplength,
|
||||
c->prot|PROT_MAX_RWX,
|
||||
MAP_COPY|MAP_FILE, fd, c->mapoff);
|
||||
|
||||
/* If the segment alignment > the page size, allocate enough space to
|
||||
@@ -34,16 +45,16 @@ _dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
|
||||
ElfW(Addr) maplen = (maplength >= c->mapalign
|
||||
? (maplength + c->mapalign)
|
||||
: (2 * c->mapalign));
|
||||
ElfW(Addr) map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplen,
|
||||
PROT_NONE,
|
||||
elfptr_t map_start = (elfptr_t) __mmap ((void *) mappref, maplen,
|
||||
PROT_NONE|PROT_MAX_RWX,
|
||||
MAP_ANONYMOUS|MAP_PRIVATE,
|
||||
-1, 0);
|
||||
if (__glibc_unlikely ((void *) map_start == MAP_FAILED))
|
||||
return map_start;
|
||||
|
||||
ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, c->mapalign);
|
||||
map_start_aligned = (ElfW(Addr)) __mmap ((void *) map_start_aligned,
|
||||
maplength, c->prot,
|
||||
elfptr_t map_start_aligned = ALIGN_UP (map_start, c->mapalign);
|
||||
map_start_aligned = (elfptr_t) __mmap ((void *) map_start_aligned,
|
||||
maplength, c->prot|PROT_MAX_RWX,
|
||||
MAP_COPY|MAP_FILE|MAP_FIXED,
|
||||
fd, c->mapoff);
|
||||
if (__glibc_unlikely ((void *) map_start_aligned == MAP_FAILED))
|
||||
@@ -54,7 +65,7 @@ _dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
|
||||
ElfW(Addr) delta = map_start_aligned - map_start;
|
||||
if (delta)
|
||||
__munmap ((void *) map_start, delta);
|
||||
ElfW(Addr) map_end = map_start_aligned + maplength;
|
||||
elfptr_t map_end = map_start + (map_start_aligned - map_start) + maplength;
|
||||
map_end = ALIGN_UP (map_end, GLRO(dl_pagesize));
|
||||
delta = map_start + maplen - map_end;
|
||||
if (delta)
|
||||
@@ -79,6 +90,10 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
struct link_map *loader)
|
||||
{
|
||||
const struct loadcmd *c = loadcmds;
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
ElfW(Addr) rw_start = -1;
|
||||
ElfW(Addr) rw_end = 0;
|
||||
#endif
|
||||
|
||||
if (__glibc_likely (type == ET_DYN))
|
||||
{
|
||||
@@ -116,7 +131,7 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
c->mapend))
|
||||
return N_("ELF load command address/offset not page-aligned");
|
||||
if (__glibc_unlikely
|
||||
(__mprotect ((caddr_t) (l->l_addr + c->mapend),
|
||||
(__mprotect ((caddr_t) dl_rx_ptr (l, c->mapend),
|
||||
loadcmds[nloadcmds - 1].mapstart - c->mapend,
|
||||
PROT_NONE) < 0))
|
||||
return DL_MAP_SEGMENTS_ERROR_MPROTECT;
|
||||
@@ -126,6 +141,23 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
|
||||
goto postmap;
|
||||
}
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
else
|
||||
{
|
||||
/* Need a single capability to cover all load segments. */
|
||||
void *p = __mmap ((void *) c->mapstart, maplength,
|
||||
c->prot|PROT_MAX_RWX,
|
||||
MAP_FIXED|MAP_COPY|MAP_FILE,
|
||||
fd, c->mapoff);
|
||||
if (p == MAP_FAILED)
|
||||
return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
|
||||
l->l_map_start = (elfptr_t) p;
|
||||
l->l_map_end = l->l_map_start + maplength;
|
||||
l->l_contiguous = !has_holes;
|
||||
|
||||
goto postmap;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remember which part of the address space this object uses. */
|
||||
l->l_map_start = c->mapstart + l->l_addr;
|
||||
@@ -134,10 +166,10 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
|
||||
while (c < &loadcmds[nloadcmds])
|
||||
{
|
||||
if (c->mapend > c->mapstart
|
||||
if (c->dataend > c->mapstart
|
||||
/* Map the segment contents from the file. */
|
||||
&& (__mmap ((void *) (l->l_addr + c->mapstart),
|
||||
c->mapend - c->mapstart, c->prot,
|
||||
&& (__mmap ((void *) dl_rx_ptr (l, c->mapstart),
|
||||
c->dataend - c->mapstart, c->prot,
|
||||
MAP_FIXED|MAP_COPY|MAP_FILE,
|
||||
fd, c->mapoff)
|
||||
== MAP_FAILED))
|
||||
@@ -146,13 +178,28 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
postmap:
|
||||
_dl_postprocess_loadcmd (l, header, c);
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (c->prot & PROT_WRITE)
|
||||
{
|
||||
if (l->l_rw_count >= DL_MAX_RW_COUNT)
|
||||
return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; // TODO: right error code
|
||||
if (c->mapstart < rw_start)
|
||||
rw_start = c->mapstart;
|
||||
if (c->allocend > rw_end)
|
||||
rw_end = c->allocend;
|
||||
l->l_rw_range[l->l_rw_count].start = l->l_addr + c->mapstart;
|
||||
l->l_rw_range[l->l_rw_count].end = l->l_addr + c->allocend;
|
||||
l->l_rw_count++;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (c->allocend > c->dataend)
|
||||
{
|
||||
/* Extra zero pages should appear at the end of this segment,
|
||||
after the data mapped from the file. */
|
||||
ElfW(Addr) zero, zeroend, zeropage;
|
||||
elfptr_t zero, zeroend, zeropage;
|
||||
|
||||
zero = l->l_addr + c->dataend;
|
||||
zero = dl_rx_ptr (l, c->dataend);
|
||||
zeroend = l->l_addr + c->allocend;
|
||||
zeropage = ((zero + GLRO(dl_pagesize) - 1)
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
@@ -194,6 +241,16 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
++c;
|
||||
}
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (l->l_rw_count > 0)
|
||||
{
|
||||
l->l_rw_start = __builtin_cheri_address_set (l->l_map_start, l->l_addr + rw_start);
|
||||
l->l_rw_start = __builtin_cheri_bounds_set (l->l_rw_start, rw_end - rw_start);
|
||||
l->l_rw_start = __builtin_cheri_perms_and (l->l_rw_start, CAP_PERM_MASK_RW);
|
||||
}
|
||||
l->l_map_start = __builtin_cheri_perms_and (l->l_map_start, CAP_PERM_MASK_RX);
|
||||
#endif
|
||||
|
||||
/* Notify ELF_PREFERRED_ADDRESS that we have to load this one
|
||||
fixed. */
|
||||
ELF_FIXED_ADDRESS (loader, c->mapstart);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
# pragma GCC visibility push(hidden)
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <malloc/malloc-internal.h>
|
||||
@@ -33,6 +34,7 @@ static void *alloc_ptr, *alloc_end, *alloc_last_block;
|
||||
void *
|
||||
__minimal_malloc (size_t n)
|
||||
{
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
if (alloc_end == 0)
|
||||
{
|
||||
/* Consume any unused space in the last page of our data segment. */
|
||||
@@ -42,9 +44,10 @@ __minimal_malloc (size_t n)
|
||||
+ GLRO(dl_pagesize) - 1)
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure the allocation pointer is ideally aligned. */
|
||||
alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + MALLOC_ALIGNMENT - 1)
|
||||
alloc_ptr = (void *)(((uintptr_t)alloc_ptr + (MALLOC_ALIGNMENT - 1))
|
||||
& ~(MALLOC_ALIGNMENT - 1));
|
||||
|
||||
if (alloc_ptr + n >= alloc_end || n >= -(uintptr_t) alloc_ptr)
|
||||
|
||||
@@ -850,6 +850,7 @@ no more namespaces available for dlmopen()"));
|
||||
++GL(dl_nns);
|
||||
}
|
||||
|
||||
GL(dl_ns)[nsid].libc_map = NULL;
|
||||
_dl_debug_update (nsid)->r_state = RT_CONSISTENT;
|
||||
}
|
||||
/* Never allow loading a DSO in a namespace which is empty. Such
|
||||
|
||||
+5
-2
@@ -163,8 +163,11 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
|
||||
/* We use alloca() to allocate the buffer with the most
|
||||
pessimistic guess for the size. Using alloca() allows
|
||||
having more than one integer formatting in a call. */
|
||||
char *buf = (char *) alloca (1 + 3 * sizeof (unsigned long int));
|
||||
char *endp = &buf[1 + 3 * sizeof (unsigned long int)];
|
||||
int size = 1 + 3 * sizeof (unsigned long int);
|
||||
if (width + 1 > size)
|
||||
size = width + 1;
|
||||
char *buf = (char *) alloca (size);
|
||||
char *endp = &buf[size];
|
||||
char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
|
||||
|
||||
/* Pad to the width the user specified. */
|
||||
|
||||
@@ -182,6 +182,9 @@ static unsigned int log_hashfraction;
|
||||
void
|
||||
_dl_start_profile (void)
|
||||
{
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
__libc_fatal ("Profiling is not supported on capability architectures.");
|
||||
#else
|
||||
char *filename;
|
||||
int fd;
|
||||
struct __stat64_t64 st;
|
||||
@@ -482,6 +485,7 @@ _dl_start_profile (void)
|
||||
|
||||
/* Turn on profiling. */
|
||||
running = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-2
@@ -353,8 +353,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
void
|
||||
_dl_protect_relro (struct link_map *l)
|
||||
{
|
||||
ElfW(Addr) start = ALIGN_DOWN((l->l_addr
|
||||
+ l->l_relro_addr),
|
||||
elfptr_t start = ALIGN_DOWN(dl_rx_ptr (l, l->l_relro_addr),
|
||||
GLRO(dl_pagesize));
|
||||
ElfW(Addr) end = ALIGN_DOWN((l->l_addr
|
||||
+ l->l_relro_addr
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ _dl_fixup (
|
||||
+ reloc_offset (pltgot, reloc_arg));
|
||||
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
|
||||
const ElfW(Sym) *refsym = sym;
|
||||
void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
|
||||
void *const rel_addr = (void *) dl_rw_ptr (l, reloc->r_offset);
|
||||
lookup_t result;
|
||||
DL_FIXUP_VALUE_TYPE value;
|
||||
|
||||
|
||||
+29
-15
@@ -27,12 +27,12 @@
|
||||
If FOR_FINI is true, this is called for finishing an object. */
|
||||
static void
|
||||
_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
|
||||
unsigned int skip, bool for_fini)
|
||||
bool force_first, bool for_fini)
|
||||
{
|
||||
/* Allows caller to do the common optimization of skipping the first map,
|
||||
usually the main binary. */
|
||||
maps += skip;
|
||||
nmaps -= skip;
|
||||
maps += force_first;
|
||||
nmaps -= force_first;
|
||||
|
||||
/* A list of one element need not be sorted. */
|
||||
if (nmaps <= 1)
|
||||
@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
|
||||
|
||||
static void
|
||||
_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
unsigned int skip __attribute__ ((unused)), bool for_fini)
|
||||
bool force_first, bool for_fini)
|
||||
{
|
||||
struct link_map *first_map = maps[0];
|
||||
for (int i = nmaps - 1; i >= 0; i--)
|
||||
maps[i]->l_visited = 0;
|
||||
|
||||
@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
Adjusting the order so that maps[0] is last traversed naturally avoids
|
||||
this problem.
|
||||
|
||||
Further, the old "optimization" of skipping the main object at maps[0]
|
||||
from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
|
||||
no longer valid, since traversing along object dependency-links
|
||||
may "find" the main object even when it is not included in the initial
|
||||
order (e.g. a dlopen()'ed shared object can have circular dependencies
|
||||
linked back to itself). In such a case, traversing N-1 objects will
|
||||
create a N-object result, and raise problems.
|
||||
|
||||
To summarize, just passing in the full list, and iterating from back
|
||||
to front makes things much more straightforward. */
|
||||
|
||||
@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
|
||||
}
|
||||
|
||||
memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
|
||||
|
||||
/* Skipping the first object at maps[0] is not valid in general,
|
||||
since traversing along object dependency-links may "find" that
|
||||
first object even when it is not included in the initial order
|
||||
(e.g., a dlopen'ed shared object can have circular dependencies
|
||||
linked back to itself). In such a case, traversing N-1 objects
|
||||
will create a N-object result, and raise problems. Instead,
|
||||
force the object back into first place after sorting. This naive
|
||||
approach may introduce further dependency ordering violations
|
||||
compared to rotating the cycle until the first map is again in
|
||||
the first position, but as there is a cycle, at least one
|
||||
violation is already present. */
|
||||
if (force_first && maps[0] != first_map)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; maps[i] != first_map; ++i)
|
||||
;
|
||||
assert (i < nmaps);
|
||||
memmove (&maps[1], maps, i * sizeof (maps[0]));
|
||||
maps[0] = first_map;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -286,7 +300,7 @@ _dl_sort_maps_init (void)
|
||||
|
||||
void
|
||||
_dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
unsigned int skip, bool for_fini)
|
||||
bool force_first, bool for_fini)
|
||||
{
|
||||
/* It can be tempting to use a static function pointer to store and call
|
||||
the current selected sorting algorithm routine, but experimentation
|
||||
@@ -296,9 +310,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
input cases. A simple if-case with direct function calls appears to
|
||||
be the fastest. */
|
||||
if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
|
||||
_dl_sort_maps_original (maps, nmaps, skip, for_fini);
|
||||
_dl_sort_maps_original (maps, nmaps, force_first, for_fini);
|
||||
else
|
||||
_dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
|
||||
_dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
|
||||
}
|
||||
|
||||
#endif /* HAVE_TUNABLES. */
|
||||
|
||||
@@ -255,6 +255,13 @@ _dl_aux_init (ElfW(auxv_t) *av)
|
||||
for (int i = 0; i < array_length (auxv_values); ++i)
|
||||
auxv_values[i] = 0;
|
||||
_dl_parse_auxv (av, auxv_values);
|
||||
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
_dl_main_map.l_map_start = auxv_values[AT_CHERI_EXEC_RX_CAP];
|
||||
_dl_main_map.l_map_start = __builtin_cheri_perms_and (_dl_main_map.l_map_start, CAP_PERM_MASK_RX);
|
||||
_dl_main_map.l_rw_start = auxv_values[AT_CHERI_EXEC_RW_CAP];
|
||||
_dl_main_map.l_rw_start = __builtin_cheri_perms_and (_dl_main_map.l_rw_start, CAP_PERM_MASK_RW);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ _dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value,
|
||||
if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
|
||||
{
|
||||
DL_FIXUP_VALUE_TYPE fixup
|
||||
= DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
|
||||
= DL_FIXUP_MAKE_VALUE (result, (elfptr_t) value);
|
||||
fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
|
||||
value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
|
||||
{
|
||||
.ti_module = map->l_tls_modid,
|
||||
.ti_offset = ref->st_value
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
,
|
||||
.ti_size = ref->st_size
|
||||
# endif
|
||||
};
|
||||
|
||||
return __TLS_GET_ADDR (&tmp);
|
||||
|
||||
@@ -62,7 +62,11 @@
|
||||
observed PT_GNU_TLS sizes across all architectures. Some
|
||||
architectures have lower values due to differences in type sizes
|
||||
and link editor capabilities. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
#define LIBC_IE_TLS 256
|
||||
#else
|
||||
#define LIBC_IE_TLS 144
|
||||
#endif
|
||||
|
||||
/* Size of initial-exec TLS in libraries other than libc.so.
|
||||
This should be large enough to cover runtime libraries of the
|
||||
@@ -87,7 +91,11 @@ tls_static_surplus (int nns, int opt_tls)
|
||||
the computation of dl_tls_static_surplus in
|
||||
_dl_tls_static_surplus_init yields the historic value 1664, for
|
||||
backwards compatibility. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
#define LEGACY_TLS 0
|
||||
#else
|
||||
#define LEGACY_TLS (1664 - tls_static_surplus (DEFAULT_NNS, OPTIONAL_TLS))
|
||||
#endif
|
||||
|
||||
/* Calculate the size of the static TLS surplus, when the given
|
||||
number of audit modules are loaded. Must be called after the
|
||||
|
||||
@@ -159,6 +159,13 @@ glibc {
|
||||
maxval: 255
|
||||
security_level: SXID_IGNORE
|
||||
}
|
||||
cap_narrowing {
|
||||
type: INT_32
|
||||
minval: 0
|
||||
maxval: 1
|
||||
default: 1
|
||||
security_level: SXID_IGNORE
|
||||
}
|
||||
}
|
||||
|
||||
rtld {
|
||||
|
||||
+5
-5
@@ -86,7 +86,7 @@ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
|
||||
def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
|
||||
assert (def_offset != 0);
|
||||
|
||||
def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
|
||||
def = (ElfW(Verdef) *) dl_rx_ptr (map, def_offset);
|
||||
while (1)
|
||||
{
|
||||
/* Currently the version number of the definition entry is 1.
|
||||
@@ -177,7 +177,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
if (dyn != NULL)
|
||||
{
|
||||
/* This file requires special versions from its dependencies. */
|
||||
ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
|
||||
ElfW(Verneed) *ent = (ElfW(Verneed) *) dl_rx_ptr (map, dyn->d_un.d_ptr);
|
||||
|
||||
/* Currently the version number of the needed entry is 1.
|
||||
Make sure all we see is this version. */
|
||||
@@ -257,7 +257,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
if (def != NULL)
|
||||
{
|
||||
ElfW(Verdef) *ent;
|
||||
ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
|
||||
ent = (ElfW(Verdef) *) dl_rx_ptr (map, def->d_un.d_ptr);
|
||||
while (1)
|
||||
{
|
||||
if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
|
||||
@@ -296,7 +296,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
if (dyn != NULL)
|
||||
{
|
||||
ElfW(Verneed) *ent;
|
||||
ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
|
||||
ent = (ElfW(Verneed) *) dl_rx_ptr (map, dyn->d_un.d_ptr);
|
||||
while (1)
|
||||
{
|
||||
ElfW(Vernaux) *aux;
|
||||
@@ -334,7 +334,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
if (def != NULL)
|
||||
{
|
||||
ElfW(Verdef) *ent;
|
||||
ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
|
||||
ent = (ElfW(Verdef) *) dl_rx_ptr (map, def->d_un.d_ptr);
|
||||
while (1)
|
||||
{
|
||||
ElfW(Verdaux) *aux;
|
||||
|
||||
+6
-6
@@ -41,7 +41,7 @@
|
||||
|
||||
static inline void __attribute__ ((always_inline))
|
||||
elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
ElfW(Addr) reladdr, ElfW(Addr) relsize,
|
||||
elfptr_t reladdr, ElfW(Addr) relsize,
|
||||
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
|
||||
int lazy, int skip_ifunc)
|
||||
{
|
||||
@@ -62,7 +62,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
{
|
||||
ElfW (Half) ndx = version[ELFW (R_SYM) (r->r_info)] & 0x7fff;
|
||||
const ElfW (Sym) *sym = &symtab[ELFW (R_SYM) (r->r_info)];
|
||||
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
|
||||
void *const r_addr_arg = (void *) dl_rw_ptr (map, r->r_offset);
|
||||
const struct r_found_version *rversion = &map->l_versions[ndx];
|
||||
|
||||
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, skip_ifunc);
|
||||
@@ -132,7 +132,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
{
|
||||
ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
|
||||
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
|
||||
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
|
||||
void *const r_addr_arg = (void *) dl_rw_ptr (map, r->r_offset);
|
||||
const struct r_found_version *rversion = &map->l_versions[ndx];
|
||||
#if defined ELF_MACHINE_IRELATIVE
|
||||
if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
|
||||
@@ -169,7 +169,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
elf_machine_rel (map, scope, r2,
|
||||
&symtab[ELFW(R_SYM) (r2->r_info)],
|
||||
&map->l_versions[ndx],
|
||||
(void *) (l_addr + r2->r_offset),
|
||||
(void *) dl_rw_ptr (map, r2->r_offset),
|
||||
skip_ifunc);
|
||||
}
|
||||
#endif
|
||||
@@ -179,7 +179,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
for (; r < end; ++r)
|
||||
{
|
||||
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
|
||||
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
|
||||
void *const r_addr_arg = (void *) dl_rw_ptr (map, r->r_offset);
|
||||
# ifdef ELF_MACHINE_IRELATIVE
|
||||
if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
|
||||
{
|
||||
@@ -210,7 +210,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
for (; r2 <= end2; ++r2)
|
||||
if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
|
||||
elf_machine_rel (map, scope, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
|
||||
NULL, (void *) (l_addr + r2->r_offset),
|
||||
NULL, (void *) dl_rw_ptr (map, r2->r_offset),
|
||||
skip_ifunc);
|
||||
# endif
|
||||
}
|
||||
|
||||
@@ -64,3 +64,10 @@ output: b>a>{}<a<b
|
||||
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
|
||||
output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
|
||||
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
|
||||
|
||||
# Test that even in the presence of dependency loops involving dlopen'ed
|
||||
# object, that object is initialized last (and not unloaded prematurely).
|
||||
# Final destructor order is indeterminate due to the cycle.
|
||||
tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
|
||||
output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
|
||||
output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1
|
||||
|
||||
+7
-2
@@ -46,9 +46,14 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
|
||||
const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
|
||||
const struct r_found_version *version, void *const reloc_addr,
|
||||
int skip_ifunc);
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
static inline void __attribute__((always_inline))
|
||||
elf_machine_rela_relative (struct link_map *map, const ElfW(Rela) *reloc);
|
||||
# else
|
||||
static inline void __attribute__((always_inline))
|
||||
elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
|
||||
void *const reloc_addr);
|
||||
# endif
|
||||
# endif
|
||||
# if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
|
||||
static inline void __attribute__((always_inline))
|
||||
@@ -80,7 +85,7 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
|
||||
# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, test_rel) \
|
||||
do { \
|
||||
struct { ElfW(Addr) start, size; \
|
||||
struct { elfptr_t start; ElfW(Addr) size; \
|
||||
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
|
||||
ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \
|
||||
\
|
||||
@@ -97,7 +102,7 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
if ((map)->l_info[DT_PLTREL] \
|
||||
&& (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
|
||||
{ \
|
||||
ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
|
||||
elfptr_t start = D_PTR ((map), l_info[DT_JMPREL]); \
|
||||
ElfW(Addr) size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
|
||||
\
|
||||
if (ranges[0].start == 0) \
|
||||
|
||||
@@ -1159,6 +1159,14 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#if defined __CHERI_PURE_CAPABILITY__
|
||||
uint64_t a_type;
|
||||
uint64_t __pad;
|
||||
union
|
||||
{
|
||||
__uintcap_t a_val;
|
||||
} a_un;
|
||||
#else
|
||||
uint64_t a_type; /* Entry type */
|
||||
union
|
||||
{
|
||||
@@ -1167,6 +1175,7 @@ typedef struct
|
||||
though, since it does not work when using 32-bit definitions
|
||||
on 64-bit platforms and vice versa. */
|
||||
} a_un;
|
||||
#endif
|
||||
} Elf64_auxv_t;
|
||||
|
||||
/* Legal values for a_type (entry type). */
|
||||
@@ -1243,6 +1252,18 @@ typedef struct
|
||||
|
||||
#define AT_MINSIGSTKSZ 51 /* Stack needed for signal delivery */
|
||||
|
||||
#define AT_CHERI_EXEC_RW_CAP 60
|
||||
#define AT_CHERI_EXEC_RX_CAP 61
|
||||
#define AT_CHERI_INTERP_RW_CAP 62
|
||||
#define AT_CHERI_INTERP_RX_CAP 63
|
||||
#define AT_CHERI_STACK_CAP 64
|
||||
#define AT_CHERI_SEAL_CAP 65
|
||||
#define AT_CHERI_CID_CAP 66
|
||||
#define AT_ARGC 80
|
||||
#define AT_ARGV 81
|
||||
#define AT_ENVC 82
|
||||
#define AT_ENVP 83
|
||||
|
||||
/* Note section contents. Each entry in the note section begins with
|
||||
a header of a fixed form. */
|
||||
|
||||
@@ -2906,6 +2927,9 @@ enum
|
||||
/* MTE memory tag segment type. */
|
||||
#define PT_AARCH64_MEMTAG_MTE (PT_LOPROC + 2)
|
||||
|
||||
/* Processor specific flags for the ELF header e_flags field. */
|
||||
#define EF_AARCH64_CHERI_PURECAP 0x00010000
|
||||
|
||||
/* AArch64 specific values for the Dyn d_tag field. */
|
||||
#define DT_AARCH64_BTI_PLT (DT_LOPROC + 1)
|
||||
#define DT_AARCH64_PAC_PLT (DT_LOPROC + 3)
|
||||
@@ -2915,6 +2939,27 @@ enum
|
||||
/* AArch64 specific values for the st_other field. */
|
||||
#define STO_AARCH64_VARIANT_PCS 0x80
|
||||
|
||||
/* Morello relocs. */
|
||||
#define R_MORELLO_TSTBR14 57344
|
||||
#define R_MORELLO_CONDBR19 57345
|
||||
#define R_MORELLO_JUMP26 57346
|
||||
#define R_MORELLO_CALL26 57347
|
||||
#define R_MORELLO_LD_PREL_LO17 57348
|
||||
#define R_MORELLO_ADR_PREL_PG_HI20 57349
|
||||
#define R_MORELLO_ADR_PREL_PG_HI20_NC 57350
|
||||
#define R_MORELLO_ADR_GOT_PAGE 57351
|
||||
#define R_MORELLO_LD128_GOT_LO12_NC 57352
|
||||
#define R_MORELLO_TLSDESC_ADR_PAGE20 57600
|
||||
#define R_MORELLO_TLSDESC_LD128_LO12 57601
|
||||
#define R_MORELLO_TLSDESC_CALL 57602
|
||||
#define R_MORELLO_CAPINIT 59392
|
||||
#define R_MORELLO_GLOB_DAT 59393
|
||||
#define R_MORELLO_JUMP_SLOT 59394
|
||||
#define R_MORELLO_RELATIVE 59395
|
||||
#define R_MORELLO_IRELATIVE 59396
|
||||
#define R_MORELLO_TLSDESC 59397
|
||||
#define R_MORELLO_TPREL128 59398
|
||||
|
||||
/* ARM relocs. */
|
||||
|
||||
#define R_ARM_NONE 0 /* No reloc */
|
||||
@@ -4085,8 +4130,11 @@ enum
|
||||
#define R_NDS32_TLS_DESC 119
|
||||
|
||||
/* LoongArch ELF Flags */
|
||||
#define EF_LARCH_ABI 0x07
|
||||
#define EF_LARCH_ABI_LP64D 0x03
|
||||
#define EF_LARCH_ABI_MODIFIER_MASK 0x07
|
||||
#define EF_LARCH_ABI_SOFT_FLOAT 0x01
|
||||
#define EF_LARCH_ABI_SINGLE_FLOAT 0x02
|
||||
#define EF_LARCH_ABI_DOUBLE_FLOAT 0x03
|
||||
#define EF_LARCH_OBJABI_V1 0x40
|
||||
|
||||
/* LoongArch specific dynamic relocations */
|
||||
#define R_LARCH_NONE 0
|
||||
|
||||
+7
-1
@@ -34,6 +34,12 @@
|
||||
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||
#include <bits/link.h>
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
typedef uintptr_t elfptr_t;
|
||||
#else
|
||||
typedef ElfW(Addr) elfptr_t;
|
||||
#endif
|
||||
|
||||
/* The legacy rendezvous structure used by the run-time dynamic linker to
|
||||
communicate details of shared object loading to the debugger. */
|
||||
|
||||
@@ -154,7 +160,7 @@ enum
|
||||
|
||||
struct dl_phdr_info
|
||||
{
|
||||
ElfW(Addr) dlpi_addr;
|
||||
elfptr_t dlpi_addr;
|
||||
const char *dlpi_name;
|
||||
const ElfW(Phdr) *dlpi_phdr;
|
||||
ElfW(Half) dlpi_phnum;
|
||||
|
||||
+43
-15
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <dl-r_debug.h>
|
||||
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
struct E(link_map)
|
||||
{
|
||||
EW(Addr) l_addr;
|
||||
@@ -35,6 +36,48 @@ struct E(link_map)
|
||||
Lmid_t l_ns;
|
||||
EW(Addr) l_libname;
|
||||
};
|
||||
|
||||
struct E(libname_list)
|
||||
{
|
||||
EW(Addr) name;
|
||||
EW(Addr) next;
|
||||
};
|
||||
|
||||
struct E(r_debug)
|
||||
{
|
||||
int r_version;
|
||||
# if CLASS == 64
|
||||
int pad;
|
||||
# endif
|
||||
EW(Addr) r_map;
|
||||
};
|
||||
#else
|
||||
struct E(link_map)
|
||||
{
|
||||
uintptr_t l_addr;
|
||||
uintptr_t l_name;
|
||||
uintptr_t l_ld;
|
||||
uintptr_t l_next;
|
||||
uintptr_t l_prev;
|
||||
uintptr_t l_real;
|
||||
Lmid_t l_ns;
|
||||
uintptr_t l_libname;
|
||||
};
|
||||
|
||||
struct E(libname_list)
|
||||
{
|
||||
uintptr_t name;
|
||||
uintptr_t next;
|
||||
};
|
||||
|
||||
struct E(r_debug)
|
||||
{
|
||||
int r_version;
|
||||
int pad;
|
||||
uintptr_t r_map;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
_Static_assert (offsetof (struct link_map, l_addr)
|
||||
== offsetof (struct E(link_map), l_addr), "l_addr");
|
||||
@@ -44,27 +87,12 @@ _Static_assert (offsetof (struct link_map, l_next)
|
||||
== offsetof (struct E(link_map), l_next), "l_next");
|
||||
#endif
|
||||
|
||||
|
||||
struct E(libname_list)
|
||||
{
|
||||
EW(Addr) name;
|
||||
EW(Addr) next;
|
||||
};
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
_Static_assert (offsetof (struct libname_list, name)
|
||||
== offsetof (struct E(libname_list), name), "name");
|
||||
_Static_assert (offsetof (struct libname_list, next)
|
||||
== offsetof (struct E(libname_list), next), "next");
|
||||
#endif
|
||||
|
||||
struct E(r_debug)
|
||||
{
|
||||
int r_version;
|
||||
#if CLASS == 64
|
||||
int pad;
|
||||
#endif
|
||||
EW(Addr) r_map;
|
||||
};
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
_Static_assert (offsetof (struct r_debug, r_version)
|
||||
== offsetof (struct E(r_debug), r_version), "r_version");
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ $(objpfx)rtld-libc.a: $(foreach dir,$(rtld-subdirs),\
|
||||
mv -f $@T $@
|
||||
|
||||
# Use the verbose option of ar and tar when not running silently.
|
||||
ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s
|
||||
ifeq ($(silent-make),no) # if not -s
|
||||
verbose := v
|
||||
else # -s
|
||||
verbose :=
|
||||
|
||||
+76
-16
@@ -384,7 +384,7 @@ extern struct rtld_global_ro _rtld_local_ro
|
||||
|
||||
|
||||
static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
|
||||
ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv);
|
||||
elfptr_t *user_entry, ElfW(auxv_t) *auxv);
|
||||
|
||||
/* These two variables cannot be moved into .data.rel.ro. */
|
||||
static struct libname_list _dl_rtld_libname;
|
||||
@@ -416,15 +416,15 @@ DL_SYSINFO_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
static ElfW(Addr) _dl_start_final (void *arg);
|
||||
static elfptr_t _dl_start_final (void *arg);
|
||||
#else
|
||||
struct dl_start_final_info
|
||||
{
|
||||
struct link_map l;
|
||||
RTLD_TIMING_VAR (start_time);
|
||||
};
|
||||
static ElfW(Addr) _dl_start_final (void *arg,
|
||||
struct dl_start_final_info *info);
|
||||
static elfptr_t _dl_start_final (void *arg,
|
||||
struct dl_start_final_info *info);
|
||||
#endif
|
||||
|
||||
/* These are defined magically by the linker. */
|
||||
@@ -446,14 +446,14 @@ RTLD_START
|
||||
this function is not inlined (see below). */
|
||||
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
static inline ElfW(Addr) __attribute__ ((always_inline))
|
||||
static inline elfptr_t __attribute__ ((always_inline))
|
||||
_dl_start_final (void *arg)
|
||||
#else
|
||||
static ElfW(Addr) __attribute__ ((noinline))
|
||||
static elfptr_t __attribute__ ((noinline))
|
||||
_dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
#endif
|
||||
{
|
||||
ElfW(Addr) start_addr;
|
||||
elfptr_t start_addr;
|
||||
|
||||
/* Do not use an initializer for these members because it would
|
||||
intefere with __rtld_static_init. */
|
||||
@@ -474,10 +474,19 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
sizeof GL(dl_rtld_map).l_info);
|
||||
GL(dl_rtld_map).l_mach = info->l.l_mach;
|
||||
GL(dl_rtld_map).l_relocated = 1;
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
GL(dl_rtld_map).l_map_start = info->l.l_map_start;
|
||||
GL(dl_rtld_map).l_rw_start = info->l.l_rw_start;
|
||||
GL(dl_rtld_map).l_rw_count = info->l.l_rw_count;
|
||||
for (int i = 0; i < info->l.l_rw_count; i++)
|
||||
GL(dl_rtld_map).l_rw_range[i] = info->l.l_rw_range[i];
|
||||
# endif
|
||||
#endif
|
||||
_dl_setup_hash (&GL(dl_rtld_map));
|
||||
GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start;
|
||||
#endif
|
||||
GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
|
||||
GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext;
|
||||
/* Copy the TLS related data if necessary. */
|
||||
@@ -515,7 +524,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
# define bootstrap_map info.l
|
||||
#endif
|
||||
|
||||
static ElfW(Addr) __attribute_used__
|
||||
static elfptr_t __attribute_used__
|
||||
_dl_start (void *arg)
|
||||
{
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
@@ -542,11 +551,16 @@ _dl_start (void *arg)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
elf_machine_rtld_base_setup (&bootstrap_map, arg);
|
||||
bootstrap_map.l_ld = elf_machine_runtime_dynamic ();
|
||||
#else
|
||||
/* Figure out the run-time load address of the dynamic linker itself. */
|
||||
bootstrap_map.l_addr = elf_machine_load_address ();
|
||||
|
||||
/* Read our own dynamic section and fill in the info array. */
|
||||
bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
|
||||
#endif
|
||||
bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION;
|
||||
elf_get_dynamic_info (&bootstrap_map, true, false);
|
||||
|
||||
@@ -708,8 +722,7 @@ match_version (const char *string, struct link_map *map)
|
||||
/* The file has no symbol versioning. */
|
||||
return 0;
|
||||
|
||||
def = (ElfW(Verdef) *) ((char *) map->l_addr
|
||||
+ map->l_info[VERDEFTAG]->d_un.d_ptr);
|
||||
def = (ElfW(Verdef) *) dl_rx_ptr (map, map->l_info[VERDEFTAG]->d_un.d_ptr);
|
||||
while (1)
|
||||
{
|
||||
ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
|
||||
@@ -1125,8 +1138,13 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
|
||||
main_map->l_map_end = 0;
|
||||
main_map->l_text_end = 0;
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
/* Perhaps the executable has no PT_LOAD header entries at all. */
|
||||
main_map->l_map_start = ~0;
|
||||
#else
|
||||
/* May be computed already when exe is loaded by ld.so. */
|
||||
main_map->l_rw_count = 0;
|
||||
#endif
|
||||
/* And it was opened directly. */
|
||||
++main_map->l_direct_opencount;
|
||||
main_map->l_contiguous = 1;
|
||||
@@ -1157,8 +1175,10 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
case PT_DYNAMIC:
|
||||
/* This tells us where to find the dynamic section,
|
||||
which tells us everything we need to do. */
|
||||
main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
|
||||
main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
|
||||
main_map->l_ld = (void *) (main_map->l_ld_readonly
|
||||
? dl_rx_ptr (main_map, ph->p_vaddr)
|
||||
: dl_rw_ptr (main_map, ph->p_vaddr));
|
||||
break;
|
||||
case PT_INTERP:
|
||||
/* This "interpreter segment" was used by the program loader to
|
||||
@@ -1167,8 +1187,8 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
dlopen call or DT_NEEDED entry, for something that wants to link
|
||||
against the dynamic linker as a shared library, will know that
|
||||
the shared object is already loaded. */
|
||||
_dl_rtld_libname.name = ((const char *) main_map->l_addr
|
||||
+ ph->p_vaddr);
|
||||
_dl_rtld_libname.name = (const char *) dl_rx_ptr (main_map,
|
||||
ph->p_vaddr);
|
||||
/* _dl_rtld_libname.next = NULL; Already zero. */
|
||||
GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
|
||||
|
||||
@@ -1205,8 +1225,10 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
/* Remember where the main program starts in memory. */
|
||||
mapstart = (main_map->l_addr
|
||||
+ (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
if (main_map->l_map_start > mapstart)
|
||||
main_map->l_map_start = mapstart;
|
||||
#endif
|
||||
|
||||
if (main_map->l_contiguous && expected_load_address != 0
|
||||
&& expected_load_address != mapstart)
|
||||
@@ -1223,6 +1245,15 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
segment. */
|
||||
expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (ph->p_flags & PF_W)
|
||||
{
|
||||
assert (main_map->l_rw_count < DL_MAX_RW_COUNT);
|
||||
main_map->l_rw_range[main_map->l_rw_count].start = mapstart;
|
||||
main_map->l_rw_range[main_map->l_rw_count].end = allocend;
|
||||
main_map->l_rw_count++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1274,7 +1305,7 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
the executable is actually an ET_DYN object. */
|
||||
if (main_map->l_tls_initimage != NULL)
|
||||
main_map->l_tls_initimage
|
||||
= (char *) main_map->l_tls_initimage + main_map->l_addr;
|
||||
= (void *) dl_rx_ptr (main_map, (ElfW(Addr)) main_map->l_tls_initimage);
|
||||
if (! main_map->l_map_end)
|
||||
main_map->l_map_end = ~0;
|
||||
if (! main_map->l_text_end)
|
||||
@@ -1352,7 +1383,7 @@ _dl_start_args_adjust (int skip_args)
|
||||
static void
|
||||
dl_main (const ElfW(Phdr) *phdr,
|
||||
ElfW(Word) phnum,
|
||||
ElfW(Addr) *user_entry,
|
||||
elfptr_t *user_entry,
|
||||
ElfW(auxv_t) *auxv)
|
||||
{
|
||||
struct link_map *main_map;
|
||||
@@ -1635,6 +1666,14 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
case AT_EXECFN:
|
||||
av->a_un.a_val = (uintptr_t) _dl_argv[0];
|
||||
break;
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
case AT_CHERI_EXEC_RX_CAP:
|
||||
av->a_un.a_val = main_map->l_map_start;
|
||||
break;
|
||||
case AT_CHERI_EXEC_RW_CAP:
|
||||
av->a_un.a_val = main_map->l_rw_start;
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1678,6 +1717,21 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
|
||||
/* We delay initializing the path structure until we got the dynamic
|
||||
information for the program. */
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
for (ElfW(auxv_t) *av = auxv; av->a_type != AT_NULL; av++)
|
||||
switch (av->a_type)
|
||||
{
|
||||
case AT_CHERI_EXEC_RX_CAP:
|
||||
main_map->l_map_start = av->a_un.a_val;
|
||||
main_map->l_map_start = __builtin_cheri_perms_and (main_map->l_map_start, CAP_PERM_MASK_RX);
|
||||
break;
|
||||
case AT_CHERI_EXEC_RW_CAP:
|
||||
main_map->l_rw_start = av->a_un.a_val;
|
||||
main_map->l_rw_start = __builtin_cheri_perms_and (main_map->l_rw_start, CAP_PERM_MASK_RW);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool has_interp = rtld_setup_main_map (main_map);
|
||||
@@ -2122,6 +2176,12 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
if (l->l_faked)
|
||||
/* The library was not found. */
|
||||
_dl_printf ("\t%s => not found\n", l->l_libname->name);
|
||||
else if (strcmp (l->l_libname->name, l->l_name) == 0)
|
||||
/* Print vDSO like libraries without duplicate name. Some
|
||||
consumers depend of this format. */
|
||||
_dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name,
|
||||
(int) sizeof l->l_map_start * 2,
|
||||
(size_t) l->l_map_start);
|
||||
else
|
||||
_dl_printf ("\t%s => %s (0x%0*Zx)\n",
|
||||
DSO_FILENAME (l->l_libname->name),
|
||||
@@ -2194,7 +2254,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
continue;
|
||||
|
||||
strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
|
||||
ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
|
||||
ent = (ElfW(Verneed) *) dl_rx_ptr (map, dyn->d_un.d_ptr);
|
||||
|
||||
if (first)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,11 @@ static int
|
||||
do_test (int argc, char *argv[])
|
||||
{
|
||||
errno = 0;
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
const char *execfn = (const char *) getauxval (AT_NULL);
|
||||
#else
|
||||
const char *execfn = (const char *) getauxptr (AT_NULL);
|
||||
#endif
|
||||
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
@@ -43,7 +47,11 @@ do_test (int argc, char *argv[])
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
execfn = (const char *) getauxval (AT_EXECFN);
|
||||
#else
|
||||
execfn = (const char *) getauxptr (AT_EXECFN);
|
||||
#endif
|
||||
|
||||
if (execfn == NULL)
|
||||
{
|
||||
|
||||
@@ -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,54 @@
|
||||
/* 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 <stdio.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xdlfcn.h>
|
||||
|
||||
/* Run the test multiple times, to check finding a new namespace while
|
||||
another namespace is already in use. This used to trigger bug 29600. */
|
||||
static void
|
||||
recurse (int depth)
|
||||
{
|
||||
if (depth == 0)
|
||||
return;
|
||||
|
||||
printf ("info: running at depth %d\n", depth);
|
||||
void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so",
|
||||
RTLD_NOW);
|
||||
xdlclose (handle);
|
||||
handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW);
|
||||
int (*run_check) (void) = xdlsym (handle, "run_check");
|
||||
TEST_COMPARE (run_check (), 0);
|
||||
recurse (depth - 1);
|
||||
xdlclose (handle);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* First run the test without nesting. */
|
||||
recurse (1);
|
||||
|
||||
/* Then with nesting. The constant needs to be less than the
|
||||
glibc.rtld.nns tunable (which is between 1 and DL_NNS). */
|
||||
recurse (10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+2
-2
@@ -264,7 +264,7 @@ do_test_dependency (void)
|
||||
xdlclose (moddep);
|
||||
}
|
||||
|
||||
for (int n = 1; n <= nmods; n++)
|
||||
for (int n = 1; n < nmods; n++)
|
||||
if (mods[n] != 0)
|
||||
unload_mod (n);
|
||||
}
|
||||
@@ -342,7 +342,7 @@ do_test_invalid_dependency (bool bind_now)
|
||||
xdlclose (moddep);
|
||||
}
|
||||
|
||||
for (int n = 1; n <= nmods; n++)
|
||||
for (int n = 1; n < nmods; n++)
|
||||
if (mods[n] != 0)
|
||||
unload_mod (n);
|
||||
}
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
# define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr)
|
||||
# define asprintf __asprintf
|
||||
# define opendir __opendir
|
||||
# define readdir __readdir
|
||||
# define readdir64 __readdir64
|
||||
# define closedir __closedir
|
||||
# define mempcpy __mempcpy
|
||||
# define struct_stat struct __stat64_t64
|
||||
# define lstat __lstat64_time64
|
||||
# define struct_stat64 struct __stat64_t64
|
||||
# define lstat64 __lstat64_time64
|
||||
# define feof_unlocked __feof_unlocked
|
||||
#else
|
||||
# define struct_stat struct stat
|
||||
# define struct_stat64 struct stat64
|
||||
#endif
|
||||
|
||||
/* Name of the file containing the module information in the directories
|
||||
@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
|
||||
DIR *confdir = opendir (buf);
|
||||
if (confdir != NULL)
|
||||
{
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir (confdir)) != NULL)
|
||||
struct dirent64 *ent;
|
||||
while ((ent = readdir64 (confdir)) != NULL)
|
||||
{
|
||||
if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN)
|
||||
continue;
|
||||
@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
|
||||
&& strcmp (ent->d_name + len - strlen (suffix), suffix) == 0)
|
||||
{
|
||||
char *conf;
|
||||
struct_stat st;
|
||||
struct_stat64 st;
|
||||
if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
|
||||
continue;
|
||||
|
||||
if (ent->d_type != DT_UNKNOWN
|
||||
|| (lstat (conf, &st) != -1 && S_ISREG (st.st_mode)))
|
||||
|| (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
|
||||
found |= read_conf_file (conf, dir, dir_len);
|
||||
|
||||
free (conf);
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
static void
|
||||
activate_test_gconv_modules (void)
|
||||
{
|
||||
unsigned long ptr = getauxval (AT_EXECFN);
|
||||
if (ptr == 0)
|
||||
const char *ptr = getauxptr (AT_EXECFN);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
printf ("warning: AT_EXECFN not support, cannot run test\n");
|
||||
exit (EXIT_UNSUPPORTED);
|
||||
}
|
||||
char *test_program_directory = dirname (xstrdup ((const char *) ptr));
|
||||
char *test_program_directory = dirname (xstrdup (ptr));
|
||||
TEST_VERIFY (setenv ("GCONV_PATH", test_program_directory, 1) == 0);
|
||||
free (test_program_directory);
|
||||
}
|
||||
|
||||
@@ -58,11 +58,11 @@ worker (void * arg)
|
||||
|
||||
char ascii[] = CONV_INPUT;
|
||||
char *inbufpos = ascii;
|
||||
size_t inbytesleft = sizeof (CONV_INPUT);
|
||||
size_t inbytesleft = sizeof (CONV_INPUT) - 1;
|
||||
|
||||
char *utf8 = xcalloc (sizeof (CONV_INPUT), 1);
|
||||
char *outbufpos = utf8;
|
||||
size_t outbytesleft = sizeof (CONV_INPUT);
|
||||
size_t outbytesleft = sizeof (CONV_INPUT) - 1;
|
||||
|
||||
if (tidx < TCOUNT/2)
|
||||
/* The first half of the worker thread pool synchronize together here,
|
||||
|
||||
@@ -248,9 +248,9 @@ __alloc_buffer_alloc (struct alloc_buffer *buf, size_t size, size_t align)
|
||||
if (size == 1 && align == 1)
|
||||
return alloc_buffer_alloc_bytes (buf, size);
|
||||
|
||||
size_t current = buf->__alloc_buffer_current;
|
||||
size_t aligned = roundup (current, align);
|
||||
size_t new_current = aligned + size;
|
||||
uintptr_t current = buf->__alloc_buffer_current;
|
||||
uintptr_t aligned = roundup (current, align);
|
||||
uintptr_t new_current = aligned + size;
|
||||
if (aligned >= current /* No overflow in align step. */
|
||||
&& new_current >= size /* No overflow in size computation. */
|
||||
&& new_current <= buf->__alloc_buffer_end) /* Room in buffer. */
|
||||
@@ -282,8 +282,8 @@ __alloc_buffer_next (struct alloc_buffer *buf, size_t align)
|
||||
if (align == 1)
|
||||
return (const void *) buf->__alloc_buffer_current;
|
||||
|
||||
size_t current = buf->__alloc_buffer_current;
|
||||
size_t aligned = roundup (current, align);
|
||||
uintptr_t current = buf->__alloc_buffer_current;
|
||||
uintptr_t aligned = roundup (current, align);
|
||||
if (aligned >= current /* No overflow in align step. */
|
||||
&& aligned <= buf->__alloc_buffer_end) /* Room in buffer. */
|
||||
{
|
||||
|
||||
@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW;
|
||||
int __ns_name_unpack (const unsigned char *, const unsigned char *,
|
||||
const unsigned char *, unsigned char *, size_t) __THROW;
|
||||
|
||||
/* Like ns_samename, but for uncompressed binary names. Return true
|
||||
if the two arguments compare are equal as case-insensitive domain
|
||||
names. */
|
||||
_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *)
|
||||
attribute_hidden;
|
||||
|
||||
#define ns_msg_getflag(handle, flag) \
|
||||
(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
|
||||
|
||||
@@ -89,5 +95,105 @@ libc_hidden_proto (__ns_name_unpack)
|
||||
extern __typeof (ns_samename) __libc_ns_samename;
|
||||
libc_hidden_proto (__libc_ns_samename)
|
||||
|
||||
/* Packet parser helper functions. */
|
||||
|
||||
/* Verify that P points to an uncompressed domain name in wire format.
|
||||
On success, return the length of the encoded name, including the
|
||||
terminating null byte. On failure, return -1 and set errno. EOM
|
||||
must point one past the last byte in the packet. */
|
||||
int __ns_name_length_uncompressed (const unsigned char *p,
|
||||
const unsigned char *eom) attribute_hidden;
|
||||
|
||||
/* Iterator over the resource records in a DNS packet. */
|
||||
struct ns_rr_cursor
|
||||
{
|
||||
/* These members are not changed after initialization. */
|
||||
const unsigned char *begin; /* First byte of packet. */
|
||||
const unsigned char *end; /* One past the last byte of the packet. */
|
||||
const unsigned char *first_rr; /* First resource record (or packet end). */
|
||||
|
||||
/* Advanced towards the end while reading the packet. */
|
||||
const unsigned char *current;
|
||||
};
|
||||
|
||||
/* Returns the RCODE field from the DNS header. */
|
||||
static inline int
|
||||
ns_rr_cursor_rcode (const struct ns_rr_cursor *c)
|
||||
{
|
||||
return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */
|
||||
}
|
||||
|
||||
/* Returns the length of the answer section according to the DNS header. */
|
||||
static inline int
|
||||
ns_rr_cursor_ancount (const struct ns_rr_cursor *c)
|
||||
{
|
||||
return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */
|
||||
}
|
||||
|
||||
/* Returns the length of the authority (name server) section according
|
||||
to the DNS header. */
|
||||
static inline int
|
||||
ns_rr_cursor_nscount (const struct ns_rr_cursor *c)
|
||||
{
|
||||
return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */
|
||||
}
|
||||
|
||||
/* Returns the length of the additional data section according to the
|
||||
DNS header. */
|
||||
static inline int
|
||||
ns_rr_cursor_adcount (const struct ns_rr_cursor *c)
|
||||
{
|
||||
return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */
|
||||
}
|
||||
|
||||
/* Returns a pointer to the uncompressed question name in wire
|
||||
format. */
|
||||
static inline const unsigned char *
|
||||
ns_rr_cursor_qname (const struct ns_rr_cursor *c)
|
||||
{
|
||||
return c->begin + 12; /* QNAME starts right after the header. */
|
||||
}
|
||||
|
||||
/* Returns the question type of the first and only question. */
|
||||
static inline const int
|
||||
ns_rr_cursor_qtype (const struct ns_rr_cursor *c)
|
||||
{
|
||||
/* 16 bits 4 bytes back from the first RR header start. */
|
||||
return c->first_rr[-4] * 256 + c->first_rr[-3];
|
||||
}
|
||||
|
||||
/* Returns the clss of the first and only question (usally C_IN). */
|
||||
static inline const int
|
||||
ns_rr_cursor_qclass (const struct ns_rr_cursor *c)
|
||||
{
|
||||
/* 16 bits 2 bytes back from the first RR header start. */
|
||||
return c->first_rr[-2] * 256 + c->first_rr[-1];
|
||||
}
|
||||
|
||||
/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false
|
||||
if LEN is less than sizeof (*HD), if the packet does not contain a
|
||||
full (uncompressed) question, or if the question count is not 1. */
|
||||
_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c,
|
||||
const unsigned char *buf, size_t len)
|
||||
attribute_hidden;
|
||||
|
||||
/* Like ns_rr, but the record owner name is not decoded into text format. */
|
||||
struct ns_rr_wire
|
||||
{
|
||||
unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */
|
||||
uint16_t rtype; /* Resource record type (T_*). */
|
||||
uint16_t rclass; /* Resource record class (C_*). */
|
||||
uint32_t ttl; /* Time-to-live field. */
|
||||
const unsigned char *rdata; /* Start of resource record data. */
|
||||
uint16_t rdlength; /* Length of the data at rdata, in bytes. */
|
||||
};
|
||||
|
||||
/* Attempts to parse the record at C into *RR. On success, return
|
||||
true, and C is advanced past the record, and RR->rdata points to
|
||||
the record data. On failure, errno is set to EMSGSIZE, and false
|
||||
is returned. */
|
||||
_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
|
||||
attribute_hidden;
|
||||
|
||||
# endif /* !_ISOMAC */
|
||||
#endif
|
||||
|
||||
+15
-2
@@ -62,6 +62,8 @@
|
||||
__atg1_result = pre##_32_##post (mem, __VA_ARGS__); \
|
||||
else if (sizeof (*mem) == 8) \
|
||||
__atg1_result = pre##_64_##post (mem, __VA_ARGS__); \
|
||||
else if (sizeof (*mem) == 16) \
|
||||
__atg1_result = pre##_128_##post (mem, __VA_ARGS__); \
|
||||
else \
|
||||
abort (); \
|
||||
__atg1_result; \
|
||||
@@ -77,6 +79,8 @@
|
||||
__atg2_result = pre##_32_##post (mem, __VA_ARGS__); \
|
||||
else if (sizeof (*mem) == 8) \
|
||||
__atg2_result = pre##_64_##post (mem, __VA_ARGS__); \
|
||||
else if (sizeof (*mem) == 16) \
|
||||
__atg2_result = pre##_128_##post (mem, __VA_ARGS__); \
|
||||
else \
|
||||
abort (); \
|
||||
__atg2_result; \
|
||||
@@ -540,7 +544,11 @@
|
||||
/* We require 32b atomic operations; some archs also support 64b atomic
|
||||
operations. */
|
||||
void __atomic_link_error (void);
|
||||
# if __HAVE_64B_ATOMICS == 1
|
||||
# if defined __CHERI_PURE_CAPABILITY__
|
||||
# define __atomic_check_size(mem) \
|
||||
if ((sizeof (*mem) != 4) && (sizeof (*mem) != 8) && (sizeof (*mem) != 16)) \
|
||||
__atomic_link_error ();
|
||||
# elif __HAVE_64B_ATOMICS == 1
|
||||
# define __atomic_check_size(mem) \
|
||||
if ((sizeof (*mem) != 4) && (sizeof (*mem) != 8)) \
|
||||
__atomic_link_error ();
|
||||
@@ -553,7 +561,12 @@ void __atomic_link_error (void);
|
||||
need other atomic operations of such sizes, and restricting the support to
|
||||
loads and stores makes this easier for archs that do not have native
|
||||
support for atomic operations to less-than-word-sized data. */
|
||||
# if __HAVE_64B_ATOMICS == 1
|
||||
# if defined __CHERI_PURE_CAPABILITY__
|
||||
# define __atomic_check_size_ls(mem) \
|
||||
if ((sizeof (*mem) != 1) && (sizeof (*mem) != 2) && (sizeof (*mem) != 4) \
|
||||
&& (sizeof (*mem) != 8) && (sizeof (*mem) != 16)) \
|
||||
__atomic_link_error ();
|
||||
# elif __HAVE_64B_ATOMICS == 1
|
||||
# define __atomic_check_size_ls(mem) \
|
||||
if ((sizeof (*mem) != 1) && (sizeof (*mem) != 2) && (sizeof (*mem) != 4) \
|
||||
&& (sizeof (*mem) != 8)) \
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include <wcsmbs/bits/wchar2-decl.h>
|
||||
@@ -43,7 +43,11 @@
|
||||
remember, if any of these versions change, the libc.so major version
|
||||
number must change too (so avoid it)! */
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
#define _GNU_OBSTACK_INTERFACE_VERSION 2 /* vs malloc/obstack.c */
|
||||
#else
|
||||
#define _GNU_OBSTACK_INTERFACE_VERSION 1 /* vs malloc/obstack.c */
|
||||
#endif
|
||||
#define _GNU_REGEX_INTERFACE_VERSION 1 /* vs posix/regex.c */
|
||||
#define _GNU_GLOB_INTERFACE_VERSION 2 /* vs posix/glob.c */
|
||||
#define _GNU_GETOPT_INTERFACE_VERSION 2 /* vs posix/getopt.c and
|
||||
|
||||
+15
-2
@@ -133,7 +133,7 @@ struct link_map
|
||||
ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
|
||||
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
|
||||
const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */
|
||||
ElfW(Addr) l_entry; /* Entry point location. */
|
||||
elfptr_t l_entry; /* Entry point location. */
|
||||
ElfW(Half) l_phnum; /* Number of program header entries. */
|
||||
ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */
|
||||
|
||||
@@ -252,9 +252,22 @@ struct link_map
|
||||
|
||||
/* Start and finish of memory map for this object. l_map_start
|
||||
need not be the same as l_addr. */
|
||||
ElfW(Addr) l_map_start, l_map_end;
|
||||
elfptr_t l_map_start;
|
||||
ElfW(Addr) l_map_end;
|
||||
/* End of the executable part of the mapping. */
|
||||
ElfW(Addr) l_text_end;
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
/* Writable part of the mapping (may have non-writable holes). */
|
||||
elfptr_t l_rw_start;
|
||||
# define DL_MAX_RW_COUNT 4
|
||||
/* Writable ranges: objects are writable in these ranges. */
|
||||
int l_rw_count;
|
||||
struct rw_range
|
||||
{
|
||||
ElfW(Addr) start;
|
||||
ElfW(Addr) end;
|
||||
} l_rw_range[DL_MAX_RW_COUNT];
|
||||
#endif
|
||||
|
||||
/* Default array for 'l_scope'. */
|
||||
struct r_scope_elem *l_scope_mem[4];
|
||||
|
||||
@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery)
|
||||
extern __typeof (__res_queriesmatch) __libc_res_queriesmatch;
|
||||
libc_hidden_proto (__libc_res_queriesmatch)
|
||||
|
||||
/* Variant of res_hnok which operates on binary (but uncompressed) names. */
|
||||
bool __res_binary_hnok (const unsigned char *dn) attribute_hidden;
|
||||
|
||||
# endif /* _RESOLV_H_ && !_ISOMAC */
|
||||
#endif
|
||||
|
||||
@@ -10,4 +10,8 @@ libc_hidden_proto (__getauxval)
|
||||
_Bool __getauxval2 (unsigned long int type, unsigned long int *result);
|
||||
libc_hidden_proto (__getauxval2)
|
||||
|
||||
/* Like getauxval, but for Arm Morello capabilities. */
|
||||
extern __typeof (getauxptr) __getauxptr;
|
||||
libc_hidden_proto (__getauxptr)
|
||||
|
||||
#endif /* !_ISOMAC */
|
||||
|
||||
+4
-2
@@ -340,8 +340,10 @@ read_alias_file (const char *fname, int fname_len)
|
||||
|
||||
for (i = 0; i < nmap; i++)
|
||||
{
|
||||
map[i].alias += new_pool - string_space;
|
||||
map[i].value += new_pool - string_space;
|
||||
map[i].alias = new_pool
|
||||
+ (map[i].alias - string_space);
|
||||
map[i].value = new_pool
|
||||
+ (map[i].value - string_space);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fts.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -67,7 +68,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
|
||||
#endif
|
||||
/* Align P to that size. */
|
||||
#ifndef ALIGN
|
||||
#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
|
||||
#define ALIGN(p) (((uintptr_t) (p) + ALIGNBYTES) & ~ALIGNBYTES)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -95,7 +95,9 @@ struct _IO_FILE_complete
|
||||
size_t __pad5;
|
||||
int _mode;
|
||||
/* Make sure we don't get into trouble again. */
|
||||
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
|
||||
char _unused2[sizeof (void *) == 4 * sizeof (int)
|
||||
? 9 * sizeof (int)
|
||||
: 15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
|
||||
};
|
||||
|
||||
/* These macros are used by bits/stdio.h and internal headers. */
|
||||
|
||||
+2
-2
@@ -247,8 +247,8 @@ __libc_tsd_define (extern, locale_t, LOCALE)
|
||||
But with thread-local locale settings, it becomes quite ungainly unless
|
||||
we can use __thread variables. So only in that case do we attempt this. */
|
||||
#ifndef SHARED
|
||||
# include <tls.h>
|
||||
# define NL_CURRENT_INDIRECT 1
|
||||
//# include <tls.h>
|
||||
//# define NL_CURRENT_INDIRECT 1
|
||||
#endif
|
||||
|
||||
#ifdef NL_CURRENT_INDIRECT
|
||||
|
||||
@@ -84,6 +84,13 @@ static const char *locnames[] =
|
||||
/* Size of the reserved address space area. */
|
||||
#define RESERVE_MMAP_SIZE 512 * 1024 * 1024
|
||||
|
||||
/* On CHERI targets ensure the mmap returned capability has RW permissions. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RW PROT_MAX (PROT_READ | PROT_WRITE)
|
||||
#else
|
||||
# define PROT_MAX_RW 0
|
||||
#endif
|
||||
|
||||
/* To prepare for enlargements of the mmaped area reserve some address
|
||||
space. On some machines, being a file mapping rather than an anonymous
|
||||
mapping affects the address selection. So do this mapping from the
|
||||
@@ -94,7 +101,8 @@ prepare_address_space (int fd, size_t total, size_t *reserved, int *xflags,
|
||||
{
|
||||
if (total < RESERVE_MMAP_SIZE)
|
||||
{
|
||||
void *p = mmap64 (NULL, RESERVE_MMAP_SIZE, PROT_NONE, MAP_SHARED, fd, 0);
|
||||
void *p = mmap64 (NULL, RESERVE_MMAP_SIZE,
|
||||
PROT_NONE | PROT_MAX_RW, MAP_SHARED, fd, 0);
|
||||
if (p != MAP_FAILED)
|
||||
{
|
||||
void *aligned_p = PTR_ALIGN_UP (p, MAP_FIXED_ALIGNMENT);
|
||||
|
||||
@@ -88,6 +88,7 @@ tests-exclude-hugetlb1 = \
|
||||
tst-interpose-thread \
|
||||
tst-interpose-static-nothread \
|
||||
tst-interpose-static-thread \
|
||||
tst-malloc-backtrace \
|
||||
tst-malloc-usable \
|
||||
tst-malloc-usable-tunables \
|
||||
tst-mallocstate
|
||||
@@ -159,6 +160,8 @@ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
libc_malloc_debug-routines = malloc-debug $(sysdep_malloc_debug_routines)
|
||||
libc_malloc_debug-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
|
||||
tst-malloc-backtrace-ENV = GLIBC_TUNABLES=glibc.mem.cap_narrowing=0
|
||||
|
||||
$(objpfx)tst-malloc-backtrace: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
|
||||
@@ -331,12 +334,14 @@ $(objpfx)tst-interpose-static-thread: \
|
||||
$(objpfx)tst-interpose-aux-thread.o $(static-thread-library)
|
||||
|
||||
tst-dynarray-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray.mtrace \
|
||||
GLIBC_TUNABLES=glibc.mem.cap_narrowing=0 \
|
||||
LD_PRELOAD=$(objpfx)libc_malloc_debug.so
|
||||
$(objpfx)tst-dynarray-mem.out: $(objpfx)tst-dynarray.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-dynarray.mtrace > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
tst-dynarray-fail-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray-fail.mtrace \
|
||||
GLIBC_TUNABLES=glibc.mem.cap_narrowing=0 \
|
||||
LD_PRELOAD=$(objpfx)libc_malloc_debug.so
|
||||
$(objpfx)tst-dynarray-fail-mem.out: $(objpfx)tst-dynarray-fail.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-dynarray-fail.mtrace > $@; \
|
||||
|
||||
@@ -23,12 +23,12 @@ void *
|
||||
__libc_alloc_buffer_alloc_array (struct alloc_buffer *buf, size_t element_size,
|
||||
size_t align, size_t count)
|
||||
{
|
||||
size_t current = buf->__alloc_buffer_current;
|
||||
uintptr_t current = buf->__alloc_buffer_current;
|
||||
/* The caller asserts that align is a power of two. */
|
||||
size_t aligned = ALIGN_UP (current, align);
|
||||
uintptr_t aligned = ALIGN_UP (current, align);
|
||||
size_t size;
|
||||
bool overflow = __builtin_mul_overflow (element_size, count, &size);
|
||||
size_t new_current = aligned + size;
|
||||
uintptr_t new_current = aligned + size;
|
||||
if (!overflow /* Multiplication did not overflow. */
|
||||
&& aligned >= current /* No overflow in align step. */
|
||||
&& new_current >= size /* No overflow in size computation. */
|
||||
|
||||
+33
-3
@@ -191,6 +191,7 @@ __malloc_fork_lock_parent (void)
|
||||
if (ar_ptr == &main_arena)
|
||||
break;
|
||||
}
|
||||
cap_fork_lock ();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -199,6 +200,8 @@ __malloc_fork_unlock_parent (void)
|
||||
if (!__malloc_initialized)
|
||||
return;
|
||||
|
||||
cap_fork_unlock_parent ();
|
||||
|
||||
for (mstate ar_ptr = &main_arena;; )
|
||||
{
|
||||
__libc_lock_unlock (ar_ptr->mutex);
|
||||
@@ -215,6 +218,8 @@ __malloc_fork_unlock_child (void)
|
||||
if (!__malloc_initialized)
|
||||
return;
|
||||
|
||||
cap_fork_unlock_child ();
|
||||
|
||||
/* Push all arenas to the free list, except thread_arena, which is
|
||||
attached to the current thread. */
|
||||
__libc_lock_init (free_list_lock);
|
||||
@@ -321,6 +326,21 @@ ptmalloc_init (void)
|
||||
tcache_key_initialize ();
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
__always_fail_morecore = true;
|
||||
if (TUNABLE_GET_FULL (glibc, mem, cap_narrowing, int32_t, NULL) == 0)
|
||||
cap_narrowing_enabled = false;
|
||||
else
|
||||
{
|
||||
cap_narrowing_enabled = true;
|
||||
# ifdef __CAP_MMAP_THRESHOLD
|
||||
/* Default mmap threshold to avoid heap fragmentation. */
|
||||
do_set_mmap_threshold (__CAP_MMAP_THRESHOLD);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
cap_init ();
|
||||
|
||||
#ifdef USE_MTAG
|
||||
if ((TUNABLE_GET_FULL (glibc, mem, tagging, int32_t, NULL) & 1) != 0)
|
||||
{
|
||||
@@ -444,7 +464,7 @@ dump_heap (heap_info *heap)
|
||||
fprintf (stderr, "Heap %p, size %10lx:\n", heap, (long) heap->size);
|
||||
ptr = (heap->ar_ptr != (mstate) (heap + 1)) ?
|
||||
(char *) (heap + 1) : (char *) (heap + 1) + sizeof (struct malloc_state);
|
||||
p = (mchunkptr) (((unsigned long) ptr + MALLOC_ALIGN_MASK) &
|
||||
p = (mchunkptr) (((uintptr_t) ptr + MALLOC_ALIGN_MASK) &
|
||||
~MALLOC_ALIGN_MASK);
|
||||
for (;; )
|
||||
{
|
||||
@@ -518,7 +538,7 @@ alloc_new_heap (size_t size, size_t top_pad, size_t pagesize,
|
||||
p1 = (char *) MMAP (0, max_size << 1, PROT_NONE, mmap_flags);
|
||||
if (p1 != MAP_FAILED)
|
||||
{
|
||||
p2 = (char *) (((unsigned long) p1 + (max_size - 1))
|
||||
p2 = (char *) (((uintptr_t) p1 + (max_size - 1))
|
||||
& ~(max_size - 1));
|
||||
ul = p2 - p1;
|
||||
if (ul)
|
||||
@@ -526,6 +546,9 @@ alloc_new_heap (size_t size, size_t top_pad, size_t pagesize,
|
||||
else
|
||||
aligned_heap_area = p2 + max_size;
|
||||
__munmap (p2 + max_size, max_size - ul);
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
p2 = __builtin_cheri_bounds_set_exact (p2, max_size);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -548,6 +571,12 @@ alloc_new_heap (size_t size, size_t top_pad, size_t pagesize,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cap_map_add (p2))
|
||||
{
|
||||
__munmap (p2, max_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
madvise_thp (p2, size);
|
||||
|
||||
h = (heap_info *) p2;
|
||||
@@ -670,6 +699,7 @@ heap_trim (heap_info *heap, size_t pad)
|
||||
LIBC_PROBE (memory_heap_free, 2, heap, heap->size);
|
||||
if ((char *) heap + max_size == aligned_heap_area)
|
||||
aligned_heap_area = NULL;
|
||||
cap_map_del (heap);
|
||||
__munmap (heap, max_size);
|
||||
heap = prev_heap;
|
||||
if (!prev_inuse (p)) /* consolidate backward */
|
||||
@@ -760,7 +790,7 @@ _int_new_arena (size_t size)
|
||||
|
||||
/* Set up the top chunk, with proper alignment. */
|
||||
ptr = (char *) (a + 1);
|
||||
misalign = (unsigned long) chunk2mem (ptr) & MALLOC_ALIGN_MASK;
|
||||
misalign = (uintptr_t) chunk2mem (ptr) & MALLOC_ALIGN_MASK;
|
||||
if (misalign > 0)
|
||||
ptr += MALLOC_ALIGNMENT - misalign;
|
||||
top (a) = (mchunkptr) ptr;
|
||||
|
||||
+365
-22
@@ -244,6 +244,9 @@
|
||||
/* For memory tagging. */
|
||||
#include <libc-mtag.h>
|
||||
|
||||
/* For CHERI capability narrowing. */
|
||||
#include <libc-cap.h>
|
||||
|
||||
#include <malloc/malloc-internal.h>
|
||||
|
||||
/* For SINGLE_THREAD_P. */
|
||||
@@ -341,8 +344,12 @@ Fatal glibc error: malloc assertion failure in %s: %s\n",
|
||||
It assumes a minimum page size of 4096 bytes (12 bits). Systems with
|
||||
larger pages provide less entropy, although the pointer mangling
|
||||
still works. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
#define PROTECT_PTR(pos, ptr) (ptr)
|
||||
#else
|
||||
#define PROTECT_PTR(pos, ptr) \
|
||||
((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
|
||||
#endif
|
||||
#define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr)
|
||||
|
||||
/*
|
||||
@@ -478,6 +485,153 @@ tag_at (void *ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* CHERI capability narrowing support. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
static bool cap_narrowing_enabled = true;
|
||||
#else
|
||||
# define cap_narrowing_enabled 0
|
||||
#endif
|
||||
|
||||
static __always_inline void
|
||||
cap_init (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
assert (__libc_cap_init ());
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
cap_fork_lock (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_fork_lock ();
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
cap_fork_unlock_parent (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_fork_unlock_parent ();
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
cap_fork_unlock_child (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_fork_unlock_child ();
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
cap_map_add (void *p)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_map_add (p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
cap_map_del (void *p)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_map_del (p);
|
||||
}
|
||||
|
||||
/* Round up size so capability bounds can be represented. */
|
||||
static __always_inline size_t
|
||||
cap_roundup (size_t n)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_roundup (n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Alignment such that capability bounds can be represented. */
|
||||
static __always_inline size_t
|
||||
cap_align (size_t n)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_align (n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Narrow the bounds of p to [p, p+n) exactly unless p is NULL.
|
||||
Must match a previous cap_reserve call. */
|
||||
static __always_inline void *
|
||||
cap_narrow (void *p, size_t n)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
{
|
||||
if (p == NULL)
|
||||
__libc_cap_unreserve ();
|
||||
else
|
||||
p = __libc_cap_narrow (p, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Used in realloc if p is already narrowed or NULL.
|
||||
Must match a previous cap_reserve call. */
|
||||
static __always_inline bool
|
||||
cap_narrow_check (void *p, void *oldp, void *narrow_oldp)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
{
|
||||
if (p == NULL)
|
||||
__libc_cap_put_back (oldp, narrow_oldp);
|
||||
else
|
||||
__libc_cap_unreserve ();
|
||||
}
|
||||
return p != NULL;
|
||||
}
|
||||
|
||||
/* Used in realloc if p is new allocation or NULL but not yet narrowed.
|
||||
Must match a previous cap_reserve call. */
|
||||
static __always_inline void *
|
||||
cap_narrow_try (void *p, size_t n, void *oldp, void *narrow_oldp)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
{
|
||||
if (p == NULL)
|
||||
__libc_cap_put_back (oldp, narrow_oldp);
|
||||
else
|
||||
p = __libc_cap_narrow (p, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Widen back the bounds of a non-NULL p that was returned by cap_narrow. */
|
||||
static __always_inline void *
|
||||
cap_widen (void *p)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_widen (p);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Reserve memory for the following cap_narrow, this may fail with ENOMEM. */
|
||||
static __always_inline bool
|
||||
cap_reserve (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_reserve ();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Release the reserved memory by cap_reserve. */
|
||||
static __always_inline void
|
||||
cap_unreserve (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_unreserve ();
|
||||
}
|
||||
|
||||
/* Remove p so cap_widen no longer works on it. */
|
||||
static __always_inline void
|
||||
cap_drop (void *p)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_drop (p);
|
||||
}
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
@@ -1130,8 +1284,16 @@ static mchunkptr mremap_chunk(mchunkptr p, size_t new_size);
|
||||
# define MAP_NORESERVE 0
|
||||
#endif
|
||||
|
||||
/* Allow RW mprotect later, on CHERI this means RW capability permission. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RW PROT_MAX (PROT_READ | PROT_WRITE)
|
||||
#else
|
||||
# define PROT_MAX_RW 0
|
||||
#endif
|
||||
|
||||
#define MMAP(addr, size, prot, flags) \
|
||||
__mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)
|
||||
__mmap((addr), (size), (prot)|PROT_MAX_RW, \
|
||||
(flags)|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)
|
||||
|
||||
|
||||
/*
|
||||
@@ -1288,6 +1450,18 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
_int_memalign: Returns untagged memory.
|
||||
_mid_memalign: Returns tagged memory.
|
||||
_int_realloc: Takes and returns tagged memory.
|
||||
|
||||
With CHERI capability narrowing enabled, public interfaces take and
|
||||
return pointers with bounds that cannot access malloc internal chunk
|
||||
headers. Narrowing CHERI capabilities in internal interfaces:
|
||||
|
||||
sysmalloc: Returns wide capability.
|
||||
_int_malloc: Returns wide capability.
|
||||
_int_free: Takes wide capability.
|
||||
_int_memalign: Returns wide capability.
|
||||
_int_memalign: Returns wide capability.
|
||||
_mid_memalign: Returns narrow capability.
|
||||
_int_realloc: Takes and returns wide capability.
|
||||
*/
|
||||
|
||||
/* The chunk header is two SIZE_SZ elements, but this is used widely, so
|
||||
@@ -2438,6 +2612,12 @@ sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags, mstate av)
|
||||
if (mm == MAP_FAILED)
|
||||
return mm;
|
||||
|
||||
if (!cap_map_add (mm))
|
||||
{
|
||||
__munmap (mm, size);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
#ifdef MAP_HUGETLB
|
||||
if (!(extra_flags & MAP_HUGETLB))
|
||||
madvise_thp (mm, size);
|
||||
@@ -2523,6 +2703,12 @@ sysmalloc_mmap_fallback (long int *s, INTERNAL_SIZE_T nb,
|
||||
if (mbrk == MAP_FAILED)
|
||||
return MAP_FAILED;
|
||||
|
||||
if (!cap_map_add (mbrk))
|
||||
{
|
||||
__munmap (mbrk, size);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
#ifdef MAP_HUGETLB
|
||||
if (!(extra_flags & MAP_HUGETLB))
|
||||
madvise_thp (mbrk, size);
|
||||
@@ -3056,6 +3242,8 @@ munmap_chunk (mchunkptr p)
|
||||
atomic_decrement (&mp_.n_mmaps);
|
||||
atomic_add (&mp_.mmapped_mem, -total_size);
|
||||
|
||||
cap_map_del ((void *) block);
|
||||
|
||||
/* If munmap failed the process virtual memory address space is in a
|
||||
bad shape. Just leave the block hanging around, the process will
|
||||
terminate shortly anyway since not much can be done. */
|
||||
@@ -3094,6 +3282,9 @@ mremap_chunk (mchunkptr p, size_t new_size)
|
||||
if (cp == MAP_FAILED)
|
||||
return 0;
|
||||
|
||||
cap_map_del ((void *) block);
|
||||
cap_map_add (cp);
|
||||
|
||||
madvise_thp (cp, new_size);
|
||||
|
||||
p = (mchunkptr) (cp + offset);
|
||||
@@ -3193,6 +3384,35 @@ tcache_get (size_t tc_idx)
|
||||
return (void *) e;
|
||||
}
|
||||
|
||||
/* Cut down __libc_free for cleaning up tcache entries. */
|
||||
static void
|
||||
tcache_libc_free (void *mem)
|
||||
{
|
||||
int err = errno;
|
||||
mchunkptr p = mem2chunk(mem);
|
||||
if (chunk_is_mmapped (p))
|
||||
{
|
||||
/* See if the dynamic brk/mmap threshold needs adjusting.
|
||||
Dumped fake mmapped chunks do not affect the threshold. */
|
||||
if (!mp_.no_dyn_threshold
|
||||
&& chunksize_nomask (p) > mp_.mmap_threshold
|
||||
&& chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX)
|
||||
{
|
||||
mp_.mmap_threshold = chunksize (p);
|
||||
mp_.trim_threshold = 2 * mp_.mmap_threshold;
|
||||
LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
|
||||
mp_.mmap_threshold, mp_.trim_threshold);
|
||||
}
|
||||
munmap_chunk (p);
|
||||
}
|
||||
else
|
||||
{
|
||||
mstate ar_ptr = arena_for_chunk (p);
|
||||
_int_free (ar_ptr, p, 0);
|
||||
}
|
||||
__set_errno (err);
|
||||
}
|
||||
|
||||
static void
|
||||
tcache_thread_shutdown (void)
|
||||
{
|
||||
@@ -3218,11 +3438,11 @@ tcache_thread_shutdown (void)
|
||||
malloc_printerr ("tcache_thread_shutdown(): "
|
||||
"unaligned tcache chunk detected");
|
||||
tcache_tmp->entries[i] = REVEAL_PTR (e->next);
|
||||
__libc_free (e);
|
||||
tcache_libc_free (e);
|
||||
}
|
||||
}
|
||||
|
||||
__libc_free (tcache_tmp);
|
||||
tcache_libc_free (tcache_tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3287,7 +3507,13 @@ __libc_malloc (size_t bytes)
|
||||
|
||||
if (!__malloc_initialized)
|
||||
ptmalloc_init ();
|
||||
|
||||
size_t align = cap_align (bytes);
|
||||
bytes = cap_roundup (bytes);
|
||||
#if USE_TCACHE
|
||||
_Static_assert (MAX_TCACHE_SIZE <= __CAP_ALIGN_THRESHOLD,
|
||||
"tcache entries are already aligned for capability narrowing");
|
||||
|
||||
/* int_free also calls request2size, be careful to not pad twice. */
|
||||
size_t tbytes = checked_request2size (bytes);
|
||||
if (tbytes == 0)
|
||||
@@ -3304,17 +3530,28 @@ __libc_malloc (size_t bytes)
|
||||
&& tcache
|
||||
&& tcache->counts[tc_idx] > 0)
|
||||
{
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
victim = tcache_get (tc_idx);
|
||||
return tag_new_usable (victim);
|
||||
victim = tag_new_usable (victim);
|
||||
victim = cap_narrow (victim, bytes);
|
||||
return victim;
|
||||
}
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
#endif
|
||||
|
||||
if (align > MALLOC_ALIGNMENT)
|
||||
return _mid_memalign (align, bytes, 0);
|
||||
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
|
||||
if (SINGLE_THREAD_P)
|
||||
{
|
||||
victim = tag_new_usable (_int_malloc (&main_arena, bytes));
|
||||
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
|
||||
&main_arena == arena_for_chunk (mem2chunk (victim)));
|
||||
victim = cap_narrow (victim, bytes);
|
||||
return victim;
|
||||
}
|
||||
|
||||
@@ -3337,6 +3574,7 @@ __libc_malloc (size_t bytes)
|
||||
|
||||
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
|
||||
ar_ptr == arena_for_chunk (mem2chunk (victim)));
|
||||
victim = cap_narrow (victim, bytes);
|
||||
return victim;
|
||||
}
|
||||
libc_hidden_def (__libc_malloc)
|
||||
@@ -3350,6 +3588,10 @@ __libc_free (void *mem)
|
||||
if (mem == 0) /* free(0) has no effect */
|
||||
return;
|
||||
|
||||
void *orig_mem = mem;
|
||||
mem = cap_widen (mem);
|
||||
cap_drop (orig_mem);
|
||||
|
||||
/* Quickly check that the freed pointer matches the tag for the memory.
|
||||
This gives a useful double-free detection. */
|
||||
if (__glibc_unlikely (mtag_enabled))
|
||||
@@ -3411,6 +3653,9 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
if (oldmem == 0)
|
||||
return __libc_malloc (bytes);
|
||||
|
||||
void *orig_oldmem = oldmem;
|
||||
oldmem = cap_widen (oldmem);
|
||||
|
||||
/* Perform a quick check to ensure that the pointer's tag matches the
|
||||
memory's tag. */
|
||||
if (__glibc_unlikely (mtag_enabled))
|
||||
@@ -3437,6 +3682,8 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
|| __builtin_expect (misaligned_chunk (oldp), 0)))
|
||||
malloc_printerr ("realloc(): invalid pointer");
|
||||
|
||||
size_t align = cap_align (bytes);
|
||||
bytes = cap_roundup (bytes);
|
||||
nb = checked_request2size (bytes);
|
||||
if (nb == 0)
|
||||
{
|
||||
@@ -3444,10 +3691,23 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Every return path below should unreserve using the cap_narrow* apis. */
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
cap_drop (orig_oldmem);
|
||||
|
||||
if (chunk_is_mmapped (oldp))
|
||||
{
|
||||
void *newmem;
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
size_t pagesize = GLRO (dl_pagesize);
|
||||
|
||||
// TODO: with pcuabi kernel more cases can be handled by mremap
|
||||
/* Don't try in-place realloc if oldmem is unaligned. */
|
||||
if (align <= pagesize && ((size_t) oldmem & (align - 1)) == 0)
|
||||
{
|
||||
#endif
|
||||
#if HAVE_MREMAP
|
||||
newp = mremap_chunk (oldp, nb);
|
||||
if (newp)
|
||||
@@ -3458,30 +3718,65 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
reused. There's a performance hit for both us and the
|
||||
caller for doing this, so we might want to
|
||||
reconsider. */
|
||||
return tag_new_usable (newmem);
|
||||
newmem = tag_new_usable (newmem);
|
||||
newmem = cap_narrow_try (newmem, bytes, oldmem, orig_oldmem);
|
||||
return newmem;
|
||||
}
|
||||
#endif
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
}
|
||||
size_t sz = oldsize - CHUNK_HDR_SZ;
|
||||
/* In-place realloc if the size shrinks, but if it shrinks a lot
|
||||
then don't waste the rest of the mapping. */
|
||||
if (sz >= bytes && sz / 4 < bytes
|
||||
&& ((size_t) oldmem & (align - 1)) == 0)
|
||||
return cap_narrow (oldmem, bytes);
|
||||
#else
|
||||
/* Note the extra SIZE_SZ overhead. */
|
||||
if (oldsize - SIZE_SZ >= nb)
|
||||
return oldmem; /* do nothing */
|
||||
#endif
|
||||
|
||||
/* Must alloc, copy, free. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (align > MALLOC_ALIGNMENT)
|
||||
newmem = _mid_memalign (align, bytes, 0);
|
||||
else
|
||||
#endif
|
||||
newmem = __libc_malloc (bytes);
|
||||
if (newmem == 0)
|
||||
if (!cap_narrow_check (newmem, oldmem, orig_oldmem))
|
||||
return 0; /* propagate failure */
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
memcpy (newmem, oldmem, sz < bytes ? sz : bytes);
|
||||
#else
|
||||
memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
|
||||
#endif
|
||||
munmap_chunk (oldp);
|
||||
return newmem;
|
||||
}
|
||||
|
||||
/* Large alignment is required and it's not possible to realloc in place. */
|
||||
if (align > MALLOC_ALIGNMENT
|
||||
&& (oldsize < nb || ((size_t) oldmem & (align - 1)) != 0))
|
||||
{
|
||||
/* Use memalign, copy, free. */
|
||||
void *newmem = _mid_memalign (align, bytes, 0);
|
||||
if (!cap_narrow_check (newmem, oldmem, orig_oldmem))
|
||||
return newmem;
|
||||
size_t sz = memsize (oldp);
|
||||
memcpy (newmem, oldmem, sz < bytes ? sz : bytes);
|
||||
(void) tag_region (chunk2mem (oldp), sz);
|
||||
_int_free (ar_ptr, oldp, 0);
|
||||
return newmem;
|
||||
}
|
||||
|
||||
if (SINGLE_THREAD_P)
|
||||
{
|
||||
newp = _int_realloc (ar_ptr, oldp, oldsize, nb);
|
||||
assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
|
||||
ar_ptr == arena_for_chunk (mem2chunk (newp)));
|
||||
|
||||
return newp;
|
||||
return cap_narrow_try (newp, bytes, oldmem, orig_oldmem);
|
||||
}
|
||||
|
||||
__libc_lock_lock (ar_ptr->mutex);
|
||||
@@ -3497,14 +3792,15 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
/* Try harder to allocate memory in other arenas. */
|
||||
LIBC_PROBE (memory_realloc_retry, 2, bytes, oldmem);
|
||||
newp = __libc_malloc (bytes);
|
||||
if (newp != NULL)
|
||||
{
|
||||
size_t sz = memsize (oldp);
|
||||
memcpy (newp, oldmem, sz);
|
||||
(void) tag_region (chunk2mem (oldp), sz);
|
||||
_int_free (ar_ptr, oldp, 0);
|
||||
}
|
||||
if (!cap_narrow_check (newp, oldmem, orig_oldmem))
|
||||
return NULL;
|
||||
size_t sz = memsize (oldp);
|
||||
memcpy (newp, oldmem, sz);
|
||||
(void) tag_region (chunk2mem (oldp), sz);
|
||||
_int_free (ar_ptr, oldp, 0);
|
||||
}
|
||||
else
|
||||
newp = cap_narrow (newp, bytes);
|
||||
|
||||
return newp;
|
||||
}
|
||||
@@ -3517,6 +3813,11 @@ __libc_memalign (size_t alignment, size_t bytes)
|
||||
ptmalloc_init ();
|
||||
|
||||
void *address = RETURN_ADDRESS (0);
|
||||
|
||||
size_t align = cap_align (bytes);
|
||||
bytes = cap_roundup (bytes);
|
||||
if (align > alignment)
|
||||
alignment = align;
|
||||
return _mid_memalign (alignment, bytes, address);
|
||||
}
|
||||
|
||||
@@ -3542,6 +3843,8 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
|
||||
/* Make sure alignment is power of 2. */
|
||||
if (!powerof2 (alignment))
|
||||
@@ -3557,7 +3860,9 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
|
||||
p = _int_memalign (&main_arena, alignment, bytes);
|
||||
assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
|
||||
&main_arena == arena_for_chunk (mem2chunk (p)));
|
||||
return tag_new_usable (p);
|
||||
p = tag_new_usable (p);
|
||||
p = cap_narrow (p, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
arena_get (ar_ptr, bytes + alignment + MINSIZE);
|
||||
@@ -3575,7 +3880,9 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
|
||||
|
||||
assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
|
||||
ar_ptr == arena_for_chunk (mem2chunk (p)));
|
||||
return tag_new_usable (p);
|
||||
p = tag_new_usable (p);
|
||||
p = cap_narrow (p, bytes);
|
||||
return p;
|
||||
}
|
||||
/* For ISO C11. */
|
||||
weak_alias (__libc_memalign, aligned_alloc)
|
||||
@@ -3589,6 +3896,10 @@ __libc_valloc (size_t bytes)
|
||||
|
||||
void *address = RETURN_ADDRESS (0);
|
||||
size_t pagesize = GLRO (dl_pagesize);
|
||||
size_t align = cap_align (bytes);
|
||||
bytes = cap_roundup (bytes);
|
||||
if (align > pagesize)
|
||||
pagesize = align;
|
||||
return _mid_memalign (pagesize, bytes, address);
|
||||
}
|
||||
|
||||
@@ -3611,6 +3922,10 @@ __libc_pvalloc (size_t bytes)
|
||||
}
|
||||
rounded_bytes = rounded_bytes & -(pagesize - 1);
|
||||
|
||||
size_t align = cap_align (rounded_bytes);
|
||||
rounded_bytes = cap_roundup (rounded_bytes);
|
||||
if (align > pagesize)
|
||||
pagesize = align;
|
||||
return _mid_memalign (pagesize, rounded_bytes, address);
|
||||
}
|
||||
|
||||
@@ -3633,12 +3948,28 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
}
|
||||
|
||||
sz = bytes;
|
||||
sz = cap_roundup (sz);
|
||||
|
||||
if (!__malloc_initialized)
|
||||
ptmalloc_init ();
|
||||
|
||||
size_t align = cap_align (bytes);
|
||||
if (align > MALLOC_ALIGNMENT)
|
||||
{
|
||||
mem = _mid_memalign (align, sz, 0);
|
||||
if (mem == NULL)
|
||||
return mem;
|
||||
mchunkptr p = mem2chunk (cap_widen (mem));
|
||||
if (chunk_is_mmapped (p) && __glibc_likely (perturb_byte == 0))
|
||||
return mem;
|
||||
return memset (mem, 0, sz);
|
||||
}
|
||||
|
||||
MAYBE_INIT_TCACHE ();
|
||||
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
|
||||
if (SINGLE_THREAD_P)
|
||||
av = &main_arena;
|
||||
else
|
||||
@@ -3690,6 +4021,8 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
}
|
||||
|
||||
/* Allocation failed even after a retry. */
|
||||
if (mem == 0)
|
||||
cap_unreserve ();
|
||||
if (mem == 0)
|
||||
return 0;
|
||||
|
||||
@@ -3699,13 +4032,19 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
regardless of MORECORE_CLEARS, so we zero the whole block while
|
||||
doing so. */
|
||||
if (__glibc_unlikely (mtag_enabled))
|
||||
return tag_new_zero_region (mem, memsize (p));
|
||||
{
|
||||
mem = tag_new_zero_region (mem, memsize (p));
|
||||
mem = cap_narrow (mem, sz);
|
||||
return mem;
|
||||
}
|
||||
|
||||
INTERNAL_SIZE_T csz = chunksize (p);
|
||||
|
||||
/* Two optional cases in which clearing not necessary */
|
||||
if (chunk_is_mmapped (p))
|
||||
{
|
||||
mem = cap_narrow (mem, sz);
|
||||
|
||||
if (__builtin_expect (perturb_byte, 0))
|
||||
return memset (mem, 0, sz);
|
||||
|
||||
@@ -3729,8 +4068,7 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
assert (nclears >= 3);
|
||||
|
||||
if (nclears > 9)
|
||||
return memset (d, 0, clearsize);
|
||||
|
||||
mem = memset (mem, 0, clearsize);
|
||||
else
|
||||
{
|
||||
*(d + 0) = 0;
|
||||
@@ -3753,6 +4091,7 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
}
|
||||
}
|
||||
|
||||
mem = cap_narrow (mem, sz);
|
||||
return mem;
|
||||
}
|
||||
#endif /* IS_IN (libc) */
|
||||
@@ -4978,8 +5317,7 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
|
||||
we can move to the next aligned spot -- we've allocated enough
|
||||
total room so that this is always possible.
|
||||
*/
|
||||
brk = (char *) mem2chunk (((unsigned long) (m + alignment - 1)) &
|
||||
- ((signed long) alignment));
|
||||
brk = (char *) mem2chunk (m + alignment - ((unsigned long) (m) % alignment));
|
||||
if ((unsigned long) (brk - (char *) (p)) < MINSIZE)
|
||||
brk += alignment;
|
||||
|
||||
@@ -5135,6 +5473,7 @@ __malloc_usable_size (void *m)
|
||||
{
|
||||
if (m == NULL)
|
||||
return 0;
|
||||
m = cap_widen (m);
|
||||
return musable (m);
|
||||
}
|
||||
#endif
|
||||
@@ -5681,6 +6020,10 @@ __posix_memalign (void **memptr, size_t alignment, size_t size)
|
||||
|| alignment == 0)
|
||||
return EINVAL;
|
||||
|
||||
size_t align = cap_align (size);
|
||||
size = cap_roundup (size);
|
||||
if (align > alignment)
|
||||
alignment = align;
|
||||
|
||||
void *address = RETURN_ADDRESS (0);
|
||||
mem = _mid_memalign (alignment, size, address);
|
||||
|
||||
+7
-28
@@ -28,7 +28,11 @@
|
||||
/* NOTE BEFORE MODIFYING THIS FILE: This version number must be
|
||||
incremented whenever callers compiled using an old obstack.h can no
|
||||
longer properly call the functions in this obstack.c. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
#define OBSTACK_INTERFACE_VERSION 2
|
||||
#else
|
||||
#define OBSTACK_INTERFACE_VERSION 1
|
||||
#endif
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, and are not
|
||||
actually compiling the library itself, and the installed library
|
||||
@@ -53,6 +57,7 @@
|
||||
|
||||
|
||||
# include <stdint.h>
|
||||
# include <string.h>
|
||||
|
||||
/* Determine default alignment. */
|
||||
union fooround
|
||||
@@ -75,15 +80,6 @@ enum
|
||||
DEFAULT_ROUNDING = sizeof (union fooround)
|
||||
};
|
||||
|
||||
/* When we copy a long block of data, this is the unit to do it with.
|
||||
On some machines, copying successive ints does not work;
|
||||
in such a case, redefine COPYING_UNIT to 'long' (if that works)
|
||||
or 'char' as a last resort. */
|
||||
# ifndef COPYING_UNIT
|
||||
# define COPYING_UNIT int
|
||||
# endif
|
||||
|
||||
|
||||
/* The functions allocating more room by calling 'obstack_chunk_alloc'
|
||||
jump to the handler pointed to by 'obstack_alloc_failed_handler'.
|
||||
This can be set to a user defined function which should either
|
||||
@@ -269,25 +265,8 @@ _obstack_newchunk (struct obstack *h, int length)
|
||||
object_base =
|
||||
__PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
|
||||
|
||||
/* Move the existing object to the new chunk.
|
||||
Word at a time is fast and is safe if the object
|
||||
is sufficiently aligned. */
|
||||
if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
|
||||
{
|
||||
for (i = obj_size / sizeof (COPYING_UNIT) - 1;
|
||||
i >= 0; i--)
|
||||
((COPYING_UNIT *) object_base)[i]
|
||||
= ((COPYING_UNIT *) h->object_base)[i];
|
||||
/* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
|
||||
but that can cross a page boundary on a machine
|
||||
which does not do strict alignment for COPYING_UNITS. */
|
||||
already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
|
||||
}
|
||||
else
|
||||
already = 0;
|
||||
/* Copy remaining bytes one by one. */
|
||||
for (i = already; i < obj_size; i++)
|
||||
object_base[i] = h->object_base[i];
|
||||
/* Move the existing object to the new chunk. */
|
||||
memcpy (object_base, h->object_base, obj_size);
|
||||
|
||||
/* If the object just copied was the only data in OLD_CHUNK,
|
||||
free that chunk and remove it from the chain.
|
||||
|
||||
+3
-16
@@ -116,22 +116,9 @@
|
||||
# define PTR_INT_TYPE ptrdiff_t
|
||||
#endif
|
||||
|
||||
/* If B is the base of an object addressed by P, return the result of
|
||||
aligning P to the next multiple of A + 1. B and P must be of type
|
||||
char *. A + 1 must be a power of 2. */
|
||||
|
||||
#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
|
||||
|
||||
/* Similar to _BPTR_ALIGN (B, P, A), except optimize the common case
|
||||
where pointers can be converted to integers, aligned as integers,
|
||||
and converted back again. If PTR_INT_TYPE is narrower than a
|
||||
pointer (e.g., the AS/400), play it safe and compute the alignment
|
||||
relative to B. Otherwise, use the faster strategy of computing the
|
||||
alignment relative to 0. */
|
||||
|
||||
#define __PTR_ALIGN(B, P, A) \
|
||||
__BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
|
||||
P, A)
|
||||
/* Align P to the next multiple of A + 1, where A + 1 is a power of 2,
|
||||
A fits into unsigned long and P has type char *. */
|
||||
#define __PTR_ALIGN(B, P, A) ((P) + (-(unsigned long)(P) & (A)))
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -83,6 +83,25 @@ do_test (void)
|
||||
|
||||
free (p);
|
||||
|
||||
/* Check as above with larger size increase. */
|
||||
p = malloc (34);
|
||||
if (p == NULL)
|
||||
FAIL_EXIT1 ("malloc (34) failed.");
|
||||
memset (p, 'a', 34);
|
||||
p = realloc (p, 80000);
|
||||
if (p == NULL)
|
||||
FAIL_EXIT1 ("realloc (p, 80000) failed.");
|
||||
c = p;
|
||||
ok = 1;
|
||||
for (i = 0; i < 34; i++)
|
||||
{
|
||||
if (c[i] != 'a')
|
||||
ok = 0;
|
||||
}
|
||||
if (ok == 0)
|
||||
FAIL_EXIT1 ("first 34 bytes were not preserved");
|
||||
free (p);
|
||||
|
||||
p = realloc (NULL, 100);
|
||||
if (p == NULL)
|
||||
FAIL_EXIT1 ("realloc (NULL, 100) failed.");
|
||||
|
||||
@@ -155,21 +155,13 @@ do_test (void)
|
||||
struct scratch_buffer buf;
|
||||
scratch_buffer_init (&buf);
|
||||
memset (buf.data, '@', buf.length);
|
||||
|
||||
size_t sizes[] = { 16, buf.length, buf.length + 16 };
|
||||
for (int i = 0; i < array_length (sizes); i++)
|
||||
{
|
||||
/* The extra size is unitialized through realloc. */
|
||||
size_t l = sizes[i] > buf.length ? sizes[i] : buf.length;
|
||||
void *r = scratch_buffer_dupfree (&buf, l);
|
||||
void *c = xmalloc (l);
|
||||
memset (c, '@', l);
|
||||
TEST_COMPARE_BLOB (r, l, buf.data, l);
|
||||
free (r);
|
||||
free (c);
|
||||
}
|
||||
|
||||
scratch_buffer_free (&buf);
|
||||
size_t l = 16 <= buf.length ? 16 : buf.length;
|
||||
void *r = scratch_buffer_dupfree (&buf, l);
|
||||
void *c = xmalloc (l);
|
||||
memset (c, '@', l);
|
||||
TEST_COMPARE_BLOB (r, l, c, l);
|
||||
free (r);
|
||||
free (c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
Morello glibc port
|
||||
==================
|
||||
|
||||
Morello is a prototype security architecture, led by Arm, based on CHERI.
|
||||
https://www.morello-project.org/
|
||||
https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
|
||||
|
||||
Toolchain components of the morello port are maintained in upstream branches.
|
||||
The morello port is implemented as an ABI variant of the aarch64 port that is
|
||||
also called the purecap ABI. Morello specific ABI documents are at:
|
||||
https://github.com/ARM-software/abi-aa
|
||||
https://git.morello-project.org/morello/kernel/linux/-/wikis/home
|
||||
|
||||
Areas with significant morello or CHERI specific changes outside the usual
|
||||
target specific changes:
|
||||
|
||||
- Early start code including ELF entry and auxv,
|
||||
- Dynamic linker and relocation processing,
|
||||
- malloc with narrow capability support,
|
||||
- printf %#p to pretty print capabilities.
|
||||
|
||||
Limitations of the morello port:
|
||||
|
||||
- Building requires --disable-werror.
|
||||
- Profiling and --enable-profile are not supported (gprof, sprof, LD_PROFILE).
|
||||
- LD_AUDIT is not supported (la_symbind, PLT hooks, require new API redesign).
|
||||
- VDSO is not supported (depends on Linux work).
|
||||
- static-pie is not supported (requires start code redesign).
|
||||
- POSIX message queue async notify does not work (pointers passed via an fd).
|
||||
- Process shared robust mutex does not work (pointers in shared memory).
|
||||
- Purecap pldd only supports purecap ABI processes (not lp64).
|
||||
- malloc bounds narrowing has large overhead (locks and hash table lookup).
|
||||
- malloc bounds narrowing can break code expecting page granularity protection.
|
||||
Use GLIBC_TUNABLES=glibc.mem.cap_narrowing=0 env var as a workaround.
|
||||
- string functions are not optimized.
|
||||
- Executable stack is not supported.
|
||||
- Internal pointer protection and pointer mangling are disabled.
|
||||
@@ -612,3 +612,9 @@ support in the kernel if this tunable has any non-zero value.
|
||||
|
||||
The default value is @samp{0}, which disables all memory tagging.
|
||||
@end deftp
|
||||
|
||||
@deftp Tunable glibc.mem.cap_narrowing
|
||||
On CHERI architecture use capability bounds narrowing in the malloc
|
||||
implementation. By default it is set to 1, to disable bounds narrowing
|
||||
set it to 0.
|
||||
@end deftp
|
||||
|
||||
@@ -164,6 +164,9 @@ libc {
|
||||
GLIBC_2.32 {
|
||||
__libc_single_threaded;
|
||||
}
|
||||
GLIBC_2.37 {
|
||||
__getauxptr; getauxptr;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
__madvise;
|
||||
__mktemp;
|
||||
|
||||
@@ -20,6 +20,39 @@
|
||||
#include <ldsodefs.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void *
|
||||
__getauxptr (unsigned long int type)
|
||||
{
|
||||
/* error if asking for a non-pointer from getauxptr(). This list is not a
|
||||
perfect enforcement as it currently supports both transitional and draft
|
||||
ABIs, which have different capability entries. */
|
||||
switch (type) {
|
||||
case AT_ENTRY:
|
||||
case AT_PHDR:
|
||||
case AT_BASE:
|
||||
case AT_SYSINFO_EHDR:
|
||||
case AT_EXECFN:
|
||||
case AT_RANDOM:
|
||||
case AT_PLATFORM:
|
||||
case AT_CHERI_EXEC_RW_CAP:
|
||||
case AT_CHERI_EXEC_RX_CAP:
|
||||
case AT_CHERI_INTERP_RW_CAP:
|
||||
case AT_CHERI_INTERP_RX_CAP:
|
||||
case AT_CHERI_SEAL_CAP:
|
||||
{
|
||||
ElfW(auxv_t) *p;
|
||||
for (p = GLRO(dl_auxv); p->a_type != AT_NULL; p++)
|
||||
if (p->a_type == type)
|
||||
return (void *) p->a_un.a_val;
|
||||
}
|
||||
}
|
||||
|
||||
__set_errno (ENOENT);
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__getauxptr, getauxptr)
|
||||
libc_hidden_def (__getauxptr)
|
||||
|
||||
bool
|
||||
__getauxval2 (unsigned long int type, unsigned long int *result)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,10 @@ __BEGIN_DECLS
|
||||
extern unsigned long int getauxval (unsigned long int __type)
|
||||
__THROW;
|
||||
|
||||
/* Same as getauxval, but for Arm Morello capabilities. */
|
||||
extern void * getauxptr (unsigned long int __type)
|
||||
__THROW;
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* sys/auxv.h */
|
||||
|
||||
+12
-8
@@ -167,7 +167,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
||||
_nl_C_locobj_ptr);
|
||||
|
||||
#define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \
|
||||
"<%d>%s %n%s%s%.0d%s: ", \
|
||||
"<%d>%s%n%s%s%.0d%s: ", \
|
||||
__pri, __timestamp, __msgoff, \
|
||||
LogTag == NULL ? __progname : LogTag, \
|
||||
"[" + (pid == 0), pid, "]" + (pid == 0)
|
||||
@@ -193,28 +193,32 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
||||
int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
|
||||
mode_flags);
|
||||
if (0 <= vl && vl < sizeof bufs - l)
|
||||
{
|
||||
buf = bufs;
|
||||
bufsize = l + vl;
|
||||
}
|
||||
buf = bufs;
|
||||
bufsize = l + vl;
|
||||
|
||||
va_end (apc);
|
||||
}
|
||||
|
||||
if (buf == NULL)
|
||||
{
|
||||
buf = malloc (l * sizeof (char));
|
||||
buf = malloc ((bufsize + 1) * sizeof (char));
|
||||
if (buf != NULL)
|
||||
{
|
||||
/* Tell the cancellation handler to free this buffer. */
|
||||
clarg.buf = buf;
|
||||
|
||||
if (has_ts)
|
||||
__snprintf (bufs, sizeof bufs,
|
||||
__snprintf (buf, l + 1,
|
||||
SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
|
||||
else
|
||||
__snprintf (bufs, sizeof bufs,
|
||||
__snprintf (buf, l + 1,
|
||||
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
||||
|
||||
va_list apc;
|
||||
va_copy (apc, ap);
|
||||
__vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
|
||||
mode_flags);
|
||||
va_end (apc);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+4
-4
@@ -131,15 +131,15 @@ typedef struct node_t
|
||||
uintptr_t right_node;
|
||||
} *node;
|
||||
|
||||
#define RED(N) (node)((N)->left_node & ((uintptr_t) 0x1))
|
||||
#define RED(N) (unsigned int)((N)->left_node & ((uintptr_t) 0x1))
|
||||
#define SETRED(N) (N)->left_node |= ((uintptr_t) 0x1)
|
||||
#define SETBLACK(N) (N)->left_node &= ~((uintptr_t) 0x1)
|
||||
#define SETNODEPTR(NP,P) (*NP) = (node)((((uintptr_t)(*NP)) \
|
||||
#define SETNODEPTR(NP,P) (*NP) = (node)((unsigned int)(((uintptr_t)(*NP)) \
|
||||
& (uintptr_t) 0x1) | (uintptr_t)(P))
|
||||
#define LEFT(N) (node)((N)->left_node & ~((uintptr_t) 0x1))
|
||||
#define LEFTPTR(N) (node *)(&(N)->left_node)
|
||||
#define SETLEFT(N,L) (N)->left_node = (((N)->left_node & (uintptr_t) 0x1) \
|
||||
| (uintptr_t)(L))
|
||||
#define SETLEFT(N,L) (N)->left_node = ((unsigned int)((N)->left_node \
|
||||
& (uintptr_t) 0x1) | (uintptr_t)(L))
|
||||
#define RIGHT(N) (node)((N)->right_node)
|
||||
#define RIGHTPTR(N) (node *)(&(N)->right_node)
|
||||
#define SETRIGHT(N,R) (N)->right_node = (uintptr_t)(R)
|
||||
|
||||
+135
-22
@@ -68,21 +68,19 @@ static const int priorities[] =
|
||||
LOG_DEBUG
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ident_length = 64,
|
||||
msg_length = 64
|
||||
};
|
||||
#define IDENT_LENGTH 64
|
||||
#define MSG_LENGTH 1024
|
||||
|
||||
#define SYSLOG_MSG_BASE "syslog_message"
|
||||
#define OPENLOG_IDENT "openlog_ident"
|
||||
static char large_message[MSG_LENGTH];
|
||||
|
||||
struct msg_t
|
||||
{
|
||||
int priority;
|
||||
int facility;
|
||||
char ident[ident_length];
|
||||
char msg[msg_length];
|
||||
char ident[IDENT_LENGTH];
|
||||
char msg[MSG_LENGTH];
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
@@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
send_syslog_large (int options)
|
||||
{
|
||||
int facility = LOG_USER;
|
||||
int priority = LOG_INFO;
|
||||
|
||||
syslog (facility | priority, "%s %d %d", large_message, facility,
|
||||
priority);
|
||||
}
|
||||
|
||||
static void
|
||||
send_vsyslog_large (int options)
|
||||
{
|
||||
int facility = LOG_USER;
|
||||
int priority = LOG_INFO;
|
||||
|
||||
call_vsyslog (facility | priority, "%s %d %d", large_message, facility,
|
||||
priority);
|
||||
}
|
||||
|
||||
static bool
|
||||
check_syslog_message_large (const struct msg_t *msg, int msgnum, int options,
|
||||
pid_t pid)
|
||||
{
|
||||
TEST_COMPARE (msg->facility, LOG_USER);
|
||||
TEST_COMPARE (msg->priority, LOG_INFO);
|
||||
TEST_COMPARE_STRING (msg->msg, large_message);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
send_openlog (int options)
|
||||
{
|
||||
@@ -179,6 +208,17 @@ send_openlog (int options)
|
||||
closelog ();
|
||||
}
|
||||
|
||||
static void
|
||||
send_openlog_large (int options)
|
||||
{
|
||||
/* Define a non-default IDENT and a not default facility. */
|
||||
openlog (OPENLOG_IDENT, options, LOG_LOCAL0);
|
||||
|
||||
syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO);
|
||||
|
||||
closelog ();
|
||||
}
|
||||
|
||||
static bool
|
||||
check_openlog_message (const struct msg_t *msg, int msgnum,
|
||||
int options, pid_t pid)
|
||||
@@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
|
||||
int expected_priority = priorities[msgnum % array_length (priorities)];
|
||||
TEST_COMPARE (msg->priority, expected_priority);
|
||||
|
||||
char expected_ident[ident_length];
|
||||
char expected_ident[IDENT_LENGTH];
|
||||
snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
|
||||
OPENLOG_IDENT,
|
||||
options & LOG_PID ? "[" : "",
|
||||
@@ -211,17 +251,43 @@ check_openlog_message (const struct msg_t *msg, int msgnum,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_openlog_message_large (const struct msg_t *msg, int msgnum,
|
||||
int options, pid_t pid)
|
||||
{
|
||||
char expected_ident[IDENT_LENGTH];
|
||||
snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:",
|
||||
OPENLOG_IDENT,
|
||||
options & LOG_PID ? "[" : "",
|
||||
options & LOG_PID ? pid : 0,
|
||||
options & LOG_PID ? "]" : "");
|
||||
|
||||
TEST_COMPARE_STRING (msg->ident, expected_ident);
|
||||
TEST_COMPARE_STRING (msg->msg, large_message);
|
||||
TEST_COMPARE (msg->priority, LOG_INFO);
|
||||
TEST_COMPARE (msg->facility, LOG_LOCAL0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct msg_t
|
||||
parse_syslog_msg (const char *msg)
|
||||
{
|
||||
struct msg_t r = { .pid = -1 };
|
||||
int number;
|
||||
int wsb, wsa;
|
||||
|
||||
#define STRINPUT(size) XSTRINPUT(size)
|
||||
#define XSTRINPUT(size) "%" # size "s"
|
||||
|
||||
/* The message in the form:
|
||||
<179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */
|
||||
int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d",
|
||||
&number, r.ident, r.msg);
|
||||
<179>Apr 8 14:51:19 tst-syslog: message 176 3 */
|
||||
int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH)
|
||||
" " STRINPUT(MSG_LENGTH) " %*d %*d",
|
||||
&number, &wsb, &wsa, r.ident, r.msg);
|
||||
TEST_COMPARE (n, 3);
|
||||
/* It should only one space between timestamp and message. */
|
||||
TEST_COMPARE (wsa - wsb, 1);
|
||||
|
||||
r.facility = number & LOG_FACMASK;
|
||||
r.priority = number & LOG_PRIMASK;
|
||||
@@ -246,7 +312,7 @@ parse_syslog_console (const char *msg)
|
||||
|
||||
/* The message in the form:
|
||||
openlog_ident: syslog_message 128 0 */
|
||||
int n = sscanf (msg, "%32s %64s %d %d",
|
||||
int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d",
|
||||
r.ident, r.msg, &facility, &priority);
|
||||
TEST_COMPARE (n, 4);
|
||||
|
||||
@@ -281,7 +347,7 @@ check_syslog_udp (void (*syslog_send)(int), int options,
|
||||
int msgnum = 0;
|
||||
while (1)
|
||||
{
|
||||
char buf[512];
|
||||
char buf[2048];
|
||||
size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0,
|
||||
(struct sockaddr *) &addr, &addrlen);
|
||||
buf[l] = '\0';
|
||||
@@ -325,7 +391,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options,
|
||||
|
||||
int client_tcp = xaccept (server_tcp, NULL, NULL);
|
||||
|
||||
char buf[512], *rb = buf;
|
||||
char buf[2048], *rb = buf;
|
||||
size_t rbl = sizeof (buf);
|
||||
size_t prl = 0; /* Track the size of the partial record. */
|
||||
int msgnum = 0;
|
||||
@@ -393,20 +459,34 @@ check_syslog_console_read (FILE *fp)
|
||||
}
|
||||
|
||||
static void
|
||||
check_syslog_console (void)
|
||||
check_syslog_console_read_large (FILE *fp)
|
||||
{
|
||||
char buf[2048];
|
||||
TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL);
|
||||
struct msg_t msg = parse_syslog_console (buf);
|
||||
|
||||
TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":");
|
||||
TEST_COMPARE_STRING (msg.msg, large_message);
|
||||
TEST_COMPARE (msg.priority, LOG_INFO);
|
||||
TEST_COMPARE (msg.facility, LOG_LOCAL0);
|
||||
}
|
||||
|
||||
static void
|
||||
check_syslog_console (void (*syslog_send)(int),
|
||||
void (*syslog_check)(FILE *fp))
|
||||
{
|
||||
xmkfifo (_PATH_CONSOLE, 0666);
|
||||
|
||||
pid_t sender_pid = xfork ();
|
||||
if (sender_pid == 0)
|
||||
{
|
||||
send_openlog (LOG_CONS);
|
||||
syslog_send (LOG_CONS);
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
{
|
||||
FILE *fp = xfopen (_PATH_CONSOLE, "r+");
|
||||
check_syslog_console_read (fp);
|
||||
syslog_check (fp);
|
||||
xfclose (fp);
|
||||
}
|
||||
|
||||
@@ -425,16 +505,28 @@ send_openlog_callback (void *clousure)
|
||||
}
|
||||
|
||||
static void
|
||||
check_syslog_perror (void)
|
||||
send_openlog_callback_large (void *clousure)
|
||||
{
|
||||
int options = *(int *) clousure;
|
||||
send_openlog_large (options);
|
||||
}
|
||||
|
||||
static void
|
||||
check_syslog_perror (bool large)
|
||||
{
|
||||
struct support_capture_subprocess result;
|
||||
result = support_capture_subprocess (send_openlog_callback,
|
||||
result = support_capture_subprocess (large
|
||||
? send_openlog_callback_large
|
||||
: send_openlog_callback,
|
||||
&(int){LOG_PERROR});
|
||||
|
||||
FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r");
|
||||
if (mfp == NULL)
|
||||
FAIL_EXIT1 ("fmemopen: %m");
|
||||
check_syslog_console_read (mfp);
|
||||
if (large)
|
||||
check_syslog_console_read_large (mfp);
|
||||
else
|
||||
check_syslog_console_read (mfp);
|
||||
xfclose (mfp);
|
||||
|
||||
support_capture_subprocess_check (&result, "tst-openlog-child", 0,
|
||||
@@ -462,10 +554,31 @@ do_test (void)
|
||||
check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message);
|
||||
|
||||
/* Check the LOG_CONS option. */
|
||||
check_syslog_console ();
|
||||
check_syslog_console (send_openlog, check_syslog_console_read);
|
||||
|
||||
/* Check the LOG_PERROR option. */
|
||||
check_syslog_perror ();
|
||||
check_syslog_perror (false);
|
||||
|
||||
/* Similar tests as before, but with a large message to trigger the
|
||||
syslog path that uses dynamically allocated memory. */
|
||||
memset (large_message, 'a', sizeof large_message - 1);
|
||||
large_message[sizeof large_message - 1] = '\0';
|
||||
|
||||
check_syslog_udp (send_syslog_large, 0, check_syslog_message_large);
|
||||
check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large);
|
||||
|
||||
check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large);
|
||||
check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large);
|
||||
|
||||
check_syslog_udp (send_openlog_large, 0, check_openlog_message_large);
|
||||
check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large);
|
||||
|
||||
check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large);
|
||||
check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large);
|
||||
|
||||
check_syslog_console (send_openlog_large, check_syslog_console_read_large);
|
||||
|
||||
check_syslog_perror (true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,13 @@
|
||||
# define MAP_STACK 0
|
||||
#endif
|
||||
|
||||
/* On CHERI targets ensure the mmap returned capability has RW permissions. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RW PROT_MAX (PROT_READ | PROT_WRITE)
|
||||
#else
|
||||
# define PROT_MAX_RW 0
|
||||
#endif
|
||||
|
||||
/* Get a stack frame from the cache. We have to match by size since
|
||||
some blocks might be too small or far too large. */
|
||||
static struct pthread *
|
||||
@@ -363,7 +370,8 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
||||
/* If a guard page is required, avoid committing memory by first
|
||||
allocate with PROT_NONE and then reserve with required permission
|
||||
excluding the guard page. */
|
||||
mem = __mmap (NULL, size, (guardsize == 0) ? prot : PROT_NONE,
|
||||
mem = __mmap (NULL, size,
|
||||
(guardsize == 0) ? prot : PROT_NONE | PROT_MAX_RW,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
|
||||
|
||||
if (__glibc_unlikely (mem == MAP_FAILED))
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#include <limits.h>
|
||||
#include "pthreadP.h"
|
||||
#include <shlib-compat.h>
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
# include <cheri_perms.h>
|
||||
#endif
|
||||
|
||||
#ifndef NEW_VERNUM
|
||||
# define NEW_VERNUM GLIBC_2_3_3
|
||||
@@ -43,6 +45,11 @@ __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
|
||||
EXTRA_PARAM_CHECKS;
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (!STACK_CAP_CHECK (stackaddr, stacksize))
|
||||
return EINVAL;
|
||||
#endif
|
||||
|
||||
iattr->stacksize = stacksize;
|
||||
#if _STACK_GROWS_DOWN
|
||||
iattr->stackaddr = (char *) stackaddr + stacksize;
|
||||
|
||||
+2
-3
@@ -110,11 +110,10 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||||
"gethostbyname4_r");
|
||||
if (fct4 != NULL)
|
||||
{
|
||||
struct gaih_addrtuple atmem;
|
||||
struct gaih_addrtuple *at;
|
||||
while (1)
|
||||
{
|
||||
at = &atmem;
|
||||
at = NULL;
|
||||
rc6 = 0;
|
||||
herrno = 0;
|
||||
status[1] = DL_CALL_FCT (fct4, (key, &at,
|
||||
@@ -137,7 +136,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
|
||||
goto next_nip;
|
||||
|
||||
/* We found the data. Count the addresses and the size. */
|
||||
for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL;
|
||||
for (const struct gaih_addrtuple *at2 = at; at2 != NULL;
|
||||
at2 = at2->next)
|
||||
{
|
||||
++naddrs;
|
||||
|
||||
+2
-1
@@ -2284,7 +2284,8 @@ main_loop_epoll (int efd)
|
||||
sizeof (buf))) != -1)
|
||||
;
|
||||
|
||||
__bump_nl_timestamp ();
|
||||
dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]
|
||||
= __bump_nl_timestamp ();
|
||||
}
|
||||
# endif
|
||||
else
|
||||
|
||||
+10
-1
@@ -58,6 +58,8 @@ static const struct argp_option args_options[] =
|
||||
{
|
||||
{ "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") },
|
||||
{ "no-idn", 'i', NULL, 0, N_("disable IDN encoding") },
|
||||
{ "no-addrconfig", 'A', NULL, 0,
|
||||
N_("do not filter out unsupported IPv4/IPv6 addresses (with ahosts*)") },
|
||||
{ NULL, 0, NULL, 0, NULL },
|
||||
};
|
||||
|
||||
@@ -79,6 +81,9 @@ static struct argp argp =
|
||||
/* Additional getaddrinfo flags for IDN encoding. */
|
||||
static int idn_flags = AI_IDN | AI_CANONIDN;
|
||||
|
||||
/* Set to 0 by --no-addrconfig. */
|
||||
static int addrconfig_flags = AI_ADDRCONFIG;
|
||||
|
||||
/* Print the version information. */
|
||||
static void
|
||||
print_version (FILE *stream, struct argp_state *state)
|
||||
@@ -346,7 +351,7 @@ ahosts_keys_int (int af, int xflags, int number, char *key[])
|
||||
|
||||
struct addrinfo hint;
|
||||
memset (&hint, '\0', sizeof (hint));
|
||||
hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME
|
||||
hint.ai_flags = (AI_V4MAPPED | addrconfig_flags | AI_CANONNAME
|
||||
| idn_flags | xflags);
|
||||
hint.ai_family = af;
|
||||
|
||||
@@ -905,6 +910,10 @@ parse_option (int key, char *arg, struct argp_state *state)
|
||||
idn_flags = 0;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
addrconfig_flags = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -28,14 +28,15 @@ do_test (void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Run getent to fetch the IPv4 address for host test4.
|
||||
This forces /etc/hosts to be parsed. */
|
||||
ret = system("getent ahostsv4 test4");
|
||||
/* Run getent to fetch the IPv4 address for host test4. This forces
|
||||
/etc/hosts to be parsed. Use --no-addrconfig to return addresses
|
||||
even in an IPv6-only environment. */
|
||||
ret = system("getent --no-addrconfig ahostsv4 test4");
|
||||
if (ret != 0)
|
||||
FAIL_EXIT1("ahostsv4 failed");
|
||||
|
||||
/* Likewise for IPv6. */
|
||||
ret = system("getent ahostsv6 test6");
|
||||
ret = system("getent --no-addrconfig ahostsv6 test6");
|
||||
if (ret != 0)
|
||||
FAIL_EXIT1("ahostsv6 failed");
|
||||
|
||||
|
||||
+4
-4
@@ -43,12 +43,12 @@ static struct passwd pwd_table_1[] = {
|
||||
|
||||
static const char *hostaddr_5[] =
|
||||
{
|
||||
"ABCD", "abcd", "1234", NULL
|
||||
"ABCd", "ABCD", "ABC4", NULL
|
||||
};
|
||||
|
||||
static const char *hostaddr_15[] =
|
||||
{
|
||||
"4321", "ghij", NULL
|
||||
"4321", "4322", NULL
|
||||
};
|
||||
|
||||
static const char *hostaddr_25[] =
|
||||
@@ -86,12 +86,12 @@ static const char *hostaddr_6[] =
|
||||
|
||||
static const char *hostaddr_16[] =
|
||||
{
|
||||
"7890", "a1b2", NULL
|
||||
"7890", "7891", NULL
|
||||
};
|
||||
|
||||
static const char *hostaddr_26[] =
|
||||
{
|
||||
"qwer", "tyui", NULL
|
||||
"qwer", "qweR", NULL
|
||||
};
|
||||
|
||||
static struct hostent host_table_2[] = {
|
||||
|
||||
@@ -204,7 +204,11 @@ typedef __off64_t __loff_t; /* Type of file sizes and offsets (LFS). */
|
||||
typedef char *__caddr_t;
|
||||
|
||||
/* Duplicates info from stdint.h but this is used in unistd.h. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
__STD_TYPE __intcap_t __intptr_t;
|
||||
#else
|
||||
__STD_TYPE __SWORD_TYPE __intptr_t;
|
||||
#endif
|
||||
|
||||
/* Duplicate info from sys/socket.h. */
|
||||
__STD_TYPE __U32_TYPE __socklen_t;
|
||||
|
||||
@@ -40,12 +40,16 @@ routines := \
|
||||
inet_pton \
|
||||
ns_makecanon \
|
||||
ns_name_compress \
|
||||
ns_name_length_uncompressed \
|
||||
ns_name_ntop \
|
||||
ns_name_pack \
|
||||
ns_name_pton \
|
||||
ns_name_skip \
|
||||
ns_name_uncompress \
|
||||
ns_name_unpack \
|
||||
ns_rr_cursor_init \
|
||||
ns_rr_cursor_next \
|
||||
ns_samebinaryname \
|
||||
ns_samename \
|
||||
nsap_addr \
|
||||
nss_dns_functions \
|
||||
@@ -89,9 +93,12 @@ tests += \
|
||||
tst-ns_name_pton \
|
||||
tst-res_hconf_reorder \
|
||||
tst-res_hnok \
|
||||
tst-resolv-aliases \
|
||||
tst-resolv-basic \
|
||||
tst-resolv-binary \
|
||||
tst-resolv-byaddr \
|
||||
tst-resolv-edns \
|
||||
tst-resolv-invalid-cname \
|
||||
tst-resolv-network \
|
||||
tst-resolv-noaaaa \
|
||||
tst-resolv-nondecimal \
|
||||
@@ -104,6 +111,18 @@ tests += \
|
||||
tests-internal += tst-resolv-txnid-collision
|
||||
tests-static += tst-resolv-txnid-collision
|
||||
|
||||
# Likewise for __ns_samebinaryname.
|
||||
tests-internal += tst-ns_samebinaryname
|
||||
tests-static += tst-ns_samebinaryname
|
||||
|
||||
# Likewise for __ns_name_length_uncompressed.
|
||||
tests-internal += tst-ns_name_length_uncompressed
|
||||
tests-static += tst-ns_name_length_uncompressed
|
||||
|
||||
# Likewise for struct ns_rr_cursor and its functions.
|
||||
tests-internal += tst-ns_rr_cursor
|
||||
tests-static += tst-ns_rr_cursor
|
||||
|
||||
# These tests need libdl.
|
||||
ifeq (yes,$(build-shared))
|
||||
tests += \
|
||||
@@ -258,8 +277,10 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales)
|
||||
$(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales)
|
||||
$(objpfx)tst-resolv-ai_idn-nolibidn2.out: \
|
||||
$(gen-locales) $(objpfx)tst-no-libidn2.so
|
||||
$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so
|
||||
@@ -267,6 +288,8 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
$(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
|
||||
@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c.
|
||||
|
||||
res_hconf.c and res_hconf.h were contributed by David Mosberger, and
|
||||
do not come from BIND.
|
||||
|
||||
The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are
|
||||
leftovers from BIND 4.9.7.
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* ++Copyright++ 1985, 1988, 1993
|
||||
* -
|
||||
* Copyright (c) 1985, 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
static void
|
||||
map_v4v6_address (const char *src, char *dst)
|
||||
{
|
||||
u_char *p = (u_char *) dst;
|
||||
int i;
|
||||
|
||||
/* Move the IPv4 part to the right position. */
|
||||
memcpy (dst + 12, src, INADDRSZ);
|
||||
|
||||
/* Mark this ipv6 addr as a mapped ipv4. */
|
||||
for (i = 0; i < 10; i++)
|
||||
*p++ = 0x00;
|
||||
*p++ = 0xff;
|
||||
*p = 0xff;
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* ++Copyright++ 1985, 1988, 1993
|
||||
* -
|
||||
* Copyright (c) 1985, 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
#include <arpa/nameser.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
typedef union {
|
||||
int32_t al;
|
||||
char ac;
|
||||
} align;
|
||||
|
||||
static int
|
||||
map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp)
|
||||
{
|
||||
char **ap;
|
||||
|
||||
if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
|
||||
return 0;
|
||||
hp->h_addrtype = AF_INET6;
|
||||
hp->h_length = IN6ADDRSZ;
|
||||
for (ap = hp->h_addr_list; *ap; ap++)
|
||||
{
|
||||
int i = sizeof (align) - ((u_long) *bpp % sizeof (align));
|
||||
|
||||
if (*lenp < (i + IN6ADDRSZ))
|
||||
/* Out of memory. */
|
||||
return 1;
|
||||
*bpp += i;
|
||||
*lenp -= i;
|
||||
map_v4v6_address (*ap, *bpp);
|
||||
*ap = *bpp;
|
||||
*bpp += IN6ADDRSZ;
|
||||
*lenp -= IN6ADDRSZ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Skip over an uncompressed name in wire format.
|
||||
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 <arpa/nameser.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int
|
||||
__ns_name_length_uncompressed (const unsigned char *p,
|
||||
const unsigned char *eom)
|
||||
{
|
||||
const unsigned char *start = p;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (p == eom)
|
||||
{
|
||||
/* Truncated packet: no room for label length. */
|
||||
__set_errno (EMSGSIZE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char b = *p;
|
||||
++p;
|
||||
if (b == 0)
|
||||
{
|
||||
/* Root label. */
|
||||
size_t length = p - start;
|
||||
if (length > NS_MAXCDNAME)
|
||||
{
|
||||
/* Domain name too long. */
|
||||
__set_errno (EMSGSIZE);
|
||||
return -1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
if (b <= 63)
|
||||
{
|
||||
/* Regular label. */
|
||||
if (b <= eom - p)
|
||||
p += b;
|
||||
else
|
||||
{
|
||||
/* Truncated packet: label incomplete. */
|
||||
__set_errno (EMSGSIZE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Compression reference or corrupted label length. */
|
||||
__set_errno (EMSGSIZE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Initialize a simple DNS packet parser.
|
||||
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 <arpa/nameser.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
bool
|
||||
__ns_rr_cursor_init (struct ns_rr_cursor *c,
|
||||
const unsigned char *buf, size_t len)
|
||||
{
|
||||
c->begin = buf;
|
||||
c->end = buf + len;
|
||||
|
||||
/* Check for header size and 16-bit question count value (it must be 1). */
|
||||
if (len < 12 || buf[4] != 0 || buf[5] != 1)
|
||||
{
|
||||
__set_errno (EMSGSIZE);
|
||||
c->current = c->end;
|
||||
return false;
|
||||
}
|
||||
c->current = buf + 12;
|
||||
|
||||
int consumed = __ns_name_length_uncompressed (c->current, c->end);
|
||||
if (consumed < 0)
|
||||
{
|
||||
__set_errno (EMSGSIZE);
|
||||
c->current = c->end;
|
||||
c->first_rr = NULL;
|
||||
return false;
|
||||
}
|
||||
c->current += consumed;
|
||||
|
||||
/* Ensure there is room for question type and class. */
|
||||
if (c->end - c->current < 4)
|
||||
{
|
||||
__set_errno (EMSGSIZE);
|
||||
c->current = c->end;
|
||||
c->first_rr = NULL;
|
||||
return false;
|
||||
}
|
||||
c->current += 4;
|
||||
c->first_rr = c->current;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Simple DNS record parser without textual name decoding.
|
||||
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 <arpa/nameser.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
bool
|
||||
__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr)
|
||||
{
|
||||
rr->rdata = NULL;
|
||||
|
||||
/* Extract the record owner name. */
|
||||
int consumed = __ns_name_unpack (c->begin, c->end, c->current,
|
||||
rr->rname, sizeof (rr->rname));
|
||||
if (consumed < 0)
|
||||
{
|
||||
memset (rr, 0, sizeof (*rr));
|
||||
__set_errno (EMSGSIZE);
|
||||
return false;
|
||||
}
|
||||
c->current += consumed;
|
||||
|
||||
/* Extract the metadata. */
|
||||
struct
|
||||
{
|
||||
uint16_t rtype;
|
||||
uint16_t rclass;
|
||||
uint32_t ttl;
|
||||
uint16_t rdlength;
|
||||
} __attribute__ ((packed)) metadata;
|
||||
_Static_assert (sizeof (metadata) == 10, "sizeof metadata");
|
||||
if (c->end - c->current < sizeof (metadata))
|
||||
{
|
||||
memset (rr, 0, sizeof (*rr));
|
||||
__set_errno (EMSGSIZE);
|
||||
return false;
|
||||
}
|
||||
memcpy (&metadata, c->current, sizeof (metadata));
|
||||
c->current += sizeof (metadata);
|
||||
/* Endianess conversion. */
|
||||
rr->rtype = ntohs (metadata.rtype);
|
||||
rr->rclass = ntohs (metadata.rclass);
|
||||
rr->ttl = ntohl (metadata.ttl);
|
||||
rr->rdlength = ntohs (metadata.rdlength);
|
||||
|
||||
/* Extract record data. */
|
||||
if (c->end - c->current < rr->rdlength)
|
||||
{
|
||||
memset (rr, 0, sizeof (*rr));
|
||||
__set_errno (EMSGSIZE);
|
||||
return false;
|
||||
}
|
||||
rr->rdata = c->current;
|
||||
c->current += rr->rdlength;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/* Compare two binary domain names for quality.
|
||||
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 <arpa/nameser.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Convert ASCII letters to upper case. */
|
||||
static inline int
|
||||
ascii_toupper (unsigned char ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'z')
|
||||
return ch - 'a' + 'A';
|
||||
else
|
||||
return ch;
|
||||
}
|
||||
|
||||
bool
|
||||
__ns_samebinaryname (const unsigned char *a, const unsigned char *b)
|
||||
{
|
||||
while (*a != 0 && *b != 0)
|
||||
{
|
||||
if (*a != *b)
|
||||
/* Different label length. */
|
||||
return false;
|
||||
int labellen = *a;
|
||||
++a;
|
||||
++b;
|
||||
for (int i = 0; i < labellen; ++i)
|
||||
{
|
||||
if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b))
|
||||
/* Different character in label. */
|
||||
return false;
|
||||
++a;
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
/* Match if both names are at the root label. */
|
||||
return *a == 0 && *b == 0;
|
||||
}
|
||||
+471
-729
File diff suppressed because it is too large
Load Diff
@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn)
|
||||
return dn[0] > 0 && dn[1] == '-';
|
||||
}
|
||||
|
||||
bool
|
||||
__res_binary_hnok (const unsigned char *dn)
|
||||
{
|
||||
return !binary_leading_dash (dn) && binary_hnok (dn);
|
||||
}
|
||||
|
||||
/* Return 1 if res_hnok is a valid host name. Labels must only
|
||||
contain [0-9a-zA-Z_-] characters, and the name must not start with
|
||||
a '-'. The latter is to avoid confusion with program options. */
|
||||
@@ -145,11 +151,9 @@ int
|
||||
___res_hnok (const char *dn)
|
||||
{
|
||||
unsigned char buf[NS_MAXCDNAME];
|
||||
if (!printable_string (dn)
|
||||
|| __ns_name_pton (dn, buf, sizeof (buf)) < 0
|
||||
|| binary_leading_dash (buf))
|
||||
return 0;
|
||||
return binary_hnok (buf);
|
||||
return (printable_string (dn)
|
||||
&& __ns_name_pton (dn, buf, sizeof (buf)) >= 0
|
||||
&& __res_binary_hnok (buf));
|
||||
}
|
||||
versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34);
|
||||
versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE);
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/* Test __ns_name_length_uncompressed.
|
||||
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 <arpa/nameser.h>
|
||||
#include <array_length.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <support/check.h>
|
||||
#include <support/next_to_fault.h>
|
||||
|
||||
/* Reference implementation based on other building blocks. */
|
||||
static int
|
||||
reference_length (const unsigned char *p, const unsigned char *eom)
|
||||
{
|
||||
unsigned char buf[NS_MAXCDNAME];
|
||||
int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf));
|
||||
if (n < 0)
|
||||
return n;
|
||||
const unsigned char *q = buf;
|
||||
if (__ns_name_skip (&q, array_end (buf)) < 0)
|
||||
return -1;
|
||||
if (q - buf != n)
|
||||
/* Compressed name. */
|
||||
return -1;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
{
|
||||
unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 };
|
||||
TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2);
|
||||
TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)),
|
||||
sizeof (buf) - 2);
|
||||
TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1);
|
||||
TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1,
|
||||
array_end (buf)), 1);
|
||||
buf[4] = 0xc0; /* Forward compression reference. */
|
||||
buf[5] = 0x06;
|
||||
TEST_COMPARE (reference_length (buf, array_end (buf)), -1);
|
||||
TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1);
|
||||
}
|
||||
|
||||
struct support_next_to_fault ntf = support_next_to_fault_allocate (300);
|
||||
|
||||
/* Buffer region with all possible bytes at start and end. */
|
||||
for (int length = 1; length <= 300; ++length)
|
||||
{
|
||||
unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
|
||||
unsigned char *start = end - length;
|
||||
memset (start, 'X', length);
|
||||
for (int first = 0; first <= 255; ++first)
|
||||
{
|
||||
*start = first;
|
||||
for (int last = 0; last <= 255; ++last)
|
||||
{
|
||||
start[length - 1] = last;
|
||||
TEST_COMPARE (reference_length (start, end),
|
||||
__ns_name_length_uncompressed (start, end));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Poor man's fuzz testing: patch two bytes. */
|
||||
{
|
||||
unsigned char ref[] =
|
||||
{
|
||||
7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0
|
||||
};
|
||||
TEST_COMPARE (reference_length (ref, array_end (ref)), 13);
|
||||
TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13);
|
||||
|
||||
int good = 0;
|
||||
int bad = 0;
|
||||
for (int length = 1; length <= sizeof (ref); ++length)
|
||||
{
|
||||
unsigned char *end = (unsigned char *) ntf.buffer + ntf.length;
|
||||
unsigned char *start = end - length;
|
||||
memcpy (start, ref, length);
|
||||
|
||||
for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos)
|
||||
{
|
||||
for (int patch1_value = 0; patch1_value <= 255; ++patch1_value)
|
||||
{
|
||||
start[patch1_pos] = patch1_value;
|
||||
for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos)
|
||||
{
|
||||
for (int patch2_value = 0; patch2_value <= 255;
|
||||
++patch2_value)
|
||||
{
|
||||
start[patch2_pos] = patch2_value;
|
||||
int expected = reference_length (start, end);
|
||||
errno = EINVAL;
|
||||
int actual
|
||||
= __ns_name_length_uncompressed (start, end);
|
||||
if (actual > 0)
|
||||
++good;
|
||||
else
|
||||
{
|
||||
TEST_COMPARE (errno, EMSGSIZE);
|
||||
++bad;
|
||||
}
|
||||
TEST_COMPARE (expected, actual);
|
||||
}
|
||||
start[patch2_pos] = ref[patch2_pos];
|
||||
}
|
||||
}
|
||||
start[patch1_pos] = ref[patch1_pos];
|
||||
}
|
||||
}
|
||||
printf ("info: patched inputs with success: %d\n", good);
|
||||
printf ("info: patched inputs with failure: %d\n", bad);
|
||||
}
|
||||
|
||||
support_next_to_fault_free (&ntf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
@@ -0,0 +1,227 @@
|
||||
/* Tests for resource record parsing.
|
||||
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 <arpa/nameser.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/next_to_fault.h>
|
||||
|
||||
/* Reference packet for packet parsing. */
|
||||
static const unsigned char valid_packet[] =
|
||||
{ 0x11, 0x12, 0x13, 0x14,
|
||||
0x00, 0x01, /* Question count. */
|
||||
0x00, 0x02, /* Answer count. */
|
||||
0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */
|
||||
3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0,
|
||||
0x00, 0x1c, /* Question type: AAAA. */
|
||||
0x00, 0x01, /* Question class: IN. */
|
||||
0xc0, 0x0c, /* Compression reference to QNAME. */
|
||||
0x00, 0x1c, /* Record type: AAAA. */
|
||||
0x00, 0x01, /* Record class: IN. */
|
||||
0x12, 0x34, 0x56, 0x78, /* Record TTL. */
|
||||
0x00, 0x10, /* Record data length (16 bytes). */
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */
|
||||
0xc0, 0x0c, /* Compression reference to QNAME. */
|
||||
0x00, 0x1c, /* Record type: AAAA. */
|
||||
0x00, 0x01, /* Record class: IN. */
|
||||
0x11, 0x33, 0x55, 0x77, /* Record TTL. */
|
||||
0x00, 0x10, /* Record data length (16 bytes). */
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */
|
||||
};
|
||||
|
||||
/* Special offsets in valid_packet. */
|
||||
enum
|
||||
{
|
||||
offset_of_first_record = 29,
|
||||
offset_of_second_record = 57,
|
||||
};
|
||||
|
||||
/* Check that parsing valid_packet succeeds. */
|
||||
static void
|
||||
test_valid (void)
|
||||
{
|
||||
struct ns_rr_cursor c;
|
||||
TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet,
|
||||
sizeof (valid_packet)));
|
||||
TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
|
||||
TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
|
||||
TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
|
||||
TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
|
||||
TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
|
||||
TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
|
||||
TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
|
||||
TEST_COMPARE (c.current - valid_packet, offset_of_first_record);
|
||||
|
||||
struct ns_rr_wire r;
|
||||
TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
|
||||
TEST_COMPARE (r.rtype, T_AAAA);
|
||||
TEST_COMPARE (r.rclass, C_IN);
|
||||
TEST_COMPARE (r.ttl, 0x12345678);
|
||||
TEST_COMPARE_BLOB (r.rdata, r.rdlength,
|
||||
"\x90\x91\x92\x93\x94\x95\x96\x97"
|
||||
"\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
|
||||
TEST_COMPARE (c.current - valid_packet, offset_of_second_record);
|
||||
TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
|
||||
TEST_COMPARE (r.rtype, T_AAAA);
|
||||
TEST_COMPARE (r.rclass, C_IN);
|
||||
TEST_COMPARE (r.ttl, 0x11335577);
|
||||
TEST_COMPARE_BLOB (r.rdata, r.rdlength,
|
||||
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
|
||||
"\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16);
|
||||
TEST_VERIFY (c.current == c.end);
|
||||
}
|
||||
|
||||
/* Check that trying to parse a packet with a compressed QNAME fails. */
|
||||
static void
|
||||
test_compressed_qname (void)
|
||||
{
|
||||
static const unsigned char packet[] =
|
||||
{ 0x11, 0x12, 0x13, 0x14,
|
||||
0x00, 0x01, /* Question count. */
|
||||
0x00, 0x00, /* Answer count. */
|
||||
0x00, 0x00, 0x00, 0x00, /* Other counts. */
|
||||
3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
|
||||
0x00, 0x01, /* Question type: A. */
|
||||
0x00, 0x01, /* Question class: IN. */
|
||||
};
|
||||
|
||||
struct ns_rr_cursor c;
|
||||
TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
|
||||
}
|
||||
|
||||
/* Check that trying to parse a packet with two questions fails. */
|
||||
static void
|
||||
test_two_questions (void)
|
||||
{
|
||||
static const unsigned char packet[] =
|
||||
{ 0x11, 0x12, 0x13, 0x14,
|
||||
0x00, 0x02, /* Question count. */
|
||||
0x00, 0x00, /* Answer count. */
|
||||
0x00, 0x00, 0x00, 0x00, /* Other counts. */
|
||||
3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
|
||||
0x00, 0x01, /* Question type: A. */
|
||||
0x00, 0x01, /* Question class: IN. */
|
||||
3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04,
|
||||
0x00, 0x1c, /* Question type: AAAA. */
|
||||
0x00, 0x01, /* Question class: IN. */
|
||||
};
|
||||
|
||||
struct ns_rr_cursor c;
|
||||
TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet)));
|
||||
}
|
||||
|
||||
/* Used to check that parsing truncated packets does not over-read. */
|
||||
static struct support_next_to_fault ntf;
|
||||
|
||||
/* Truncated packet in the second resource record. */
|
||||
static void
|
||||
test_truncated_one_rr (size_t length)
|
||||
{
|
||||
unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
|
||||
unsigned char *start = end - length;
|
||||
|
||||
/* Produce the truncated packet. */
|
||||
memcpy (start, valid_packet, length);
|
||||
|
||||
struct ns_rr_cursor c;
|
||||
TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
|
||||
TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
|
||||
TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
|
||||
TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
|
||||
TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
|
||||
TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
|
||||
TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
|
||||
TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
|
||||
TEST_COMPARE (c.current - start, offset_of_first_record);
|
||||
|
||||
struct ns_rr_wire r;
|
||||
TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r));
|
||||
TEST_COMPARE (r.rtype, T_AAAA);
|
||||
TEST_COMPARE (r.rclass, C_IN);
|
||||
TEST_COMPARE (r.ttl, 0x12345678);
|
||||
TEST_COMPARE_BLOB (r.rdata, r.rdlength,
|
||||
"\x90\x91\x92\x93\x94\x95\x96\x97"
|
||||
"\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16);
|
||||
TEST_COMPARE (c.current - start, offset_of_second_record);
|
||||
TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
|
||||
}
|
||||
|
||||
/* Truncated packet in the first resource record. */
|
||||
static void
|
||||
test_truncated_no_rr (size_t length)
|
||||
{
|
||||
unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
|
||||
unsigned char *start = end - length;
|
||||
|
||||
/* Produce the truncated packet. */
|
||||
memcpy (start, valid_packet, length);
|
||||
|
||||
struct ns_rr_cursor c;
|
||||
TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length));
|
||||
TEST_COMPARE (ns_rr_cursor_rcode (&c), 4);
|
||||
TEST_COMPARE (ns_rr_cursor_ancount (&c), 2);
|
||||
TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122);
|
||||
TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324);
|
||||
TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13);
|
||||
TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA);
|
||||
TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN);
|
||||
TEST_COMPARE (c.current - start, offset_of_first_record);
|
||||
|
||||
struct ns_rr_wire r;
|
||||
TEST_VERIFY (!__ns_rr_cursor_next (&c, &r));
|
||||
}
|
||||
|
||||
/* Truncated packet before first resource record. */
|
||||
static void
|
||||
test_truncated_before_rr (size_t length)
|
||||
{
|
||||
unsigned char *end = (unsigned char *) ntf.buffer - ntf.length;
|
||||
unsigned char *start = end - length;
|
||||
|
||||
/* Produce the truncated packet. */
|
||||
memcpy (start, valid_packet, length);
|
||||
|
||||
struct ns_rr_cursor c;
|
||||
TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length));
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
ntf = support_next_to_fault_allocate (sizeof (valid_packet));
|
||||
|
||||
test_valid ();
|
||||
test_compressed_qname ();
|
||||
test_two_questions ();
|
||||
|
||||
for (int length = offset_of_second_record; length < sizeof (valid_packet);
|
||||
++length)
|
||||
test_truncated_one_rr (length);
|
||||
for (int length = offset_of_first_record; length < offset_of_second_record;
|
||||
++length)
|
||||
test_truncated_no_rr (length);
|
||||
for (int length = 0; length < offset_of_first_record; ++length)
|
||||
test_truncated_before_rr (length);
|
||||
|
||||
support_next_to_fault_free (&ntf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user