Hi, Could someone please take a look at my errors below and see if this
is a uclibc problem? I'm struggling to understand.
System is gentoo/hardened/uclibc-ng. Using gcc-9.3.0, uclibc-1.0.33 in a
chroot on x86-64
Using dhcpcd-8+, ie observe the same on 9.x and various 8.x versions.
Specifically testing dhcpcd-8.1.9 in this case.
Error on compilation looks like:
In file included from /usr/include/sys/stat.h:106,
from /usr/include/fcntl.h:37,
from if.c:58:
/usr/include/bits/stat.h:102:22: error: expected identifier or '('
before '[' token
102 | long int __unused[3];
| ^
If I comment out the "#include <fcntl.h>" in if.c, then it compiles
without error.
Also, if I convert the definition from the form "__unused[3]" to
separate lines like "long int __unused1", etc, then it also compiles
without error.
I'm not clear why an array definition in a struct is triggering this
compiler error? Any thoughts? Is this something that dhcpcd is doing wrong?
Thanks for any help. Full log below
Ed W
# ./configure
configure args:
Deriving operating system from ... x86_64-unknown-linux
Configuring dhcpcd for ... linux
Enabling INET support
Enabling ARP support
Enabling ARPing support
Enabling IPv4LL support
Enabling INET6 support
Enabling DHCPv6 support
Enabling Authentication
Using compiler .. cc
cc (Gentoo Hardened 9.3.0 p2) 9.3.0
dhcpcd-definitions.conf will be embedded in dhcpcd itself
Testing for nl80211 ... yes
Testing for IN6_ADDR_GEN_MODE_NONE ... yes
Testing for getifaddrs ... yes
Testing for ifaddrs.ifa_addrflags ... no
Testing for clock_gettime ... yes
Testing for inet_ntoa ... yes
Testing for arc4random ... no
Testing for arc4random_uniform ... no
Testing for open_memstream ... yes
Testing for pidfile_lock ... no
Testing for setproctitle ... no
Testing for strlcpy ... yes
Testing for strtoi ... no
Testing for consttime_memequal ... no
Testing for dprintf ... yes
Testing for TAILQ_FOREACH_SAFE ... no
Testing for TAILQ_FOREACH_MUTABLE ... no
Testing for TAILQ_CONCAT ...yes
Testing for rb_tree_init ... no
Testing for reallocarray ... no
Testing for kqueue1 ... no
Testing for kqueue ... no
Testing for epoll ... yes
Testing for be64enc ... no
Testing for fls64 ... no
Testing for MD5Init ... no
Testing for sha2.h ... no
Testing for SHA256_Init ... no
Testing for SHA256Init ... no
Testing for hmac ... no
Checking for libudev ... yes
Checking udev_monitor_filter_add_match_subsystem_devtype ... yes
Checking udev_device_get_is_initialized ... yes
Testing for dlopen ... yes
Checking for ntpd ... /usr/sbin/ntpd (50-ntp.conf)
Checking for chronyd ... not found
Checking for ypbind ... not found
SYSCONFDIR = /etc
SBINDIR = /sbin
LIBDIR = /lib
LIBEXECDIR = /libexec
DBDIR = /var/db/dhcpcd
RUNDIR = /var/run
MANDIR = /usr/share/man
DATADIR = /usr/share
HOOKSCRIPTS = 50-ntp.conf
EGHOOKSCRIPTS =
STATUSARG =
chroot:twocubed dhcpcd-8.1.9 # make
for x in src hooks; do cd $x; make all || exit $?; cd ..; done
make[1]: Entering directory
'/var/tmp/portage/net-misc/dhcpcd-8.1.9/work/dhcpcd-8.1.9/src'
cc -O2 -std=c99 -DHAVE_CONFIG_H -DNDEBUG -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DINET
-DARP -DARPING -DIPV4LL -DINET6 -DDHCP6 -DAUTH -DPLUGIN_DEV -I..
-I../src -I./crypt -c common.c -o common.o
cc -O2 -std=c99 -DHAVE_CONFIG_H -DNDEBUG -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DINET
-DARP -DARPING -DIPV4LL -DINET6 -DDHCP6 -DAUTH -DPLUGIN_DEV -I..
-I../src -I./crypt -c control.c -o control.o
cc -O2 -std=c99 -DHAVE_CONFIG_H -DNDEBUG -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DINET
-DARP -DARPING -DIPV4LL -DINET6 -DDHCP6 -DAUTH -DPLUGIN_DEV -I..
-I../src -I./crypt -c dhcpcd.c -o dhcpcd.o
cc -O2 -std=c99 -DHAVE_CONFIG_H -DNDEBUG -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DINET
-DARP -DARPING -DIPV4LL -DINET6 -DDHCP6 -DAUTH -DPLUGIN_DEV -I..
-I../src -I./crypt -c duid.c -o duid.o
cc -O2 -std=c99 -DHAVE_CONFIG_H -DNDEBUG -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DINET
-DARP -DARPING -DIPV4LL -DINET6 -DDHCP6 -DAUTH -DPLUGIN_DEV -I..
-I../src -I./crypt -c eloop.c -o eloop.o
cc -O2 -std=c99 -DHAVE_CONFIG_H -DNDEBUG -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DINET
-DARP -DARPING -DIPV4LL -DINET6 -DDHCP6 -DAUTH -DPLUGIN_DEV -I..
-I../src -I./crypt -c logerr.c -o logerr.o
cc -O2 -std=c99 -DHAVE_CONFIG_H -DNDEBUG -D_GNU_SOURCE
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -DINET
-DARP -DARPING -DIPV4LL -DINET6 -DDHCP6 -DAUTH -DPLUGIN_DEV -I..
-I../src -I./crypt -c if.c -o if.o
In file included from /usr/include/sys/stat.h:106,
from /usr/include/fcntl.h:37,
from if.c:58:
/usr/include/bits/stat.h:102:22: error: expected identifier or '('
before '[' token
102 | long int __unused[3];
| ^
/usr/include/bits/stat.h:163:22: error: expected identifier or '('
before '[' token
163 | long int __unused[3];
| ^
make[1]: *** [Makefile:55: if.o] Error 1
make[1]: Leaving directory
'/var/tmp/portage/net-misc/dhcpcd-8.1.9/work/dhcpcd-8.1.9/src'
make: *** [Makefile:24: all] Error 2
In Nov 2019, I was unable to compile openbsd-netcat on a
uclibc-ng-1.0.32 based system. Note: /I don't really write C and I
don't know what I'm doing/ but the following patch allowed me to compile
openbsd-netcat and run it. I just pulled the bit from glibc (mostly
verbatim iirc) and added corresponding config parameter. Hopefully it
will be useful even if incompetent.
I've been using openbsd-netcat with uclibc-ng 1.0.32 and 1.0.33 from
2019-11 to 2020-06 (now) on regular basis, and openbsd-netcat seems to
work fine.
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -329,9 +329,12 @@
#endif
__END_DECLS
-#if 0
+
+#ifdef __UCLIBC_HAS_BSD_B64_NTOP_B64_PTON__
#define b64_ntop __b64_ntop
#define b64_pton __b64_pton
+#endif
+#if 0
#define dn_count_labels __dn_count_labels
#endif
#define dn_comp __dn_comp
@@ -384,8 +387,12 @@
int sym_ston (const struct res_sym *, const char *, int *) __THROW;
const char * sym_ntos (const struct res_sym *, int, int *) __THROW;
const char * sym_ntop (const struct res_sym *, int, int *) __THROW;
+#endif
+#ifdef __UCLIBC_HAS_BSD_B64_NTOP_B64_PTON__
int b64_ntop (u_char const *, size_t, char *, size_t) __THROW;
int b64_pton (char const *, u_char *, size_t) __THROW;
+#endif
+#if 0
int loc_aton (const char *ascii, u_char *binary) __THROW;
const char * loc_ntoa (const u_char *binary, char *ascii) __THROW;
void putlong (u_int32_t, u_char *) __THROW;
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -1036,6 +1036,14 @@
If unsure, say N.
+config UCLIBC_HAS_BSD_B64_NTOP_B64_PTON
+ bool "Support b64_ntop(), b64_pton() (bsd-compat)"
+ help
+ Answer Y if you need additional BSD compatibility
+ (e.g. for openbsd-netcat).
+
+ Most people will say N.
+
config UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL
bool "SYSV obsolete signal functions"
help
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -3632,6 +3632,263 @@
}
#endif
+#ifdef __UCLIBC_HAS_BSD_B64_NTOP_B64_PTON__
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+/* libc_hidden_def (b64_ntop) */
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton (char const *src, u_char *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
+#endif
+
/* This needs to be after the use of _res in res_init, above. */
#undef _res
We've been using uclibc 0.9.33.2 for yonks, and until now didn't have
any real reason to upgrade. However, we've run into a problem where
calls to pthread_cond_broadcast() sometimes take an extraordinarily
long time.
On a 400MHz ARM926, a call to pthread_cond_broadcast() usually takes
under 200us. However, occasionally it takes _far_ longer (up to
several tens of milliseconds). The caller is running with real-time
priority at a level higher than all other threads. The condition
variable is in shared RAM and the waiting threads (3-4 of them) are in
different processes. The long delays happen about 1 out of 100,000
calls. If you want to see the actual distribution of elapsed times
for the pthread_cond_broadcast() call, the elapsed time distribution
from one test run is at the bottom of this email.
Is this due to some fundamental design decision in the pthreads
implimentation? If so, is it still that way in uClibc-ng? Or is it a
bug that's likely been fixed?
Or is it actually a kernel issue? The kernel version is 2.6.33.7 with
PREEMPT patches.
Re-writing the code so that the "waiting" threads just poll a shared
counter which is incremented by the broadcaster eliminates the delay
problem but has other drawbacks.
ms occurances
------ ----------
0.000 3088767
0.122 8641750
0.244 1751
0.366 989
0.488 374
0.610 770
0.732 476
0.854 120
0.977 38
1.099 16
1.221 4
1.343 9
1.465 3
1.587 5
1.709 4
1.831 6
1.953 4
2.075 4
2.197 6
2.319 6
2.441 2
2.686 4
2.808 9
2.930 11
3.052 10
3.174 5
3.296 5
3.418 1
3.540 3
3.662 47
3.784 48
3.906 22
4.028 11
4.150 6
4.272 4
4.395 2
4.639 3
4.761 2
4.883 3
5.005 1
5.127 2
5.249 2
5.615 1
5.859 1
5.981 1
6.104 1
6.470 1
6.958 1
7.080 1
7.202 2
7.324 1
7.568 1
7.690 11
7.813 4
8.057 1
8.179 2
8.301 1
8.911 1
9.033 1
11.230 1
11.475 1
11.719 2
11.841 1
11.963 1
12.085 1
12.207 1
12.329 1
13.184 1
13.794 1
15.625 2
Hi,
the panfrost driver in next release of mesa3d version 20.1.0 needs fromfp
code from glibc:
https://cgit.freedesktop.org/mesa/mesa/commit/?
id=9f50b19534a2a534a5cc509516211656f84f2f08
https://sourceware.org/git/?
p=glibc.git;a=commit;h=423c2b9d086a880199fcb46cc7b6672c13885eed
Please consider porting the glibc code to uClibc-ng.
Thanks!
Regards, Bernd
akater <nuclearspace(a)gmail.com> writes:
> --- a/libc/sysdeps/linux/ia64/bits/stat.h
> +++ b/libc/sysdeps/linux/ia64/bits/stat.h
This was misleading, sorry. dhcpcd compiled successfully after I
applied the patch to /usr/include/bits/stat.h --- not to the source.
I did not try to restart dhcpcd since either. Just reporting that it
did build in these conditions.
This patch serie allow TLS tests to really run some TLS testing
instead of just doing "return 0;".
Some defines were missing since the split between libc and tests
repositories.
It also adds some missing tls macros for or1k and ppc64.
Some dead code is removed from 3 tests, it was accessing
private/internal data structures from libc which is no longer
possible since repository split.
TLS tests have been run only on OpenRISC using qemu.
This has been compiled for x86_64, or1k, powerpc, ppc64, mips32r6,
sparc, armv7a.
Yann Sionneau (4):
or1k: add missing tls macros
powerpc64: add missing tls macros
powerpc: update tls macros inline asm clobbers
tls: make tls tests great again
test/tls/Makefile.in | 6 +++
test/tls/tls-macros-or1k.h | 75 ++++++++++++++++++++++++++
test/tls/tls-macros-powerpc.h | 2 +-
test/tls/tls-macros-powerpc64.h | 43 +++++++++++++++
test/tls/tls-macros.h | 10 +++-
test/tls/tst-tls6.c | 25 ---------
test/tls/tst-tls7.c | 25 ---------
test/tls/tst-tls8.c | 95 ---------------------------------
8 files changed, 134 insertions(+), 147 deletions(-)
create mode 100644 test/tls/tls-macros-or1k.h
create mode 100644 test/tls/tls-macros-powerpc64.h
--
2.17.1
Safe-Linking alignment checks should be done on the user's buffer and not
the mchunkptr. The new check adds support for cases in which:
MALLOC_ALIGNMENT != 2*(sizeof(size_t))
The default case for both 32 bits and 64 bits was already supported, and
this patch adds support for the described irregular case.
Safe-Linking is a security mechanism that protects single-linked
lists (such as the fastbins) from being tampered by attackers. The
mechanism makes use of randomness from ASLR (mmap_base), and when
combined with chunk alignment integrity checks, it protects the
pointers from being hijacked by an attacker.
While Safe-Unlinking protects double-linked lists (such as the small
bins), there wasn't any similar protection for attacks against
single-linked lists. This solution protects against 3 common attacks:
* Partial pointer override: modifies the lower bytes (Little Endian)
* Full pointer override: hijacks the pointer to an attacker's location
* Unaligned chunks: pointing the list to an unaligned address
The design assumes an attacker doesn't know where the heap is located,
and uses the ASLR randomness to "sign" the single-linked pointers. We
mark the pointer as P and the location in which it is stored as L, and
the calculation will be:
* PROTECT(P) := (L >> PAGE_SHIFT) XOR (P)
* *L = PROTECT(P)
This way, the random bits from the address L (which start at the bits
in the PAGE_SHIFT position), will be merged with the LSB of the stored
protected pointer. This protection layer prevents an attacker from
modifying the pointer into a controlled value.
An additional check that the chunks are MALLOC_ALIGNed adds an
important layer:
* Attackers can't point to illegal (unaligned) memory addresses
* Attackers must guess correctly the alignment bits
On standard 32 bit Linux machines, an attacker will directly fail 7
out of 8 times, and on 64 bit machines it will fail 15 out of 16
times.
The proposed solution adds 3-4 asm instructions per malloc()/free()
and therefore has only minor performance implications if it has
any. A similar protection was added to Chromium's version of TCMalloc
in 2013, and according to their documentation the performance overhead
was less than 2%.
For more information, feel free to check out our White Paper which can be
found here:
https://github.com/gperftools/gperftools/files/4023520/Safe-Linking-White-P…
---
libc/stdlib/malloc-standard/free.c | 5 +++--
libc/stdlib/malloc-standard/mallinfo.c | 3 ++-
libc/stdlib/malloc-standard/malloc.c | 6 ++++--
libc/stdlib/malloc-standard/malloc.h | 12 ++++++++++++
4 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/libc/stdlib/malloc-standard/free.c
b/libc/stdlib/malloc-standard/free.c
index a2d765d41..f3602cf48 100644
--- a/libc/stdlib/malloc-standard/free.c
+++ b/libc/stdlib/malloc-standard/free.c
@@ -214,8 +214,9 @@ void attribute_hidden __malloc_consolidate(mstate av)
*fb = 0;
do {
+ CHECK_PTR(p);
check_inuse_chunk(p);
- nextp = p->fd;
+ nextp = REVEAL_PTR(&p->fd, p->fd);
/* Slightly streamlined version of consolidation code in free() */
size = p->size & ~PREV_INUSE;
@@ -308,7 +309,7 @@ void free(void* mem)
set_fastchunks(av);
fb = &(av->fastbins[fastbin_index(size)]);
- p->fd = *fb;
+ p->fd = PROTECT_PTR(&p->fd, *fb);
*fb = p;
}
diff --git a/libc/stdlib/malloc-standard/mallinfo.c
b/libc/stdlib/malloc-standard/mallinfo.c
index dbe4d49b8..992322341 100644
--- a/libc/stdlib/malloc-standard/mallinfo.c
+++ b/libc/stdlib/malloc-standard/mallinfo.c
@@ -49,7 +49,8 @@ struct mallinfo mallinfo(void)
fastavail = 0;
for (i = 0; i < NFASTBINS; ++i) {
- for (p = av->fastbins[i]; p != 0; p = p->fd) {
+ for (p = av->fastbins[i]; p != 0; p = REVEAL_PTR(&p->fd, p->fd)) {
+ CHECK_PTR(p);
++nfastblocks;
fastavail += chunksize(p);
}
diff --git a/libc/stdlib/malloc-standard/malloc.c
b/libc/stdlib/malloc-standard/malloc.c
index 1a6d4dc1c..1f898eb29 100644
--- a/libc/stdlib/malloc-standard/malloc.c
+++ b/libc/stdlib/malloc-standard/malloc.c
@@ -260,12 +260,13 @@ void __do_check_malloc_state(void)
assert(p == 0);
while (p != 0) {
+ CHECK_PTR(p);
/* each chunk claims to be inuse */
__do_check_inuse_chunk(p);
total += chunksize(p);
/* chunk belongs in this bin */
assert(fastbin_index(chunksize(p)) == i);
- p = p->fd;
+ p = REVEAL_PTR(&p->fd, p->fd);
}
}
@@ -855,7 +856,8 @@ void* malloc(size_t bytes)
if ((unsigned long)(nb) <= (unsigned long)(av->max_fast)) {
fb = &(av->fastbins[(fastbin_index(nb))]);
if ( (victim = *fb) != 0) {
- *fb = victim->fd;
+ CHECK_PTR(victim);
+ *fb = REVEAL_PTR(&victim->fd, victim->fd);
check_remalloced_chunk(victim, nb);
retval = chunk2mem(victim);
goto DONE;
diff --git a/libc/stdlib/malloc-standard/malloc.h
b/libc/stdlib/malloc-standard/malloc.h
index 44120d388..30a696e5a 100644
--- a/libc/stdlib/malloc-standard/malloc.h
+++ b/libc/stdlib/malloc-standard/malloc.h
@@ -839,6 +839,18 @@ typedef struct malloc_chunk* mfastbinptr;
#define get_max_fast(M) \
((M)->max_fast & ~(FASTCHUNKS_BIT | ANYCHUNKS_BIT))
+/*
+ Safe-Linking:
+ Use randomness from ASLR (mmap_base) to protect single-linked lists
+ of fastbins. Together with allocation alignment checks, this mechanism
+ reduces the risk of pointer hijacking, as was done with Safe-Unlinking
+ in the double-linked lists of smallbins.
+*/
+#define PROTECT_PTR(pos, ptr) ((mchunkptr)((((size_t)pos) >>
PAGE_SHIFT) ^ ((size_t)ptr)))
+#define REVEAL_PTR(pos, ptr) PROTECT_PTR(pos, ptr)
+#define CHECK_PTR(P) \
+ if (!aligned_OK(P)) \
+ abort();
/*
morecore_properties is a status word holding dynamically discovered
--
2.17.1