aboutsummaryrefslogtreecommitdiff
path: root/sys/net/if_clone.c
diff options
context:
space:
mode:
authorBrooks Davis <brooks@FreeBSD.org>2004-09-15 04:41:56 +0000
committerBrooks Davis <brooks@FreeBSD.org>2004-09-15 04:41:56 +0000
commitc859ef977e347c7dd2a1086f0f1809838300eec0 (patch)
treeb532f0fccfa8b8b1e679621ae637757365f14d89 /sys/net/if_clone.c
parente8807f22f9383f9a5f3a86fb6dbe77efb5beade6 (diff)
downloadsrc-c859ef977e347c7dd2a1086f0f1809838300eec0.tar.gz
src-c859ef977e347c7dd2a1086f0f1809838300eec0.zip
Fix a LOR where copyout was called while holding a lock.
Reported by: rwatson
Notes
Notes: svn path=/head/; revision=135256
Diffstat (limited to 'sys/net/if_clone.c')
-rw-r--r--sys/net/if_clone.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c
index 04c54bdd069f..7a519ee452d5 100644
--- a/sys/net/if_clone.c
+++ b/sys/net/if_clone.c
@@ -235,9 +235,24 @@ if_clone_free(struct if_clone *ifc)
int
if_clone_list(struct if_clonereq *ifcr)
{
- char outbuf[IFNAMSIZ], *dst;
+ char *buf, *dst, *outbuf = NULL;
struct if_clone *ifc;
- int count, err = 0;
+ int buf_count, count, err = 0;
+
+ IF_CLONERS_LOCK();
+ /*
+ * Set our internal output buffer size. We could end up not
+ * reporting a cloner that is added between the unlock and lock
+ * below, but that's not a major problem. Not caping our
+ * allocation to the number of cloners actually in the system
+ * could be because that would let arbitrary users cause us to
+ * allocate abritrary amounts of kernel memory.
+ */
+ buf_count = (if_cloners_count < ifcr->ifcr_count) ?
+ if_cloners_count : ifcr->ifcr_count;
+ IF_CLONERS_UNLOCK();
+
+ outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO);
IF_CLONERS_LOCK();
@@ -252,19 +267,21 @@ if_clone_list(struct if_clonereq *ifcr)
goto done;
}
- count = (if_cloners_count < ifcr->ifcr_count) ?
- if_cloners_count : ifcr->ifcr_count;
+ count = (if_cloners_count < buf_count) ?
+ if_cloners_count : buf_count;
- for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
- ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
- strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ);
- err = copyout(outbuf, dst, IFNAMSIZ);
- if (err)
- break;
+ for (ifc = LIST_FIRST(&if_cloners), buf = outbuf;
+ ifc != NULL && count != 0;
+ ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) {
+ strlcpy(buf, ifc->ifc_name, IFNAMSIZ);
}
done:
IF_CLONERS_UNLOCK();
+ if (err == 0)
+ err = copyout(outbuf, dst, buf_count*IFNAMSIZ);
+ if (outbuf != NULL)
+ free(outbuf, M_CLONE);
return (err);
}