Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/fs/tmpfs/tmpfs_vnops.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/fs/tmpfs/tmpfs_vnops.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.92 retrieving revision 1.92.2.3 diff -u -p -r1.92 -r1.92.2.3 --- src/sys/fs/tmpfs/tmpfs_vnops.c 2011/09/27 01:32:21 1.92 +++ src/sys/fs/tmpfs/tmpfs_vnops.c 2012/04/17 00:08:20 1.92.2.3 @@ -1,4 +1,4 @@ -/* $NetBSD: tmpfs_vnops.c,v 1.92 2011/09/27 01:32:21 christos Exp $ */ +/* $NetBSD: tmpfs_vnops.c,v 1.92.2.3 2012/04/17 00:08:20 yamt Exp $ */ /* * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.92 2011/09/27 01:32:21 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.92.2.3 2012/04/17 00:08:20 yamt Exp $"); #include #include @@ -253,27 +253,19 @@ tmpfs_lookup(void *v) /* Check the permissions. */ if (lastcn && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { - kauth_action_t action = 0; - - /* This is the file-system's decision. */ - if ((dnode->tn_mode & S_ISTXT) != 0 && - kauth_cred_geteuid(cnp->cn_cred) != dnode->tn_uid && - kauth_cred_geteuid(cnp->cn_cred) != tnode->tn_uid) { - error = EPERM; - } else { - error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred); - } - - if (cnp->cn_nameiop == DELETE) { - action |= KAUTH_VNODE_DELETE; - } else { - KASSERT(cnp->cn_nameiop == RENAME); - action |= KAUTH_VNODE_RENAME; - } - error = kauth_authorize_vnode(cnp->cn_cred, - action, *vpp, dvp, error); - if (error) { + error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred); + if (error) goto out; + + if ((dnode->tn_mode & S_ISTXT) != 0) { + error = kauth_authorize_vnode(cnp->cn_cred, + KAUTH_VNODE_DELETE, tnode->tn_vnode, + dnode->tn_vnode, genfs_can_sticky(cnp->cn_cred, + dnode->tn_uid, tnode->tn_uid)); + if (error) { + error = EPERM; + goto out; + } } } @@ -382,11 +374,23 @@ tmpfs_close(void *v) return 0; } -static int -tmpfs_check_possible(vnode_t *vp, tmpfs_node_t *node, mode_t mode) +int +tmpfs_access(void *v) { + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + kauth_cred_t a_cred; + } */ *ap = v; + vnode_t *vp = ap->a_vp; + mode_t mode = ap->a_mode; + kauth_cred_t cred = ap->a_cred; + tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp); const bool writing = (mode & VWRITE) != 0; + KASSERT(VOP_ISLOCKED(vp)); + + /* Possible? */ switch (vp->v_type) { case VDIR: case VLNK: @@ -403,41 +407,13 @@ tmpfs_check_possible(vnode_t *vp, tmpfs_ default: return EINVAL; } - return (writing && (node->tn_flags & IMMUTABLE) != 0) ? EPERM : 0; -} - -static int -tmpfs_check_permitted(vnode_t *vp, tmpfs_node_t *node, mode_t mode, - kauth_cred_t cred) -{ - - return genfs_can_access(vp->v_type, node->tn_mode, node->tn_uid, - node->tn_gid, mode, cred); -} - -int -tmpfs_access(void *v) -{ - struct vop_access_args /* { - struct vnode *a_vp; - int a_mode; - kauth_cred_t a_cred; - } */ *ap = v; - vnode_t *vp = ap->a_vp; - mode_t mode = ap->a_mode; - kauth_cred_t cred = ap->a_cred; - tmpfs_node_t *node; - int error; - - KASSERT(VOP_ISLOCKED(vp)); - - node = VP_TO_TMPFS_NODE(vp); - error = tmpfs_check_possible(vp, node, mode); - if (error) { - return error; + if (writing && (node->tn_flags & IMMUTABLE) != 0) { + return EPERM; } - return kauth_authorize_vnode(cred, kauth_mode_to_action(mode), vp, - NULL, tmpfs_check_permitted(vp, node, mode, cred)); + + return kauth_authorize_vnode(cred, kauth_access_action(mode, + vp->v_type, node->tn_mode), vp, NULL, genfs_can_access(vp->v_type, + node->tn_mode, node->tn_uid, node->tn_gid, mode, cred)); } int @@ -545,6 +521,7 @@ tmpfs_read(void *v) const int ioflag = ap->a_ioflag; tmpfs_node_t *node; struct uvm_object *uobj; + const int advice = IO_ADV_DECODE(ioflag); int error; KASSERT(VOP_ISLOCKED(vp)); @@ -561,6 +538,9 @@ tmpfs_read(void *v) uobj = node->tn_spec.tn_reg.tn_aobj; error = 0; + if (uio->uio_offset + uio->uio_resid <= node->tn_size) { + uvm_loanobj(&vp->v_uobj, uio, advice); + } while (error == 0 && uio->uio_resid > 0) { vsize_t len; @@ -571,7 +551,7 @@ tmpfs_read(void *v) if (len == 0) { break; } - error = ubc_uiomove(uobj, uio, len, IO_ADV_DECODE(ioflag), + error = ubc_uiomove(uobj, uio, len, advice, UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); } return error; @@ -2054,13 +2034,14 @@ tmpfs_check_sticky(kauth_cred_t cred, KASSERT((node == NULL) || (VOP_ISLOCKED(dnode->tn_vnode) == LK_EXCLUSIVE)); + if (node == NULL) + return 0; + if (dnode->tn_mode & S_ISTXT) { - uid_t euid = kauth_cred_geteuid(cred); - if (euid == dnode->tn_uid) - return 0; - if ((node == NULL) || (euid == node->tn_uid)) - return 0; - return EPERM; + if (kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, + node->tn_vnode, dnode->tn_vnode, genfs_can_sticky(cred, + dnode->tn_uid, node->tn_uid)) != 0) + return EPERM; } return 0; @@ -2218,6 +2199,10 @@ tmpfs_readdir(void *v) node = VP_TO_TMPFS_DIR(vp); startoff = uio->uio_offset; cnt = 0; + if (node->tn_links == 0) { + error = 0; + goto out; + } if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) { error = tmpfs_dir_getdotdent(node, uio); @@ -2465,8 +2450,11 @@ tmpfs_getpages(void *v) if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0) node->tn_status |= TMPFS_NODE_ACCESSED; - if ((access_type & VM_PROT_WRITE) != 0) + if ((access_type & VM_PROT_WRITE) != 0) { node->tn_status |= TMPFS_NODE_MODIFIED; + if (vp->v_mount->mnt_flag & MNT_RELATIME) + node->tn_status |= TMPFS_NODE_ACCESSED; + } } /*