summaryrefslogtreecommitdiff
path: root/libc/inet/resolv.c
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2008-01-09 05:49:44 +0000
committerMike Frysinger <vapier@gentoo.org>2008-01-09 05:49:44 +0000
commite0523d622cdf5b96575ce025221ec2533a6b4454 (patch)
tree8a708bf35f651121317735ddb3f1c3c9fbeecb09 /libc/inet/resolv.c
parent6c05ed96f646e20a8ef104d36d260fab30486768 (diff)
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.
Diffstat (limited to 'libc/inet/resolv.c')
-rw-r--r--libc/inet/resolv.c26
1 files changed, 26 insertions, 0 deletions
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;