aboutsummaryrefslogtreecommitdiff
path: root/nscd/connections.c
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/connections.c
parent189699ab375111a25dac19f1b4f89e38d31c8b3d (diff)
downloadglibc-318bad78b084cd510c7b672a1a0859c0df08dbb7.zip
glibc-318bad78b084cd510c7b672a1a0859c0df08dbb7.tar.gz
glibc-318bad78b084cd510c7b672a1a0859c0df08dbb7.tar.bz2
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/connections.c')
-rw-r--r--nscd/connections.c99
1 files changed, 61 insertions, 38 deletions
diff --git a/nscd/connections.c b/nscd/connections.c
index 1b3bae4..47fbb99 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);