about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--elf/dl-sysdep.c3
-rw-r--r--elf/dl-tls.c1
-rw-r--r--elf/rtld.c5
-rw-r--r--sysdeps/generic/ldsodefs.h3
-rw-r--r--sysdeps/unix/sysv/linux/dl-osinfo.h97
-rw-r--r--sysdeps/unix/sysv/linux/dl-sysdep.c98
-rw-r--r--sysdeps/unix/sysv/linux/dl-sysdep.h11
-rw-r--r--sysdeps/unix/sysv/linux/sysconf.c20
9 files changed, 148 insertions, 102 deletions
diff --git a/ChangeLog b/ChangeLog
index 7a6db2d8ac..b3746f9797 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2008-03-07  Ulrich Drepper  <drepper@redhat.com>
 
+	[BZ #5786]
+	* elf/dl-sysdep.c: Undefine ROUND after use.
+	* sysdeps/generic/ldsodefs.h [HAVE_DL_DISCOVER_OSVERSION]
+	(struct rtld_global_ro): Add _dl_tls_get_addr_soft element.
+	* elf/rtld.c (rtld_global_ro): Initialize _dl_discover_osversion.
+	* sysdeps/unix/sysv/linux/dl-osinfo.h: Move _dl_discover_osversion
+	to ...
+	* sysdeps/unix/sysv/linux/dl-sysdep.c: ...here.
+	* sysdeps/unix/sysv/linux/dl-sysdep.h: Declare _dl_discover_osversion
+	if necessary.
+	* sysdeps/unix/sysv/linux/sysconf.c: Handle _SC_ARG_MAX here.
+
 	* sysdeps/generic/ldsodefs.h (struct rtld_global_ro): Add
 	_dl_tls_get_addr_soft element.
 	* elf/rtld.c (rtld_global_ro): Initialize _dl_tls_get_addr_soft.
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index 85e331a90f..dd55905e14 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -1,5 +1,5 @@
 /* Operating system support for run-time dynamic linker.  Generic Unix version.
-   Copyright (C) 1995-1998, 2000-2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2007, 2008 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
@@ -398,6 +398,7 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
 		  }
 		note = ((const void *) (note + 1)
 			+ ROUND (note->vendorlen) + ROUND (note->datalen));
+#undef ROUND
 	      }
 	    if (dsocaps != NULL)
 	      break;
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index deed47249f..76a3f25c0f 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -758,7 +758,6 @@ __tls_get_addr (GET_ADDR_ARGS)
 /* Look up the module's TLS block as for __tls_get_addr,
    but never touch anything.  Return null if it's not allocated yet.  */
 void *
-attribute_hidden
 _dl_tls_get_addr_soft (struct link_map *l)
 {
   if (__builtin_expect (l->l_tls_modid == 0, 0))
diff --git a/elf/rtld.c b/elf/rtld.c
index 9497e5d43f..46bece7fa3 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -162,7 +162,10 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
     ._dl_check_caller = _dl_check_caller,
     ._dl_open = _dl_open,
     ._dl_close = _dl_close,
-    ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft
+    ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
+#ifdef HAVE_DL_DISCOVER_OSVERSION
+    ._dl_discover_osversion = _dl_discover_osversion
+#endif
   };
 /* If we would use strong_alias here the compiler would see a
    non-hidden definition.  This would undo the effect of the previous
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 580e1e3953..9d1ebdf615 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -656,6 +656,9 @@ struct rtld_global_ro
 		     Lmid_t nsid, int argc, char *argv[], char *env[]);
   void (*_dl_close) (void *map);
   void *(*_dl_tls_get_addr_soft) (struct link_map *);
+#ifdef HAVE_DL_DISCOVER_OSVERSION
+  int (*_dl_discover_osversion) (void);
+#endif
 
   /* List of auditing interfaces.  */
   struct audit_ifaces *_dl_audit;
diff --git a/sysdeps/unix/sysv/linux/dl-osinfo.h b/sysdeps/unix/sysv/linux/dl-osinfo.h
index 082790f63b..b13b6cf1db 100644
--- a/sysdeps/unix/sysv/linux/dl-osinfo.h
+++ b/sysdeps/unix/sysv/linux/dl-osinfo.h
@@ -1,6 +1,5 @@
 /* Operating system specific code for generic dynamic loader functions.  Linux.
-   Copyright (C) 2000,2001,2002,2004,2005,2006,2007
-	Free Software Foundation, Inc.
+   Copyright (C) 2000-2002,2004-2007,2008 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
@@ -18,9 +17,6 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <string.h>
-#include <fcntl.h>
-#include <sys/utsname.h>
 #include <kernel-features.h>
 #include <dl-sysdep.h>
 #include <stdint.h>
@@ -41,97 +37,6 @@ dl_fatal (const char *str)
 }
 #endif
 
-static inline int __attribute__ ((always_inline))
-_dl_discover_osversion (void)
-{
-#if (defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO) && defined SHARED
-  if (GLRO(dl_sysinfo_map) != NULL)
-    {
-      /* If the kernel-supplied DSO contains a note indicating the kernel's
-	 version, we don't need to call uname or parse any strings.  */
-
-      static const struct
-      {
-	ElfW(Nhdr) hdr;
-	char vendor[8];
-      } expected_note = { { sizeof "Linux", sizeof (ElfW(Word)), 0 }, "Linux" };
-      const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr;
-      const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum;
-      for (uint_fast16_t i = 0; i < phnum; ++i)
-	if (phdr[i].p_type == PT_NOTE)
-	  {
-	    const ElfW(Addr) start = (phdr[i].p_vaddr
-				      + GLRO(dl_sysinfo_map)->l_addr);
-	    const ElfW(Nhdr) *note = (const void *) start;
-	    while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
-	      {
-		if (!memcmp (note, &expected_note, sizeof expected_note))
-		  return *(const ElfW(Word) *) ((const void *) note
-						+ sizeof expected_note);
-#define ROUND(len) (((len) + sizeof note->n_type - 1) & -sizeof note->n_type)
-		note = ((const void *) (note + 1)
-			+ ROUND (note->n_namesz) + ROUND (note->n_descsz));
-#undef ROUND
-	      }
-	  }
-    }
-#endif
-
-  char bufmem[64];
-  char *buf = bufmem;
-  unsigned int version;
-  int parts;
-  char *cp;
-  struct utsname uts;
-
-  /* Try the uname system call.  */
-  if (__uname (&uts))
-    {
-      /* This was not successful.  Now try reading the /proc filesystem.  */
-      int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY);
-      if (fd < 0)
-	return -1;
-      ssize_t reslen = __read (fd, bufmem, sizeof (bufmem));
-      __close (fd);
-      if (reslen <= 0)
-	/* This also didn't work.  We give up since we cannot
-	   make sure the library can actually work.  */
-	return -1;
-      buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0';
-    }
-  else
-    buf = uts.release;
-
-  /* Now convert it into a number.  The string consists of at most
-     three parts.  */
-  version = 0;
-  parts = 0;
-  cp = buf;
-  while ((*cp >= '0') && (*cp <= '9'))
-    {
-      unsigned int here = *cp++ - '0';
-
-      while ((*cp >= '0') && (*cp <= '9'))
-	{
-	  here *= 10;
-	  here += *cp++ - '0';
-	}
-
-      ++parts;
-      version <<= 8;
-      version |= here;
-
-      if (*cp++ != '.' || parts == 3)
-	/* Another part following?  */
-	break;
-    }
-
-  if (parts < 3)
-    version <<= 8 * (3 - parts);
-
-  return version;
-}
-
 #define DL_SYSDEP_OSCHECK(FATAL)					      \
   do {									      \
     /* Test whether the kernel is new enough.  This test is only performed    \
diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.c b/sysdeps/unix/sysv/linux/dl-sysdep.c
index 42aec77e82..d4be205cde 100644
--- a/sysdeps/unix/sysv/linux/dl-sysdep.c
+++ b/sysdeps/unix/sysv/linux/dl-sysdep.c
@@ -1,5 +1,5 @@
 /* Dynamic linker system dependencies for Linux.
-   Copyright (C) 1995,1997,2001,2004,2005,2006 Free Software Foundation, Inc.
+   Copyright (C) 1995,1997,2001,2004,2005,2006, 2008 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
@@ -20,7 +20,10 @@
 /* Linux needs some special initialization, but otherwise uses
    the generic dynamic linker system interface code.  */
 
+#include <string.h>
+#include <fcntl.h>
 #include <unistd.h>
+#include <sys/utsname.h>
 #include <ldsodefs.h>
 #include <kernel-features.h>
 
@@ -54,3 +57,96 @@ frob_brk (void)
 }
 
 #include <elf/dl-sysdep.c>
