src/librc/librc-daemon.c: fix buffer overrun in pid_is_argv

The contents of /proc/<pid>/cmdline are read into
a stack buffer using

  bytes = read(fd, buffer, sizeof(buffer));

followed by appending a null terminator to the buffer with

  buffer[bytes] = '\0';

If bytes == sizeof(buffer), then this write is out-of-bounds.

Refactor the code to use rc_getfile instead, since PATH_MAX
is not the maximum size of /proc/<pid>/cmdline. (I hit this
issue in practice while compiling Linux; it tripped the
stack-smashing protector.)

This is roughly the same buffer overflow condition
that was fixed by commit 0ddee9b7d2
This fixes #269.
This commit is contained in:
philhofer 2018-12-18 20:36:26 -08:00 committed by William Hubbs
parent 97e74f9734
commit 084877eb52

View File

@ -48,34 +48,40 @@ pid_is_exec(pid_t pid, const char *exec)
static bool static bool
pid_is_argv(pid_t pid, const char *const *argv) pid_is_argv(pid_t pid, const char *const *argv)
{ {
char *buffer = NULL;
char *cmdline = NULL; char *cmdline = NULL;
int fd;
char buffer[PATH_MAX];
char *p; char *p;
ssize_t bytes; size_t bytes;
bool rc;
xasprintf(&cmdline, "/proc/%u/cmdline", pid); xasprintf(&cmdline, "/proc/%u/cmdline", pid);
if ((fd = open(cmdline, O_RDONLY)) < 0) { if (!rc_getfile(cmdline, &buffer, &bytes)) {
free(cmdline); free(cmdline);
return false; return false;
} }
bytes = read(fd, buffer, sizeof(buffer));
close(fd);
free(cmdline); free(cmdline);
if (bytes == -1) if (bytes <= 0) {
if (buffer)
free(buffer);
return false; return false;
}
buffer[bytes] = '\0';
p = buffer; p = buffer;
rc = true;
while (*argv) { while (*argv) {
if (strcmp(*argv, p) != 0) if (strcmp(*argv, p) != 0) {
return false; rc = false;
break;
}
argv++; argv++;
p += strlen(p) + 1; p += strlen(p) + 1;
if ((unsigned)(p - buffer) > sizeof(buffer)) if ((unsigned)(p - buffer) >= bytes) {
return false; rc = false;
break;
}
} }
return true; free(buffer);
return rc;
} }
RC_PIDLIST * RC_PIDLIST *