Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177461768
D61353.1794472731.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None
D61353.1794472731.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D61353: mbuf: add m_dataobj() and m_databuf() bounded accessors
Attached
Detach File
Event Timeline