+
+
+int
+attribute_hidden
+_dl_discover_osversion (void)
+{
+#if (defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO) && defined SHARED
+  if (GLRO(dl_sysinfo_map) != NULL)
+    {
+      /* If the kernel-supplied DSO contains a note indicating the kernel's
+	 version, we don't need to call uname or parse any strings.  */
+
+      static const struct
+      {
+	ElfW(Nhdr) hdr;
+	char vendor[8];
+      } expected_note = { { sizeof "Linux", sizeof (ElfW(Word)), 0 }, "Linux" };
+      const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr;
+      const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum;
+      for (uint_fast16_t i = 0; i < phnum; ++i)
+	if (phdr[i].p_type == PT_NOTE)
+	  {
+	    const ElfW(Addr) start = (phdr[i].p_vaddr
+				      + GLRO(dl_sysinfo_map)->l_addr);
+	    const ElfW(Nhdr) *note = (const void *) start;
+	    while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz)
+	      {
+		if (!memcmp (note, &expected_note, sizeof expected_note))
+		  return *(const ElfW(Word) *) ((const void *) note
+						+ sizeof expected_note);
+#define ROUND(len) (((len) + sizeof note->n_type - 1) & -sizeof note->n_type)
+		note = ((const void *) (note + 1)
+			+ ROUND (note->n_namesz) + ROUND (note->n_descsz));
+#undef ROUND
+	      }
+	  }
+    }
+#endif
+
+  char bufmem[64];
+  char *buf = bufmem;
+  unsigned int version;
+  int parts;
+  char *cp;
+  struct utsname uts;
+
+  /* Try the uname system call.  */
+  if (__uname (&uts))
+    {
+      /* This was not successful.  Now try reading the /proc filesystem.  */
+      int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY);
+      if (fd < 0)
+	return -1;
+      ssize_t reslen = __read (fd, bufmem, sizeof (bufmem));
+      __close (fd);
+      if (reslen <= 0)
+	/* This also didn't work.  We give up since we cannot
+	   make sure the library can actually work.  */
+	return -1;
+      buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0';
+    }
+  else
+    buf = uts.release;
+
+  /* Now convert it into a number.  The string consists of at most
+     three parts.  */
+  version = 0;
+  parts = 0;
+  cp = buf;
+  while ((*cp >= '0') && (*cp <= '9'))
+    {
+      unsigned int here = *cp++ - '0';
+
+      while ((*cp >= '0') && (*cp <= '9'))
+	{
+	  here *= 10;
+	  here += *cp++ - '0';
+	}
+
+      ++parts;
+      version <<= 8;
+      version |= here;
+
+      if (*cp++ != '.' || parts == 3)
+	/* Another part following?  */
+	break;
+    }
+
+  if (parts < 3)
+    version <<= 8 * (3 - parts);
+
+  return version;
+}
diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.h b/sysdeps/unix/sysv/linux/dl-sysdep.h
index becfc8df3f..0371fe87a1 100644
--- a/sysdeps/unix/sysv/linux/dl-sysdep.h
+++ b/sysdeps/unix/sysv/linux/dl-sysdep.h
@@ -1,5 +1,5 @@
 /* System-specific settings for dynamic linker code.  Linux version.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2008 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
@@ -25,3 +25,12 @@
    we aren't making direct use of it.  So enable this across the board.  */
 
 #define NEED_DL_SYSINFO_DSO	1
