From e0523d622cdf5b96575ce025221ec2533a6b4454 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 9 Jan 2008 05:49:44 +0000 Subject: Daniel Jacobowitz writes: MontaVista noticed that when their kernels were configured to trap on unaligned access gethostbyname_r could mysteriously crash. I tracked this down to an unaligned buffer being passed to gethostbyname_r from some other part of uClibc (afraid I don't remember where from any more). We have to pad the beginning of the buffer to a pointer alignment before we store pointers in it. --- libc/inet/resolv.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'libc/inet') diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index 7f9d7d536..591106a24 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -234,6 +234,14 @@ libc_hidden_proto(__ctype_b) #define DPRINTF(X,args...) #endif /* DEBUG */ +/* Make sure the incoming char * buffer is aligned enough to handle our random + * structures. This define is the same as we use for malloc alignment (which + * has same requirements). The offset is the number of bytes we need to adjust + * in order to attain desired alignment. + */ +#define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t))) +#define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR) + /* Global stuff (stuff needing to be locked to be thread safe)... */ extern int __nameservers attribute_hidden; @@ -1534,6 +1542,15 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type, char *cp, **alias; int aliases, i, ret = HOST_NOT_FOUND; + /* make sure user char * is aligned */ + i = ALIGN_BUFFER_OFFSET(buf); + if (unlikely(i)) { + if (buflen < i) + return ERANGE; + buf += i; + buflen -= i; + } + if (buflen < sizeof(char *)*(ALIAS_DIM)) return ERANGE; alias = (char **)buf; @@ -2029,6 +2046,15 @@ int gethostbyname_r(const char * name, DPRINTF("Nothing found in /etc/hosts\n"); + /* make sure user char * is aligned */ + i = ALIGN_BUFFER_OFFSET(buf); + if (unlikely(i)) { + if (buflen < i) + return ERANGE; + buf += i; + buflen -= i; + } + *h_errnop = NETDB_INTERNAL; if (buflen < sizeof(*in)) return ERANGE; -- cgit v1.2.3