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.
This commit is contained in:
parent
9e9be081d8
commit
4e2266100d
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user