summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlstewart <lstewart@FreeBSD.org>2011-01-23 13:00:25 +0000
committerlstewart <lstewart@FreeBSD.org>2011-01-23 13:00:25 +0000
commit3087aa2fa91d995a820fabb18e1cac1068e9c6b0 (patch)
tree5c026cdda8f4584df332222cd0c784dde2f9fc50
parent42a63fe711f3b2bd5f354dc9e6a065d48588c0cb (diff)
downloadFreeBSD-src-3087aa2fa91d995a820fabb18e1cac1068e9c6b0.zip
FreeBSD-src-3087aa2fa91d995a820fabb18e1cac1068e9c6b0.tar.gz
An sbuf configured with SBUF_AUTOEXTEND will call malloc with M_WAITOK when a
write to the buffer causes it to overflow. We therefore can't hold the CC list rwlock over a call to sbuf_printf() for an sbuf configured with SBUF_AUTOEXTEND. Switch to a fixed length sbuf which should be of sufficient size except in the very unlikely event that the sysctl is being processed as one or more new algorithms are loaded. If that happens, we accept the race and may fail the sysctl gracefully if there is insufficient room to print the names of all the algorithms. This should address a WITNESS warning and the potential panic that would occur if the sbuf call to malloc did sleep whilst holding the CC list rwlock. Sponsored by: FreeBSD Foundation Reported by: Nick Hibma Reviewed by: bz MFC after: 3 weeks X-MFC with: r215166
-rw-r--r--sys/netinet/cc/cc.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/sys/netinet/cc/cc.c b/sys/netinet/cc/cc.c
index f075327..cfcbfa6 100644
--- a/sys/netinet/cc/cc.c
+++ b/sys/netinet/cc/cc.c
@@ -128,20 +128,37 @@ cc_list_available(SYSCTL_HANDLER_ARGS)
{
struct cc_algo *algo;
struct sbuf *s;
- int err, first;
+ int err, first, nalgos;
- err = 0;
+ err = nalgos = 0;
first = 1;
- s = sbuf_new(NULL, NULL, TCP_CA_NAME_MAX, SBUF_AUTOEXTEND);
+
+ CC_LIST_RLOCK();
+ STAILQ_FOREACH(algo, &cc_list, entries) {
+ nalgos++;
+ }
+ CC_LIST_RUNLOCK();
+
+ s = sbuf_new(NULL, NULL, nalgos * TCP_CA_NAME_MAX, SBUF_FIXEDLEN);
if (s == NULL)
return (ENOMEM);
+ /*
+ * It is theoretically possible for the CC list to have grown in size
+ * since the call to sbuf_new() and therefore for the sbuf to be too
+ * small. If this were to happen (incredibly unlikely), the sbuf will
+ * reach an overflow condition, sbuf_printf() will return an error and
+ * the sysctl will fail gracefully.
+ */
CC_LIST_RLOCK();
STAILQ_FOREACH(algo, &cc_list, entries) {
err = sbuf_printf(s, first ? "%s" : ", %s", algo->name);
- if (err)
+ if (err) {
+ /* Sbuf overflow condition. */
+ err = EOVERFLOW;
break;
+ }
first = 0;
}
CC_LIST_RUNLOCK();
OpenPOWER on IntegriCloud