Page MenuHomeFreeBSD

D61353.1794472731.diff
No OneTemporary

Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None

D61353.1794472731.diff

diff --git a/sys/kern/kern_bounds_test.c b/sys/kern/kern_bounds_test.c
--- a/sys/kern/kern_bounds_test.c
+++ b/sys/kern/kern_bounds_test.c
@@ -11,8 +11,9 @@
* add kern_bounds_test.c (not kern_bounds.c) to BOUNDS_SAFETY_FILES to enable
* it. Writing N to debug.bounds_test reads arr[N] of a 4-element array; N is
* clamped to [0, 4], and N == 4 (one past the end) traps.
- * debug.bounds_mtod_test and debug.bounds_dataptr_test take a case number
- * and exercise mtod(), mtod_len() and m_dataptr().
+ * The other debug.bounds_*_test sysctls take a case number so the kyua test
+ * can check which cases trap. Hooks that check results fail with EDOOFUS, so
+ * a wrong pointer or length fails the test even when nothing traps.
*/
#include <sys/param.h>
@@ -203,4 +204,129 @@
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
sysctl_debug_bounds_dataptr_test, "I",
"Exercise m_dataptr(); modes 2 and 8 trap, 3-7 return NULL");
+
+struct bounds_test_obj {
+ char b[20];
+};
+
+static int
+sysctl_debug_bounds_dataobj_test(SYSCTL_HANDLER_ARGS)
+{
+ struct mbuf *m;
+ struct bounds_test_obj *o;
+ int error, mode;
+ volatile int idx;
+ volatile char sink;
+
+ mode = -1;
+ error = sysctl_handle_int(oidp, &mode, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (mode < 0 || mode > 2)
+ return (EINVAL);
+
+ m = m_getcl(M_WAITOK, MT_DATA, 0);
+ m->m_len = sizeof(*o);
+ memset(mtod(m, char *), 0x5a, 64);
+ sink = 0;
+ idx = sizeof(*o);
+
+ switch (mode) {
+ case 0:
+ o = m_dataobj(m, struct bounds_test_obj *);
+ if (o == NULL || (char *)o != mtod(m, char *) ||
+ o->b[sizeof(o->b) - 1] != 0x5a)
+ error = EDOOFUS;
+ break;
+ case 1:
+ m->m_len = sizeof(*o) - 1;
+ if (m_dataobj(m, struct bounds_test_obj *) != NULL)
+ error = EDOOFUS;
+ break;
+ case 2:
+ o = m_dataobj(m, struct bounds_test_obj *);
+ if (o == NULL)
+ error = EDOOFUS;
+ else
+ sink = ((char *)o)[idx];
+ break;
+ }
+ printf("bounds-safety: dataobj test mode %d -> %d\n", mode, (int)sink);
+ m_freem(m);
+ return (error);
+}
+SYSCTL_PROC(_debug, OID_AUTO, bounds_dataobj_test,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
+ sysctl_debug_bounds_dataobj_test, "I",
+ "Exercise m_dataobj(); mode 1 returns NULL, mode 2 traps");
+
+static int
+sysctl_debug_bounds_databuf_test(SYSCTL_HANDLER_ARGS)
+{
+ struct mbuf *m;
+ char *p;
+ size_t len;
+ u_int realsize;
+ int error, mode;
+ volatile char sink;
+
+ mode = -1;
+ error = sysctl_handle_int(oidp, &mode, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (mode < 0 || mode > 5)
+ return (EINVAL);
+
+ m = m_getcl(M_WAITOK, MT_DATA, 0);
+ m->m_len = 64;
+ realsize = m->m_ext.ext_size;
+ memset(mtod(m, char *), 0x5a, realsize);
+ sink = 0;
+
+ switch (mode) {
+ case 0:
+ p = m_databuf(m, &len);
+ if (len != 64 || p != mtod(m, char *) || p[len - 1] != 0x5a)
+ error = EDOOFUS;
+ break;
+ case 1:
+ p = m_databuf(m, &len);
+ if (len != 64)
+ error = EDOOFUS;
+ else
+ sink = p[len];
+ break;
+ case 2:
+ m->m_flags |= M_EXTPG;
+ p = m_databuf(m, &len);
+ m->m_flags &= ~M_EXTPG;
+ if (p == NULL || len != 0)
+ error = EDOOFUS;
+ else
+ sink = p[0];
+ break;
+ case 3:
+ m->m_ext.ext_size = TESTCAP;
+ m->m_len = TESTCAP + 16;
+ p = m_databuf(m, &len);
+ sink = p[0];
+ break;
+ case 4:
+ case 5:
+ m->m_len = mode == 4 ? 0 : -1;
+ p = m_databuf(m, &len);
+ m->m_len = 0;
+ if (p == NULL || len != 0)
+ error = EDOOFUS;
+ break;
+ }
+ m->m_ext.ext_size = realsize;
+ printf("bounds-safety: databuf test mode %d -> %d\n", mode, (int)sink);
+ m_freem(m);
+ return (error);
+}
+SYSCTL_PROC(_debug, OID_AUTO, bounds_databuf_test,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
+ sysctl_debug_bounds_databuf_test, "I",
+ "Exercise m_databuf(); modes 1-3 trap");
#endif /* __has_ptrcheck */
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -1271,6 +1271,28 @@
return (mtodo(m, off));
}
+/*
+ * Return the data of m as a t, a pointer type such as struct tcphdr *, or
+ * NULL if m_len is shorter than the object it points to. The data must be
+ * aligned for that object. Under -fbounds-safety the result is bounded to
+ * that one object.
+ */
+#define m_dataobj(m, t) ((t __single)m_dataptr((m), 0, sizeof(*(t)0)))
+
+/*
+ * Return the data of m with its length in *lenp, so that a walk over the
+ * whole buffer is bounded under -fbounds-safety. M_EXTPG data is not
+ * mapped and a negative m_len is bogus, so both give length 0 and any
+ * checked read traps.
+ */
+static __inline void * __sized_by(*lenp)
+m_databuf(const struct mbuf *m, size_t *lenp)
+{
+
+ *lenp = (m->m_flags & M_EXTPG) != 0 || m->m_len < 0 ? 0 : m->m_len;
+ return (mtod_len(m, void *));
+}
+
/*
* Set the m_data pointer of a newly allocated mbuf to place an object of the
* specified size at the end of the mbuf, longword aligned.
diff --git a/tests/sys/kern/bounds_safety_test.sh b/tests/sys/kern/bounds_safety_test.sh
--- a/tests/sys/kern/bounds_safety_test.sh
+++ b/tests/sys/kern/bounds_safety_test.sh
@@ -21,6 +21,7 @@
}
# Run each mode of a test sysctl and check how many violations it reports.
+# A hook that also checks its results fails the sysctl if one is wrong.
check_modes()
{
local oid=$1 mode=0 before after want
@@ -77,9 +78,37 @@
check_modes debug.bounds_dataptr_test 0 0 1 0 0 0 0 0 1
}
+atf_test_case dataobj
+dataobj_head()
+{
+ atf_set "descr" "m_dataobj() returns one bounded object or NULL"
+ atf_set "require.config" "allow_sysctl_side_effects"
+ atf_set "require.user" "root"
+}
+dataobj_body()
+{
+ require_soft_traps
+ check_modes debug.bounds_dataobj_test 0 0 1
+}
+
+atf_test_case databuf
+databuf_head()
+{
+ atf_set "descr" "m_databuf() bounds the data by the length it returns"
+ atf_set "require.config" "allow_sysctl_side_effects"
+ atf_set "require.user" "root"
+}
+databuf_body()
+{
+ require_soft_traps
+ check_modes debug.bounds_databuf_test 0 1 1 1 0 0
+}
+
atf_init_test_cases()
{
atf_add_test_case array
atf_add_test_case mtod
atf_add_test_case dataptr
+ atf_add_test_case dataobj
+ atf_add_test_case databuf
}

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 12, 8:38 AM (18 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41645325
Default Alt Text
D61353.1794472731.diff (6 KB)

Event Timeline