+
+
+/* The _dl_discover_osversion function is so far only needed in sysconf
+   to check for kernels later than 2.6.23.  */
+#if !defined ASSEMBLER && __LINUX_KERNEL_VERSION < 0x020617
+/* Get version of the OS.  */
+extern int _dl_discover_osversion (void) attribute_hidden;
+# define HAVE_DL_DISCOVER_OSVERSION	1
+#endif
diff --git a/sysdeps/unix/sysv/linux/sysconf.c b/sysdeps/unix/sysv/linux/sysconf.c
index f9f6f1bfa5..ab9cddc306 100644
--- a/sysdeps/unix/sysv/linux/sysconf.c
+++ b/sysdeps/unix/sysv/linux/sysconf.c
@@ -1,5 +1,5 @@
 /* Get file-specific information about a file.  Linux version.
-   Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2006, 2008 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
@@ -23,7 +23,9 @@
 #include <sysdep.h>
 #include <time.h>
 #include <unistd.h>
+#include <sys/resource.h>
 #include <not-cancel.h>
+#include <ldsodefs.h>
 
 static long int posix_sysconf (int name);
 
@@ -70,6 +72,22 @@ __sysconf (int name)
       }
 #endif
 
+    case _SC_ARG_MAX:
+#if __LINUX_KERNEL_VERSION < 0x020617
+      /* Determine whether this is a kernel 2.6.23 or later.  Only
+	 then do we have an argument limit determined by the stack
+	 size.  */
+      if (GLRO(dl_discover_osversion) () >= 0x020617)
+#endif
+	{
+	  /* Use getrlimit to get the stack limit.  */
+	  struct rlimit rlimit;
+	  if (__getrlimit (RLIMIT_STACK, &rlimit) == 0)
+	    return MAX (ARG_MAX, rlimit.rlim_cur / 4);
+	}
+
+      return ARG_MAX;
+
     case _SC_NGROUPS_MAX:
       /* Try to read the information from the /proc/sys/kernel/ngroups_max
 	 file.  */