diff options
author | Rick Macklem <rmacklem@FreeBSD.org> | 2023-02-24 15:36:28 +0000 |
---|---|---|
committer | Rick Macklem <rmacklem@FreeBSD.org> | 2023-02-24 15:36:28 +0000 |
commit | 4036fcb8053adf3ac54c8428eef0dd076dfc1718 (patch) | |
tree | a05bf66d234b3b2b6dea7973558127f6fc791924 | |
parent | 70960bb86a3ba5b6f5c4652e613e6313a7ed1ac1 (diff) | |
download | src-4036fcb8053adf3ac54c8428eef0dd076dfc1718.tar.gz src-4036fcb8053adf3ac54c8428eef0dd076dfc1718.zip |
nfsd: Fix a use after free when vnet prisons are deleted
The Kasan tests show the nfsrvd_cleancache() results
in a modify after free. I think this occurs because the
nfsrv_cleanup() function gets executed after nfs_cleanup()
which free's the nfsstatsv1_p.
This patch makes them use the same subsystem and sets
SI_ORDER_FIRST for nfs_cleanup(), so that it will be called
after nfsrv_cleanup() via VNET_SYSUNINIT().
The patch also sets nfsstatsv1_p NULL after free'ng it,
so that a crash will result if it is used after free'ng.
Tested by: markj
Reviewed by: markj
MFC after: 3 months
Differential Revision: https://reviews.freebsd.org/D38750
-rw-r--r-- | sys/fs/nfs/nfs_commonport.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c index 212b498e6328..be5fc688b7eb 100644 --- a/sys/fs/nfs/nfs_commonport.c +++ b/sys/fs/nfs/nfs_commonport.c @@ -885,7 +885,7 @@ nfs_vnetinit(const void *unused __unused) mtx_init(&NFSD_VNET(nfsrv_nfsuserdsock).nr_mtx, "nfsuserd", NULL, MTX_DEF); } -VNET_SYSINIT(nfs_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_ANY, +VNET_SYSINIT(nfs_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_FIRST, nfs_vnetinit, NULL); static void @@ -893,12 +893,14 @@ nfs_cleanup(void *unused __unused) { mtx_destroy(&NFSD_VNET(nfsrv_nfsuserdsock).nr_mtx); - if (!IS_DEFAULT_VNET(curvnet)) + if (!IS_DEFAULT_VNET(curvnet)) { free(NFSD_VNET(nfsstatsv1_p), M_TEMP); + NFSD_VNET(nfsstatsv1_p) = NULL; + } /* Clean out the name<-->id cache. */ nfsrv_cleanusergroup(); } -VNET_SYSUNINIT(nfs_cleanup, SI_SUB_VNET_DONE, SI_ORDER_ANY, +VNET_SYSUNINIT(nfs_cleanup, SI_SUB_VNET_DONE, SI_ORDER_FIRST, nfs_cleanup, NULL); extern int (*nfsd_call_nfscommon)(struct thread *, struct nfssvc_args *); |