diff options
author | 2015-06-11 08:39:51 +0000 | |
---|---|---|
committer | 2015-06-11 08:39:51 +0000 | |
commit | 3db678b80e3fd17a6522173c1fbf8171ea7ce4a3 (patch) | |
tree | a03a363d5ee302165fe3af34633ca4ba45eb1447 /sys/nfs | |
parent | remove uneeded pci includes (diff) | |
download | wireguard-openbsd-3db678b80e3fd17a6522173c1fbf8171ea7ce4a3.tar.xz wireguard-openbsd-3db678b80e3fd17a6522173c1fbf8171ea7ce4a3.zip |
Avoid double-free in error path by cribbing the HASBUF flag
logic from the rest of the kernel that deals with filename
lookups.
In snaps for some time.
Initially found by jsg@
Prodded by deraadt@
Diffstat (limited to 'sys/nfs')
-rw-r--r-- | sys/nfs/nfs_serv.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c index e4eaaec0375..5649c1866a8 100644 --- a/sys/nfs/nfs_serv.c +++ b/sys/nfs/nfs_serv.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_serv.c,v 1.103 2015/05/06 02:19:40 jsg Exp $ */ +/* $OpenBSD: nfs_serv.c,v 1.104 2015/06/11 08:39:51 blambert Exp $ */ /* $NetBSD: nfs_serv.c,v 1.34 1997/05/12 23:37:12 fvdl Exp $ */ /* @@ -879,7 +879,6 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, info.nmi_dpos = nfsd->nd_dpos; info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); - nd.ni_cnd.cn_nameiop = 0; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); @@ -979,7 +978,10 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, if (va.va_type != VFIFO && (error = suser_ucred(cred))) { vrele(nd.ni_startdir); - pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + if (nd.ni_cnd.cn_flags & HASBUF) { + pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; + } VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); vput(nd.ni_dvp); nfsm_reply(0); @@ -991,7 +993,10 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, &va); if (error) { vrele(nd.ni_startdir); - pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + if (nd.ni_cnd.cn_flags & HASBUF) { + pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; + } nfsm_reply(0); error = 0; goto nfsmout; @@ -1001,12 +1006,15 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nd.ni_cnd.cn_proc = procp; nd.ni_cnd.cn_cred = cred; if ((error = vfs_lookup(&nd)) != 0) { - pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + if (nd.ni_cnd.cn_flags & HASBUF) { + pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; + } nfsm_reply(0); error = 0; goto nfsmout; } - + pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); if (nd.ni_cnd.cn_flags & ISSYMLINK) { vrele(nd.ni_dvp); @@ -1020,6 +1028,7 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, } else { vrele(nd.ni_startdir); pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); vput(nd.ni_dvp); error = ENXIO; @@ -1028,6 +1037,7 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, } else { vrele(nd.ni_startdir); pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; vp = nd.ni_vp; if (nd.ni_dvp == vp) vrele(nd.ni_dvp); @@ -1081,9 +1091,12 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsmout: if (dirp) vrele(dirp); - if (nd.ni_cnd.cn_nameiop) { + if (nd.ni_cnd.cn_nameiop != LOOKUP) { vrele(nd.ni_startdir); - pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + if (nd.ni_cnd.cn_flags & HASBUF) { + pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); + nd.ni_cnd.cn_flags &= ~HASBUF; + } } VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) |