summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2015-09-04 02:58:15 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2015-09-04 02:58:15 +0000
commit257c2732903c8dc2a2e5edc5013da40f3b3ad8fb (patch)
tree1d6d91ceec375c0ca2e802229011625b39511007
parentf9d2816e89126e3eed53e66635fa41b8b1c74efa (diff)
fix a race when fetching files from the kernel. the number of files
might have increased between when we got the number of files and when we requested that number of files. now we allocate another 10ish percent on top of what the kernel says we need, and retry if that still isnt enough. while here use realloc instead of constantly going through free/malloc sequences. with input from claudio@ deraadt@ ok millert@ guenther@
-rw-r--r--lib/libkvm/kvm.c7
-rw-r--r--lib/libkvm/kvm_file2.c77
2 files changed, 44 insertions, 40 deletions
diff --git a/lib/libkvm/kvm.c b/lib/libkvm/kvm.c
index a261ce4ff82..f784b5f013f 100644
--- a/lib/libkvm/kvm.c
+++ b/lib/libkvm/kvm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kvm.c,v 1.56 2015/09/04 02:55:09 dlg Exp $ */
+/* $OpenBSD: kvm.c,v 1.57 2015/09/04 02:58:14 dlg Exp $ */
/* $NetBSD: kvm.c,v 1.43 1996/05/05 04:31:59 gwr Exp $ */
/*-
@@ -183,7 +183,7 @@ _kvm_open(kvm_t *kd, const char *uf, const char *mf, const char *sf,
kd->swfd = -1;
kd->nlfd = -1;
kd->alive = 0;
- kd->filebase = 0;
+ kd->filebase = NULL;
kd->procbase = 0;
kd->nbpg = getpagesize();
kd->swapspc = 0;
@@ -653,8 +653,7 @@ kvm_close(kvm_t *kd)
free((void *)kd->cpu_data);
if (kd->kcore_hdr != NULL)
free((void *)kd->kcore_hdr);
- if (kd->filebase != 0)
- free((void *)kd->filebase);
+ free(kd->filebase);
if (kd->procbase != 0)
free((void *)kd->procbase);
if (kd->swapspc != 0)
diff --git a/lib/libkvm/kvm_file2.c b/lib/libkvm/kvm_file2.c
index 04912bf2562..669a7d4ae77 100644
--- a/lib/libkvm/kvm_file2.c
+++ b/lib/libkvm/kvm_file2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kvm_file2.c,v 1.46 2015/08/28 04:38:47 guenther Exp $ */
+/* $OpenBSD: kvm_file2.c,v 1.47 2015/09/04 02:58:14 dlg Exp $ */
/*
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -114,6 +114,7 @@
#include <string.h>
#include <unistd.h>
#include <limits.h>
+#include <errno.h>
#include "kvm_private.h"
#include "kvm_file.h"
@@ -132,44 +133,46 @@ struct kinfo_file *
kvm_getfiles(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
{
int mib[6], rv;
+ void *filebase;
size_t size;
- if (kd->filebase != NULL) {
- free(kd->filebase);
- /*
- * Clear this pointer in case this call fails. Otherwise,
- * kvm_close() will free it again.
- */
- kd->filebase = 0;
- }
-
if (ISALIVE(kd)) {
mib[0] = CTL_KERN;
mib[1] = KERN_FILE;
mib[2] = op;
mib[3] = arg;
mib[4] = esize;
- mib[5] = 0;
-
- /* find size and alloc buffer */
- rv = sysctl(mib, 6, NULL, &size, NULL, 0);
- if (rv == -1) {
- if (kd->vmfd != -1)
- goto deadway;
- _kvm_syserr(kd, kd->program, "kvm_getfiles");
- return (NULL);
- }
- kd->filebase = _kvm_malloc(kd, size);
- if (kd->filebase == NULL)
- return (NULL);
- /* get actual data */
- mib[5] = size / esize;
- rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
- if (rv == -1) {
- _kvm_syserr(kd, kd->program, "kvm_getfiles");
- return (NULL);
- }
+ do {
+ mib[5] = 0;
+
+ /* find size and alloc buffer */
+ rv = sysctl(mib, 6, NULL, &size, NULL, 0);
+ if (rv == -1) {
+ if (kd->vmfd != -1)
+ goto deadway;
+ _kvm_syserr(kd, kd->program, "kvm_getfiles");
+ return (NULL);
+ }
+
+ size += size / 8; /* add ~10% */
+
+ filebase = _kvm_realloc(kd, kd->filebase, size);
+ if (filebase == NULL)
+ return (NULL);
+
+ kd->filebase = filebase;
+
+ /* get actual data */
+ mib[5] = size / esize;
+ rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
+ if (rv == -1 && errno != ENOMEM) {
+ _kvm_syserr(kd, kd->program,
+ "kvm_getfiles");
+ return (NULL);
+ }
+ } while (rv == -1);
+
*cnt = size / esize;
return (kd->filebase);
} else {
@@ -224,10 +227,11 @@ kvm_deadfile_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
_kvm_err(kd, kd->program, "can't read nfiles");
return (NULL);
}
- where = _kvm_reallocarray(kd, NULL, nfiles, esize);
- kd->filebase = (void *)where;
- if (kd->filebase == NULL)
+ where = _kvm_reallocarray(kd, kd->filebase, nfiles, esize);
+ if (where == NULL)
return (NULL);
+
+ kd->filebase = (void *)where;
buflen = nfiles * esize;
for (fp = LIST_FIRST(&filehead);
@@ -301,10 +305,11 @@ kvm_deadfile_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
return (NULL);
}
/* this may be more room than we need but counting is expensive */
- where = _kvm_reallocarray(kd, NULL, nfiles + 10, esize);
- kd->filebase = (void *)where;
- if (kd->filebase == NULL)
+ where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize);
+ if (where == NULL)
return (NULL);
+
+ kd->filebase = (void *)where;
buflen = (nfiles + 10) * esize;
for (pr = LIST_FIRST(&allprocess);