Bug 4381 - unaligned memory access in gethostbyname_r()
Summary: unaligned memory access in gethostbyname_r()
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-04-16 21:48 UTC by Aurelien Jarno
Modified: 2014-07-10 20:32 UTC (History)
1 user (show)

See Also:
Host: sparc-unknown-linux-gnu
Target: sparc-unknown-linux-gnu
Build: sparc-unknown-linux-gnu
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Aurelien Jarno 2007-04-16 21:48:52 UTC
The third argument of gethostbyname_r() is supposed to be a buffer of type char 
*buf, with no particular memory alignment.

This buffer is then casted into a (struct host_data *). This causes a SIGBUS on 
architecture that does not support unaligned memory access.

As it is not possible to change the API, please find a small patch below, which 
align the buffer before using it. The drawback of this method is that the 
buffer may be a bit smaller.


--- resolv/nss_dns/dns-host.c.orig      2007-04-16 00:13:12.000000000 +0200
+++ resolv/nss_dns/dns-host.c   2007-04-16 00:34:41.000000000 +0200
@@ -78,6 +78,7 @@
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
+#include <obstack.h>
 #include <sys/syslog.h>

 #include "nsswitch.h"
@@ -465,8 +466,8 @@
     char *aliases[MAX_NR_ALIASES];
     unsigned char host_addr[16];       /* IPv4 or IPv6 */
     char *h_addr_ptrs[0];
-  } *host_data = (struct host_data *) buffer;
-  int linebuflen = buflen - sizeof (struct host_data);
+  } *host_data;
+  int linebuflen;
   register const HEADER *hp;
   const u_char *end_of_message, *cp;
   int n, ancount, qdcount;
@@ -479,6 +480,10 @@
   int have_to_map = 0;
   int32_t ttl = 0;

+  /* Align the buffer. */
+  host_data = (struct host_data *) __PTR_ALIGN(0, buffer, sizeof(char*) - 1);
+  linebuflen = buflen - sizeof (struct host_data) - ((char *)host_data - 
buffer);
+
   if (__builtin_expect (linebuflen, 0) < 0)
     {
       /* The buffer is too small.  */
Comment 1 Ulrich Drepper 2007-04-24 18:40:52 UTC
Fixed in cvs.
Comment 2 cvs-commit@gcc.gnu.org 2007-07-12 15:10:54 UTC
Subject: Bug 4381

CVSROOT:	/cvs/glibc
Module name:	libc
Branch: 	glibc-2_5-branch
Changes by:	jakub@sourceware.org	2007-07-12 15:10:44

Modified files:
	.              : ChangeLog 
	nis/nss_nis    : nis-hosts.c 
	nss/nss_files  : files-hosts.c 
	resolv/nss_dns : dns-host.c dns-network.c 

Log message:
	2007-04-23  Jakub Jelinek  <jakub@redhat.com>
	
	[BZ #4381]
	* nss/nss_files/files-hosts.c (HOST_DB_LOOKUP): Ensure sufficient
	alignment of buffer and tmp_buffer.
	* nis/nss_nis/nis-hosts.c (internal_nis_gethostent_r,
	internal_gethostbyname2_r, _nss_nis_gethostbyaddr_r): Ensure sufficient
	alignment of buffer.
	* resolv/nss_dns/dns-hosts.c (getanswer_r): Likewise.  Handle buflen
	bigger than INT_MAX.
	* resolv/nss_dns/dns-network.c (getanswer_r): Likewise.  Add errnop and
	h_errnop arguments.  Fail if buflen is too small.
	(_nss_dns_getnetbyname_r, _nss_dns_getnetbyaddr_r): Adjust callers.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/libc/ChangeLog.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=1.10362.2.69&r2=1.10362.2.70
http://sourceware.org/cgi-bin/cvsweb.cgi/libc/nis/nss_nis/nis-hosts.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=1.26&r2=1.26.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/libc/nss/nss_files/files-hosts.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=1.23&r2=1.23.8.1
http://sourceware.org/cgi-bin/cvsweb.cgi/libc/resolv/nss_dns/dns-host.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=1.43&r2=1.43.4.1
http://sourceware.org/cgi-bin/cvsweb.cgi/libc/resolv/nss_dns/dns-network.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=1.21&r2=1.21.2.1