diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2013-10-10 11:00:29 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2013-10-10 11:00:29 +0000 |
commit | 49e3f17d4c8dd6ebd9d7e65468ea09e49838da5f (patch) | |
tree | cd76b4c4be03cb715dde4031b3500ed162e52a74 | |
parent | 929026206bb7ec352247a2031e29e0d63dd09071 (diff) |
A few fixes from Pedro Martelletto, adapted from
https://github.com/bitrig/bitrig/commits/pedro_tmpfs_fixes
7efd381ac3:
# mkdir -p x/y
# mv x/y/. z (or mv x/y/.. z)
(panic)
264ecd2c7b:
# mknod x b 100 100 (can be any block/character device)
# ls -lR /
(panic)
7da08d22fd:
# mkfifo x (or mknod x)
# mv x y
(panic)
af0666c65a:
# mount -t tmpfs -o -n16 tmpfs /mnt (create tmpfs with 16 inodes limit)
# cd /mnt
# touch x
# for i in `jot 100 1 100`; do ln -s x $i; done (create 100 symlinks, =
they "succeed" even though they failed)
# ls -lart
7e9296a6f8:
# mkdir x
# touch x/y
# chflags uappnd x (or sappnd)
# rm x/y
936b9cf257:
# mkdir -p x/y
# rmdir x/y/..
(panic)
de541406ef:
# touch x
# ln x y
# stat -f %c x
# sleep 10
# rm y
# stat -f %c x
okay guenther@, krw@
-rw-r--r-- | sys/tmpfs/tmpfs_fifoops.c | 3 | ||||
-rw-r--r-- | sys/tmpfs/tmpfs_specops.c | 3 | ||||
-rw-r--r-- | sys/tmpfs/tmpfs_vnops.c | 95 |
3 files changed, 74 insertions, 27 deletions
diff --git a/sys/tmpfs/tmpfs_fifoops.c b/sys/tmpfs/tmpfs_fifoops.c index ba6e2b8c9d2..217fdbbf0bc 100644 --- a/sys/tmpfs/tmpfs_fifoops.c +++ b/sys/tmpfs/tmpfs_fifoops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tmpfs_fifoops.c,v 1.2 2013/06/03 10:37:02 espie Exp $ */ +/* $OpenBSD: tmpfs_fifoops.c,v 1.3 2013/10/10 11:00:28 espie Exp $ */ /* $NetBSD: tmpfs_fifoops.c,v 1.9 2011/05/24 20:17:49 rmind Exp $ */ /* @@ -89,6 +89,7 @@ struct vops tmpfs_fifovops = { .vop_bmap = vop_generic_bmap, .vop_strategy = fifo_badop, .vop_print = tmpfs_print, + .vop_islocked = tmpfs_islocked, .vop_pathconf = fifo_pathconf, .vop_advlock = fifo_advlock, .vop_bwrite = tmpfs_bwrite, diff --git a/sys/tmpfs/tmpfs_specops.c b/sys/tmpfs/tmpfs_specops.c index cd298d5f3ed..e0165bcfc62 100644 --- a/sys/tmpfs/tmpfs_specops.c +++ b/sys/tmpfs/tmpfs_specops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tmpfs_specops.c,v 1.2 2013/06/03 10:37:02 espie Exp $ */ +/* $OpenBSD: tmpfs_specops.c,v 1.3 2013/10/10 11:00:28 espie Exp $ */ /* $NetBSD: tmpfs_specops.c,v 1.10 2011/05/24 20:17:49 rmind Exp $ */ /* @@ -88,6 +88,7 @@ struct vops tmpfs_specvops = { .vop_bmap = vop_generic_bmap, .vop_strategy = spec_strategy, .vop_print = tmpfs_print, + .vop_islocked = tmpfs_islocked, .vop_pathconf = spec_pathconf, .vop_advlock = spec_advlock, .vop_bwrite = vop_generic_bwrite, diff --git a/sys/tmpfs/tmpfs_vnops.c b/sys/tmpfs/tmpfs_vnops.c index 892e9cd645a..7b9b5c883d8 100644 --- a/sys/tmpfs/tmpfs_vnops.c +++ b/sys/tmpfs/tmpfs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tmpfs_vnops.c,v 1.8 2013/09/22 03:34:31 guenther Exp $ */ +/* $OpenBSD: tmpfs_vnops.c,v 1.9 2013/10/10 11:00:28 espie Exp $ */ /* $NetBSD: tmpfs_vnops.c,v 1.100 2012/11/05 17:27:39 dholland Exp $ */ /* @@ -166,9 +166,15 @@ tmpfs_lookup(void *v) /* * Lookup of ".." case. */ - if (lastcn && cnp->cn_nameiop == RENAME) { - error = EINVAL; - goto out; + if (lastcn) { + if (cnp->cn_nameiop == RENAME) { + error = EINVAL; + goto out; + } + if (cnp->cn_nameiop == DELETE) { + /* Keep the name for tmpfs_rmdir(). */ + cnp->cn_flags |= SAVENAME; + } } KASSERT(dnode->tn_type == VDIR); pnode = dnode->tn_spec.tn_dir.tn_parent; @@ -353,15 +359,7 @@ tmpfs_mknod(void *v) if (error) return error; - /* - * As in ufs_mknod(), remove inode so that it will be reloaded by - * VFS_VGET and checked to see if it is an alias of an existing entry - * in the vnode cache. - */ vput(*vpp); - (*vpp)->v_type = VNON; - vgone(*vpp); - *vpp = NULL; return 0; } @@ -689,7 +687,7 @@ tmpfs_remove(void *v) } */ *ap = v; struct vnode *dvp = ap->a_dvp, *vp = ap->a_vp; struct componentname *cnp = ap->a_cnp; - tmpfs_node_t *node; + tmpfs_node_t *dnode, *node; tmpfs_dirent_t *de; int error; @@ -701,6 +699,8 @@ tmpfs_remove(void *v) error = EPERM; goto out; } + + dnode = VP_TO_TMPFS_NODE(dvp); node = VP_TO_TMPFS_NODE(vp); /* Files marked as immutable or append-only cannot be deleted. */ @@ -709,6 +709,15 @@ tmpfs_remove(void *v) goto out; } + /* + * Likewise, files residing on directories marked as append-only cannot + * be deleted. + */ + if (dnode->tn_flags & APPEND) { + error = EPERM; + goto out; + } + /* Lookup the directory entry (check the cached hint first). */ de = tmpfs_dir_cached(node); if (de == NULL) { @@ -729,6 +738,10 @@ tmpfs_remove(void *v) tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT); else tmpfs_free_dirent(VFS_TO_TMPFS(vp->v_mount), de); + if (node->tn_links > 0) { + /* We removed a hard link. */ + tmpfs_update(node, TMPFS_NODE_CHANGED); + } error = 0; out: pool_put(&namei_pool, cnp->cn_pnbuf); @@ -856,9 +869,16 @@ tmpfs_rmdir(void *v) KASSERT(VOP_ISLOCKED(dvp)); KASSERT(VOP_ISLOCKED(vp)); - KASSERT(node->tn_spec.tn_dir.tn_parent == dnode); KASSERT(cnp->cn_flags & HASBUF); + if (cnp->cn_namelen == 2 && cnp->cn_nameptr[0] == '.' && + cnp->cn_nameptr[1] == '.') { + error = ENOTEMPTY; + goto out; + } + + KASSERT(node->tn_spec.tn_dir.tn_parent == dnode); + /* * Directories with more than two non-whiteout * entries ('.' and '..') cannot be removed. @@ -948,7 +968,7 @@ tmpfs_symlink(void *v) if (error == 0) vput(*vpp); - return 0; + return error; } int @@ -1437,6 +1457,7 @@ int tmpfs_check_sticky(struct ucred *, struct tmpfs_node *, struct tmpfs_node *); void tmpfs_rename_cache_purge(struct vnode *, struct vnode *, struct vnode *, struct vnode *); +void tmpfs_rename_abort(void *); int tmpfs_rename(void *v) @@ -1482,20 +1503,21 @@ tmpfs_rename(void *v) */ if (fvp->v_mount != tdvp->v_mount || (tvp != NULL && (fvp->v_mount != tvp->v_mount))) { - VOP_ABORTOP(tdvp, tcnp); - if (tdvp == tvp) - vrele(tdvp); - else - vput(tdvp); - if (tvp != NULL) - vput(tvp); - VOP_ABORTOP(fdvp, fcnp); - vrele(fdvp); - vrele(fvp); + tmpfs_rename_abort(v); return EXDEV; } /* + * Reject renaming '.' and '..'. + */ + if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || + (fcnp->cn_namelen == 2 && fcnp->cn_nameptr[0] == '.' && + fcnp->cn_nameptr[1] == '.')) { + tmpfs_rename_abort(v); + return EINVAL; + } + + /* * Sanitize our world from the VFS insanity. Unlock the target * directory and node, which are locked. Release the children, * which are referenced. Check for rename("x", "y/."), which @@ -2698,3 +2720,26 @@ tmpfs_rename_cache_purge(struct vnode *fdvp, struct vnode *fvp, if ((tvp != NULL) && (tvp->v_type == VDIR)) cache_purge(tvp); } + +void +tmpfs_rename_abort(void *v) +{ + struct vop_rename_args *ap = v; + struct vnode *fdvp = ap->a_fdvp; + struct vnode *fvp = ap->a_fvp; + struct componentname *fcnp = ap->a_fcnp; + struct vnode *tdvp = ap->a_tdvp; + struct vnode *tvp = ap->a_tvp; + struct componentname *tcnp = ap->a_tcnp; + + VOP_ABORTOP(tdvp, tcnp); + if (tdvp == tvp) + vrele(tdvp); + else + vput(tdvp); + if (tvp != NULL) + vput(tvp); + VOP_ABORTOP(fdvp, fcnp); + vrele(fdvp); + vrele(fvp); +} |