about summary refs log tree commit diff
path: root/nscd
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2018-06-25 17:10:15 +0200
committerFlorian Weimer <fweimer@redhat.com>2018-06-25 17:10:15 +0200
commit318bad78b084cd510c7b672a1a0859c0df08dbb7 (patch)
tree530b33b954bef36b1fc0b55475c46c9700ec65f0 /nscd
parent189699ab375111a25dac19f1b4f89e38d31c8b3d (diff)
downloadglibc-318bad78b084cd510c7b672a1a0859c0df08dbb7.tar.gz
glibc-318bad78b084cd510c7b672a1a0859c0df08dbb7.tar.xz
glibc-318bad78b084cd510c7b672a1a0859c0df08dbb7.zip
nscd restart: Use malloc instead of extend_alloca [BZ #18023]
This introduces a separate function, read_cmdline, which reads the
contents of /proc/self/cmdline into a heap-allocated buffer.
Diffstat (limited to 'nscd')
-rw-r--r--nscd/connections.c99
1 files changed, 61 insertions, 38 deletions
diff --git a/nscd/connections.c b/nscd/connections.c
index 1b3bae4eeb..47fbb9923a 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -1281,64 +1281,83 @@ request from '%s' [%ld] not handled due to missing permission"),
     }
 }
 
-
-/* Restart the process.  */
-static void
-restart (void)
+static char *
+read_cmdline (size_t *size)
 {
-  /* First determine the parameters.  We do not use the parameters
-     passed to main() since in case nscd is started by running the
-     dynamic linker this will not work.  Yes, this is not the usual
-     case but nscd is part of glibc and we occasionally do this.  */
-  size_t buflen = 1024;
-  char *buf = alloca (buflen);
-  size_t readlen = 0;
   int fd = open ("/proc/self/cmdline", O_RDONLY);
-  if (fd == -1)
+  if (fd < 0)
+    return NULL;
+  size_t current = 0;
+  size_t limit = 1024;
+  char *buffer = malloc (limit);
+  if (buffer == NULL)
     {
-      dbg_log (_("\
-cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
-	       strerror (errno));
-
-      paranoia = 0;
-      return;
+      close (fd);
+      errno = ENOMEM;
+      return NULL;
     }
-
   while (1)
     {
-      ssize_t n = TEMP_FAILURE_RETRY (read (fd, buf + readlen,
-					    buflen - readlen));
-      if (n == -1)
+      if (current == limit)
 	{
-	  dbg_log (_("\
-cannot read /proc/self/cmdline: %s; disabling paranoia mode"),
-		   strerror (errno));
+	  char *newptr;
+	  if (2 * limit < limit
+	      || (newptr = realloc (buffer, 2 * limit)) == NULL)
+	    {
+	      free (buffer);
+	      close (fd);
+	      errno = ENOMEM;
+	      return NULL;
+	    }
+	  buffer = newptr;
+	  limit *= 2;
+	}
 
+      ssize_t n = TEMP_FAILURE_RETRY (read (fd, buffer + current,
+					    limit - current));
+      if (n == -1)
+	{
+	  int e = errno;
+	  free (buffer);
 	  close (fd);
-	  paranoia = 0;
-	  return;
+	  errno = e;
+	  return NULL;
 	}
-
-      readlen += n;
-
-      if (readlen < buflen)
+      if (n == 0)
 	break;
-
-      /* We might have to extend the buffer.  */
-      size_t old_buflen = buflen;
-      char *newp = extend_alloca (buf, buflen, 2 * buflen);
-      buf = memmove (newp, buf, old_buflen);
+      current += n;
     }
 
   close (fd);
+  *size = current;
+  return buffer;
+}
+
+
+/* Restart the process.  */
+static void
+restart (void)
+{
+  /* First determine the parameters.  We do not use the parameters
+     passed to main because then nscd would use the system libc after
+     restarting even if it was started by a non-system dynamic linker
+     during glibc testing.  */
+  size_t readlen;
+  char *cmdline = read_cmdline (&readlen);
+  if (cmdline == NULL)
+    {
+      dbg_log (_("\
+cannot open /proc/self/cmdline: %m; disabling paranoia mode"));
+      paranoia = 0;
+      return;
+    }
 
   /* Parse the command line.  Worst case scenario: every two
      characters form one parameter (one character plus NUL).  */
   char **argv = alloca ((readlen / 2 + 1) * sizeof (argv[0]));
   int argc = 0;
 
-  char *cp = buf;
-  while (cp < buf + readlen)
+  for (char *cp = cmdline; cp < cmdline + readlen;)
     {
       argv[argc++] = cp;
       cp = (char *) rawmemchr (cp, '\0') + 1;
@@ -1355,6 +1374,7 @@ cannot change to old UID: %s; disabling paranoia mode"),
 		   strerror (errno));
 
 	  paranoia = 0;
+	  free (cmdline);
 	  return;
 	}
 
@@ -1366,6 +1386,7 @@ cannot change to old GID: %s; disabling paranoia mode"),
 
 	  ignore_value (setuid (server_uid));
 	  paranoia = 0;
+	  free (cmdline);
 	  return;
 	}
     }
@@ -1383,6 +1404,7 @@ cannot change to old working directory: %s; disabling paranoia mode"),
 	  ignore_value (setgid (server_gid));
 	}
       paranoia = 0;
+      free (cmdline);
       return;
     }
 
@@ -1431,6 +1453,7 @@ cannot change to old working directory: %s; disabling paranoia mode"),
     dbg_log (_("cannot change current working directory to \"/\": %s"),
 	     strerror (errno));
   paranoia = 0;
+  free (cmdline);
 
   /* Reenable the databases.  */
   time_t now = time (NULL);