git: e1e847374bcc - main - Add DEBUG_POISON_POINTER
- Reply: Gleb Smirnoff : "Re: git: e1e847374bcc - main - Add DEBUG_POISON_POINTER"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 28 Nov 2023 16:35:40 UTC
The branch main has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=e1e847374bcc287ca97e6cb16cb5e07a697cf055 commit e1e847374bcc287ca97e6cb16cb5e07a697cf055 Author: Mateusz Guzik <mjg@FreeBSD.org> AuthorDate: 2023-11-28 15:23:25 +0000 Commit: Mateusz Guzik <mjg@FreeBSD.org> CommitDate: 2023-11-28 16:33:46 +0000 Add DEBUG_POISON_POINTER If you have a pointer which you know points to stale data, you can fill it with junk so that dereference later will trap Reviewed by: kib Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D40946 --- sys/kern/vfs_bio.c | 6 ++++++ sys/sys/kassert.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 31059f1c0a94..4e0832475c3e 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -159,6 +159,9 @@ nbufp(unsigned i) } caddr_t __read_mostly unmapped_buf; +#ifdef INVARIANTS +caddr_t poisoned_buf = (void *)-1; +#endif /* Used below and for softdep flushing threads in ufs/ffs/ffs_softdep.c */ struct proc *bufdaemonproc; @@ -1211,6 +1214,9 @@ bufinit(void) mtx_init(&bdirtylock, "dirty buf lock", NULL, MTX_DEF); unmapped_buf = (caddr_t)kva_alloc(maxphys); +#ifdef INVARIANTS + poisoned_buf = unmapped_buf; +#endif /* finally, initialize each buffer header and stick on empty q */ for (i = 0; i < nbuf; i++) { diff --git a/sys/sys/kassert.h b/sys/sys/kassert.h index d7c1a21385f9..7b54ac6ae519 100644 --- a/sys/sys/kassert.h +++ b/sys/sys/kassert.h @@ -38,6 +38,37 @@ extern const char *panicstr; /* panic message */ extern bool panicked; #define KERNEL_PANICKED() __predict_false(panicked) +/* + * Trap accesses going through a pointer. Moreover if kasan is available trap + * reading the pointer itself. + * + * Sample usage: you have a struct with numerous fields and by API contract + * only some of them get populated, even if the implementation temporary writes + * to them. You can use DEBUG_POISON_POINTER so that the consumer which should + * no be looking at the field gets caught. + * + * DEBUG_POISON_POINTER(obj->ptr); + * .... + * if (obj->ptr != NULL) // traps with kasan, does not trap otherwise + * .... + * if (obj->ptr->field) // traps with and without kasan + */ +#ifdef INVARIANTS + +#include <sys/asan.h> + +extern caddr_t poisoned_buf; +#define DEBUG_POISON_POINTER_VALUE poisoned_buf + +#define DEBUG_POISON_POINTER(x) ({ \ + x = (void *)(DEBUG_POISON_POINTER_VALUE); \ + kasan_mark(&x, 0, sizeof(x), KASAN_GENERIC_REDZONE); \ +}) + +#else +#define DEBUG_POISON_POINTER(x) +#endif + #ifdef INVARIANTS /* The option is always available */ #define VNASSERT(exp, vp, msg) do { \ if (__predict_false(!(exp))) { \