diff options
author | anton <anton@openbsd.org> | 2018-12-25 21:56:53 +0000 |
---|---|---|
committer | anton <anton@openbsd.org> | 2018-12-25 21:56:53 +0000 |
commit | 8180eaf209af4b7901aadc13f45463c52d09965a (patch) | |
tree | bd5227e881d67b75dfa9a4c1bb18e959a2594683 /sys/dev/kcov.c | |
parent | rework icmp6_error() to be closer to icmp_error() (diff) | |
download | wireguard-openbsd-8180eaf209af4b7901aadc13f45463c52d09965a.tar.xz wireguard-openbsd-8180eaf209af4b7901aadc13f45463c52d09965a.zip |
In the kcov ioctl(KIOSETBUFSIZE) path, malloc() can sleep. Double check that
someone else didn't win the race.
ok mpi@
Diffstat (limited to 'sys/dev/kcov.c')
-rw-r--r-- | sys/dev/kcov.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/sys/dev/kcov.c b/sys/dev/kcov.c index 6a8dc3ebfbc..ea28ba8f326 100644 --- a/sys/dev/kcov.c +++ b/sys/dev/kcov.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kcov.c,v 1.5 2018/12/12 07:29:38 anton Exp $ */ +/* $OpenBSD: kcov.c,v 1.6 2018/12/25 21:56:53 anton Exp $ */ /* * Copyright (c) 2018 Anton Lindqvist <anton@openbsd.org> @@ -50,7 +50,7 @@ struct kcov_dev { void kcovattach(int); -int kd_alloc(struct kcov_dev *, unsigned long); +int kd_init(struct kcov_dev *, unsigned long); void kd_free(struct kcov_dev *); struct kcov_dev *kd_lookup(int); @@ -159,13 +159,7 @@ kcovioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) switch (cmd) { case KIOSETBUFSIZE: - if (kd->kd_mode != KCOV_MODE_DISABLED) { - error = EBUSY; - break; - } - error = kd_alloc(kd, *((unsigned long *)data)); - if (error == 0) - kd->kd_mode = KCOV_MODE_INIT; + error = kd_init(kd, *((unsigned long *)data)); break; case KIOENABLE: /* Only one kcov descriptor can be enabled per thread. */ @@ -247,20 +241,31 @@ kd_lookup(int unit) } int -kd_alloc(struct kcov_dev *kd, unsigned long nmemb) +kd_init(struct kcov_dev *kd, unsigned long nmemb) { + void *buf; size_t size; KASSERT(kd->kd_buf == NULL); + if (kd->kd_mode != KCOV_MODE_DISABLED) + return (EBUSY); + if (nmemb == 0 || nmemb > KCOV_BUF_MAX_NMEMB) return (EINVAL); size = roundup(nmemb * sizeof(uintptr_t), PAGE_SIZE); - kd->kd_buf = malloc(size, M_SUBPROC, M_WAITOK | M_ZERO); + buf = malloc(size, M_SUBPROC, M_WAITOK | M_ZERO); + /* malloc() can sleep, ensure the race was won. */ + if (kd->kd_mode != KCOV_MODE_DISABLED) { + free(buf, M_SUBPROC, size); + return (EBUSY); + } + kd->kd_buf = buf; /* The first element is reserved to hold the number of used elements. */ kd->kd_nmemb = nmemb - 1; kd->kd_size = size; + kd->kd_mode = KCOV_MODE_INIT; return (0); } |