svn commit: r366462 - in head/sys: kern sys
Mateusz Guzik
mjg at FreeBSD.org
Mon Oct 5 19:38:52 UTC 2020
Author: mjg
Date: Mon Oct 5 19:38:51 2020
New Revision: 366462
URL: https://svnweb.freebsd.org/changeset/base/366462
Log:
cache: fix pwd use-after-free in setting up fallback
Since the code exits smr section prior to calling pwd_hold, the used
pwd can be freed and a new one allocated with the same address, making
the comparison erroneously true.
Note it is very unlikely anyone ran into it.
Modified:
head/sys/kern/kern_descrip.c
head/sys/kern/vfs_cache.c
head/sys/sys/filedesc.h
Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c Mon Oct 5 19:26:54 2020 (r366461)
+++ head/sys/kern/kern_descrip.c Mon Oct 5 19:38:51 2020 (r366462)
@@ -3344,6 +3344,17 @@ pwd_hold_filedesc(struct filedesc *fdp)
return (pwd);
}
+bool
+pwd_hold_smr(struct pwd *pwd)
+{
+
+ MPASS(pwd != NULL);
+ if (__predict_true(refcount_acquire_if_not_zero(&pwd->pwd_refcount))) {
+ return (true);
+ }
+ return (false);
+}
+
struct pwd *
pwd_hold(struct thread *td)
{
@@ -3354,8 +3365,7 @@ pwd_hold(struct thread *td)
vfs_smr_enter();
pwd = vfs_smr_entered_load(&fdp->fd_pwd);
- MPASS(pwd != NULL);
- if (__predict_true(refcount_acquire_if_not_zero(&pwd->pwd_refcount))) {
+ if (pwd_hold_smr(pwd)) {
vfs_smr_exit();
return (pwd);
}
Modified: head/sys/kern/vfs_cache.c
==============================================================================
--- head/sys/kern/vfs_cache.c Mon Oct 5 19:26:54 2020 (r366461)
+++ head/sys/kern/vfs_cache.c Mon Oct 5 19:38:51 2020 (r366462)
@@ -3484,25 +3484,24 @@ cache_fplookup_partial_setup(struct cache_fpl *fpl)
ndp = fpl->ndp;
cnp = fpl->cnp;
+ pwd = fpl->pwd;
dvp = fpl->dvp;
dvp_seqc = fpl->dvp_seqc;
- dvs = vget_prep_smr(dvp);
- if (__predict_false(dvs == VGET_NONE)) {
+ if (!pwd_hold_smr(pwd)) {
cache_fpl_smr_exit(fpl);
return (cache_fpl_aborted(fpl));
}
+ dvs = vget_prep_smr(dvp);
cache_fpl_smr_exit(fpl);
-
- vget_finish_ref(dvp, dvs);
- if (!vn_seqc_consistent(dvp, dvp_seqc)) {
- vrele(dvp);
+ if (__predict_false(dvs == VGET_NONE)) {
+ pwd_drop(pwd);
return (cache_fpl_aborted(fpl));
}
- pwd = pwd_hold(curthread);
- if (fpl->pwd != pwd) {
+ vget_finish_ref(dvp, dvs);
+ if (!vn_seqc_consistent(dvp, dvp_seqc)) {
vrele(dvp);
pwd_drop(pwd);
return (cache_fpl_aborted(fpl));
Modified: head/sys/sys/filedesc.h
==============================================================================
--- head/sys/sys/filedesc.h Mon Oct 5 19:26:54 2020 (r366461)
+++ head/sys/sys/filedesc.h Mon Oct 5 19:38:51 2020 (r366462)
@@ -302,6 +302,7 @@ void pwd_ensure_dirs(void);
void pwd_set_rootvnode(void);
struct pwd *pwd_hold_filedesc(struct filedesc *fdp);
+bool pwd_hold_smr(struct pwd *pwd);
struct pwd *pwd_hold(struct thread *td);
void pwd_drop(struct pwd *pwd);
static inline void
More information about the svn-src-all
mailing list