version 1.350, 2008/04/25 13:40:55 |
version 1.350.2.9, 2010/10/09 03:32:33 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/*- |
/*- |
* Copyright (c) 2008 The NetBSD Foundation, Inc. |
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. |
* All rights reserved. |
* All rights reserved. |
* |
* |
|
* This code is derived from software contributed to The NetBSD Foundation |
|
* by Andrew Doran. |
|
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
* are met: |
* are met: |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by the NetBSD |
|
* Foundation, Inc. and its contributors. |
|
* 4. Neither the name of The NetBSD Foundation nor the names of its |
|
* contributors may be used to endorse or promote products derived |
|
* from this software without specific prior written permission. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
#include "opt_compat_netbsd.h" |
#ifdef _KERNEL_OPT |
#include "opt_compat_43.h" |
|
#include "opt_fileassoc.h" |
#include "opt_fileassoc.h" |
#include "fss.h" |
|
#include "veriexec.h" |
#include "veriexec.h" |
|
#endif |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
Line 89 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 84 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/mount.h> |
#include <sys/mount.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
#include <sys/uio.h> |
#include <sys/uio.h> |
#include <sys/malloc.h> |
|
#include <sys/kmem.h> |
#include <sys/kmem.h> |
#include <sys/dirent.h> |
#include <sys/dirent.h> |
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
Line 102 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 96 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/verified_exec.h> |
#include <sys/verified_exec.h> |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
#include <sys/atomic.h> |
#include <sys/atomic.h> |
|
#include <sys/module.h> |
|
#include <sys/buf.h> |
|
|
#include <miscfs/genfs/genfs.h> |
#include <miscfs/genfs/genfs.h> |
#include <miscfs/syncfs/syncfs.h> |
#include <miscfs/syncfs/syncfs.h> |
#include <miscfs/specfs/specdev.h> |
#include <miscfs/specfs/specdev.h> |
|
|
#ifdef COMPAT_30 |
|
#include "opt_nfsserver.h" |
|
#include <nfs/rpcv2.h> |
#include <nfs/rpcv2.h> |
#endif |
|
#include <nfs/nfsproto.h> |
#include <nfs/nfsproto.h> |
#ifdef COMPAT_30 |
|
#include <nfs/nfs.h> |
#include <nfs/nfs.h> |
#include <nfs/nfs_var.h> |
#include <nfs/nfs_var.h> |
#endif |
|
|
|
#if NFSS > 0 |
|
#include <dev/fssvar.h> |
|
#endif |
|
|
|
MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct"); |
MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct"); |
|
|
static int change_dir(struct nameidata *, struct lwp *); |
|
static int change_flags(struct vnode *, u_long, struct lwp *); |
static int change_flags(struct vnode *, u_long, struct lwp *); |
static int change_mode(struct vnode *, int, struct lwp *l); |
static int change_mode(struct vnode *, int, struct lwp *l); |
static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int); |
static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int); |
|
|
void checkdirs(struct vnode *); |
void checkdirs(struct vnode *); |
|
|
int dovfsusermount = 0; |
|
|
|
/* |
/* |
* Virtual File System System Calls |
* Virtual File System System Calls |
*/ |
*/ |
Line 140 int dovfsusermount = 0; |
|
Line 124 int dovfsusermount = 0; |
|
* Mount a file system. |
* Mount a file system. |
*/ |
*/ |
|
|
#if defined(COMPAT_09) || defined(COMPAT_43) |
|
/* |
/* |
* This table is used to maintain compatibility with 4.3BSD |
* This table is used to maintain compatibility with 4.3BSD |
* and NetBSD 0.9 mount syscalls. Note, the order is important! |
* and NetBSD 0.9 mount syscalls - and possibly other systems. |
|
* Note, the order is important! |
* |
* |
* Do not modify this table. It should only contain filesystems |
* Do not modify this table. It should only contain filesystems |
* supported by NetBSD 0.9 and 4.3BSD. |
* supported by NetBSD 0.9 and 4.3BSD. |
Line 162 const char * const mountcompatnames[] = |
|
Line 146 const char * const mountcompatnames[] = |
|
}; |
}; |
const int nmountcompatnames = sizeof(mountcompatnames) / |
const int nmountcompatnames = sizeof(mountcompatnames) / |
sizeof(mountcompatnames[0]); |
sizeof(mountcompatnames[0]); |
#endif /* COMPAT_09 || COMPAT_43 */ |
|
|
|
static int |
static int |
mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags, |
mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags, |
Line 182 mount_update(struct lwp *l, struct vnode |
|
Line 165 mount_update(struct lwp *l, struct vnode |
|
|
|
/* |
/* |
* We only allow the filesystem to be reloaded if it |
* We only allow the filesystem to be reloaded if it |
* is currently mounted read-only. |
* is currently mounted read-only. Additionally, we |
|
* prevent read-write to read-only downgrades. |
*/ |
*/ |
if (flags & MNT_RELOAD && !(mp->mnt_flag & MNT_RDONLY)) { |
if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 && |
|
(mp->mnt_flag & MNT_RDONLY) == 0) { |
error = EOPNOTSUPP; /* Needs translation */ |
error = EOPNOTSUPP; /* Needs translation */ |
goto out; |
goto out; |
} |
} |
Line 194 mount_update(struct lwp *l, struct vnode |
|
Line 179 mount_update(struct lwp *l, struct vnode |
|
if (error) |
if (error) |
goto out; |
goto out; |
|
|
if (vfs_trybusy(mp, RW_WRITER, 0)) { |
if (vfs_busy(mp, NULL)) { |
error = EPERM; |
error = EPERM; |
goto out; |
goto out; |
} |
} |
|
|
|
mutex_enter(&mp->mnt_updating); |
|
|
mp->mnt_flag &= ~MNT_OP_FLAGS; |
mp->mnt_flag &= ~MNT_OP_FLAGS; |
mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); |
mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); |
|
|
Line 212 mount_update(struct lwp *l, struct vnode |
|
Line 199 mount_update(struct lwp *l, struct vnode |
|
mp->mnt_flag &= |
mp->mnt_flag &= |
~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | |
~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | |
MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | |
MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | |
MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP); |
MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP | |
|
MNT_LOG); |
mp->mnt_flag |= flags & |
mp->mnt_flag |= flags & |
(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | |
(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | |
MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | |
MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | |
MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP | |
MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP | |
MNT_IGNORE); |
MNT_LOG | MNT_IGNORE); |
|
|
error = VFS_MOUNT(mp, path, data, data_len); |
error = VFS_MOUNT(mp, path, data, data_len); |
|
|
#if defined(COMPAT_30) && defined(NFSSERVER) |
|
if (error && data != NULL) { |
if (error && data != NULL) { |
int error2; |
int error2; |
|
|
/* Update failed; let's try and see if it was an |
/* |
* export request. */ |
* Update failed; let's try and see if it was an |
error2 = nfs_update_exports_30(mp, path, data, l); |
* export request. For compat with 3.0 and earlier. |
|
*/ |
|
error2 = vfs_hooks_reexport(mp, path, data); |
|
|
/* Only update error code if the export request was |
/* |
|
* Only update error code if the export request was |
* understood but some problem occurred while |
* understood but some problem occurred while |
* processing it. */ |
* processing it. |
|
*/ |
if (error2 != EJUSTRETURN) |
if (error2 != EJUSTRETURN) |
error = error2; |
error = error2; |
} |
} |
#endif |
|
if (mp->mnt_iflag & IMNT_WANTRDWR) |
if (mp->mnt_iflag & IMNT_WANTRDWR) |
mp->mnt_flag &= ~MNT_RDONLY; |
mp->mnt_flag &= ~MNT_RDONLY; |
if (error) |
if (error) |
Line 249 mount_update(struct lwp *l, struct vnode |
|
Line 240 mount_update(struct lwp *l, struct vnode |
|
if (mp->mnt_syncer != NULL) |
if (mp->mnt_syncer != NULL) |
vfs_deallocate_syncvnode(mp); |
vfs_deallocate_syncvnode(mp); |
} |
} |
vfs_unbusy(mp, false); |
mutex_exit(&mp->mnt_updating); |
|
vfs_unbusy(mp, false, NULL); |
|
|
out: |
out: |
return (error); |
return (error); |
Line 264 mount_get_vfsops(const char *fstype, str |
|
Line 256 mount_get_vfsops(const char *fstype, str |
|
/* Copy file-system type from userspace. */ |
/* Copy file-system type from userspace. */ |
error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL); |
error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL); |
if (error) { |
if (error) { |
#if defined(COMPAT_09) || defined(COMPAT_43) |
|
/* |
/* |
* Historically, filesystem types were identified by numbers. |
* Historically, filesystem types were identified by numbers. |
* If we get an integer for the filesystem type instead of a |
* If we get an integer for the filesystem type instead of a |
Line 277 mount_get_vfsops(const char *fstype, str |
|
Line 268 mount_get_vfsops(const char *fstype, str |
|
return ENODEV; |
return ENODEV; |
strlcpy(fstypename, mountcompatnames[fsindex], |
strlcpy(fstypename, mountcompatnames[fsindex], |
sizeof(fstypename)); |
sizeof(fstypename)); |
#else |
|
return error; |
|
#endif |
|
} |
} |
|
|
#ifdef COMPAT_10 |
/* Accept `ufs' as an alias for `ffs', for compatibility. */ |
/* Accept `ufs' as an alias for `ffs'. */ |
|
if (strcmp(fstypename, "ufs") == 0) |
if (strcmp(fstypename, "ufs") == 0) |
fstypename[0] = 'f'; |
fstypename[0] = 'f'; |
#endif |
|
|
|
if ((*vfsops = vfs_getopsbyname(fstypename)) == NULL) |
if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) |
return ENODEV; |
return 0; |
return 0; |
|
|
/* If we can autoload a vfs module, try again */ |
|
(void)module_autoload(fstypename, MODULE_CLASS_VFS); |
|
|
|
if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) |
|
return 0; |
|
|
|
return ENODEV; |
} |
} |
|
|
static int |
static int |
mount_domount(struct lwp *l, struct vnode **vpp, struct vfsops *vfsops, |
mount_domount(struct lwp *l, struct vnode **vpp, struct vfsops *vfsops, |
const char *path, int flags, void *data, size_t *data_len, u_int recurse) |
const char *path, int flags, void *data, size_t *data_len) |
{ |
{ |
struct mount *mp = NULL; |
struct mount *mp; |
struct vnode *vp = *vpp; |
struct vnode *vp = *vpp; |
struct vattr va; |
struct vattr va; |
|
struct nameidata nd; |
int error; |
int error; |
|
|
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, |
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, |
KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, KAUTH_ARG(flags), data); |
KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, KAUTH_ARG(flags), data); |
if (error) |
if (error) { |
|
vfs_delref(vfsops); |
return error; |
return error; |
|
} |
|
|
/* Can't make a non-dir a mount-point (from here anyway). */ |
/* Can't make a non-dir a mount-point (from here anyway). */ |
if (vp->v_type != VDIR) |
if (vp->v_type != VDIR) { |
|
vfs_delref(vfsops); |
return ENOTDIR; |
return ENOTDIR; |
|
} |
|
|
/* |
/* |
* If the user is not root, ensure that they own the directory |
* If the user is not root, ensure that they own the directory |
* onto which we are attempting to mount. |
* onto which we are attempting to mount. |
*/ |
*/ |
if ((error = VOP_GETATTR(vp, &va, l->l_cred)) != 0 || |
vn_lock(vp, LK_SHARED | LK_RETRY); |
(va.va_uid != kauth_cred_geteuid(l->l_cred) && |
error = VOP_GETATTR(vp, &va, l->l_cred); |
|
VOP_UNLOCK(vp); |
|
if (error != 0) { |
|
vfs_delref(vfsops); |
|
return error; |
|
} |
|
if ((va.va_uid != kauth_cred_geteuid(l->l_cred) && |
(error = kauth_authorize_generic(l->l_cred, |
(error = kauth_authorize_generic(l->l_cred, |
KAUTH_GENERIC_ISSUSER, NULL)) != 0)) { |
KAUTH_GENERIC_ISSUSER, NULL)) != 0)) { |
|
vfs_delref(vfsops); |
return error; |
return error; |
} |
} |
|
|
if (flags & MNT_EXPORTED) |
if (flags & MNT_EXPORTED) { |
|
vfs_delref(vfsops); |
return EINVAL; |
return EINVAL; |
|
} |
|
|
if ((error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0)) != 0) |
if ((mp = vfs_mountalloc(vfsops, vp)) == NULL) { |
return error; |
vfs_delref(vfsops); |
|
|
/* |
|
* Check if a file-system is not already mounted on this vnode. |
|
*/ |
|
if (vp->v_mountedhere != NULL) |
|
return EBUSY; |
|
|
|
mp = kmem_zalloc(sizeof(*mp), KM_SLEEP); |
|
if (mp == NULL) |
|
return ENOMEM; |
return ENOMEM; |
|
} |
|
|
mp->mnt_op = vfsops; |
|
mp->mnt_refcnt = 1; |
|
|
|
TAILQ_INIT(&mp->mnt_vnodelist); |
|
rw_init(&mp->mnt_lock); |
|
mutex_init(&mp->mnt_renamelock, MUTEX_DEFAULT, IPL_NONE); |
|
(void)vfs_busy(mp, RW_WRITER, 0); |
|
|
|
mp->mnt_vnodecovered = vp; |
|
mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred); |
mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred); |
mount_initspecific(mp); |
|
|
|
/* |
/* |
* The underlying file system may refuse the mount for |
* The underlying file system may refuse the mount for |
Line 360 mount_domount(struct lwp *l, struct vnod |
|
Line 349 mount_domount(struct lwp *l, struct vnod |
|
(MNT_FORCE | MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | |
(MNT_FORCE | MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | |
MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | |
MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | |
MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP | |
MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP | |
MNT_IGNORE | MNT_RDONLY); |
MNT_LOG | MNT_IGNORE | MNT_RDONLY); |
|
|
|
mutex_enter(&mp->mnt_updating); |
error = VFS_MOUNT(mp, path, data, data_len); |
error = VFS_MOUNT(mp, path, data, data_len); |
mp->mnt_flag &= ~MNT_OP_FLAGS; |
mp->mnt_flag &= ~MNT_OP_FLAGS; |
|
|
|
if (error != 0) |
|
goto err_unmounted; |
|
|
/* |
/* |
* Put the new filesystem on the mount list after root. |
* Validate and prepare the mount point. |
*/ |
*/ |
cache_purge(vp); |
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, |
|
UIO_USERSPACE, path); |
|
error = namei(&nd); |
if (error != 0) { |
if (error != 0) { |
vp->v_mountedhere = NULL; |
goto err_mounted; |
mp->mnt_op->vfs_refcount--; |
} |
vfs_unbusy(mp, false); |
if (nd.ni_vp != vp) { |
vfs_destroy(mp); |
vput(nd.ni_vp); |
return error; |
error = EINVAL; |
|
goto err_mounted; |
|
} |
|
if (vp->v_mountedhere != NULL) { |
|
vput(nd.ni_vp); |
|
error = EBUSY; |
|
goto err_mounted; |
|
} |
|
error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0); |
|
if (error != 0) { |
|
vput(nd.ni_vp); |
|
goto err_mounted; |
} |
} |
|
|
|
/* |
|
* Put the new filesystem on the mount list after root. |
|
*/ |
|
cache_purge(vp); |
mp->mnt_iflag &= ~IMNT_WANTRDWR; |
mp->mnt_iflag &= ~IMNT_WANTRDWR; |
|
|
mutex_enter(&mountlist_lock); |
mutex_enter(&mountlist_lock); |
vp->v_mountedhere = mp; |
|
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); |
CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); |
mutex_exit(&mountlist_lock); |
mutex_exit(&mountlist_lock); |
vn_restorerecurse(vp, recurse); |
|
VOP_UNLOCK(vp, 0); |
|
checkdirs(vp); |
|
if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) |
if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) |
error = vfs_allocate_syncvnode(mp); |
error = vfs_allocate_syncvnode(mp); |
|
if (error == 0) |
|
vp->v_mountedhere = mp; |
|
vput(nd.ni_vp); |
|
if (error != 0) |
|
goto err_onmountlist; |
|
|
|
checkdirs(vp); |
|
mutex_exit(&mp->mnt_updating); |
|
|
/* Hold an additional reference to the mount across VFS_START(). */ |
/* Hold an additional reference to the mount across VFS_START(). */ |
vfs_unbusy(mp, true); |
vfs_unbusy(mp, true, NULL); |
(void) VFS_STATVFS(mp, &mp->mnt_stat); |
(void) VFS_STATVFS(mp, &mp->mnt_stat); |
error = VFS_START(mp, 0); |
error = VFS_START(mp, 0); |
if (error) { |
if (error) |
vrele(vp); |
vrele(vp); |
vfs_destroy(mp); |
|
} |
|
/* Drop reference held for VFS_START(). */ |
/* Drop reference held for VFS_START(). */ |
vfs_destroy(mp); |
vfs_destroy(mp); |
*vpp = NULL; |
*vpp = NULL; |
return error; |
return error; |
|
|
|
err_onmountlist: |
|
mutex_enter(&mountlist_lock); |
|
CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); |
|
mp->mnt_iflag |= IMNT_GONE; |
|
mutex_exit(&mountlist_lock); |
|
|
|
err_mounted: |
|
if (VFS_UNMOUNT(mp, MNT_FORCE) != 0) |
|
panic("Unmounting fresh file system failed"); |
|
|
|
err_unmounted: |
|
vp->v_mountedhere = NULL; |
|
mutex_exit(&mp->mnt_updating); |
|
vfs_unbusy(mp, false, NULL); |
|
vfs_destroy(mp); |
|
|
|
return error; |
} |
} |
|
|
static int |
static int |
Line 423 mount_getargs(struct lwp *l, struct vnod |
|
Line 455 mount_getargs(struct lwp *l, struct vnod |
|
if ((vp->v_vflag & VV_ROOT) == 0) |
if ((vp->v_vflag & VV_ROOT) == 0) |
return EINVAL; |
return EINVAL; |
|
|
if (vfs_trybusy(mp, RW_WRITER, NULL)) |
if (vfs_busy(mp, NULL)) |
return EPERM; |
return EPERM; |
|
|
|
mutex_enter(&mp->mnt_updating); |
mp->mnt_flag &= ~MNT_OP_FLAGS; |
mp->mnt_flag &= ~MNT_OP_FLAGS; |
mp->mnt_flag |= MNT_GETARGS; |
mp->mnt_flag |= MNT_GETARGS; |
error = VFS_MOUNT(mp, path, data, data_len); |
error = VFS_MOUNT(mp, path, data, data_len); |
mp->mnt_flag &= ~MNT_OP_FLAGS; |
mp->mnt_flag &= ~MNT_OP_FLAGS; |
|
mutex_exit(&mp->mnt_updating); |
|
|
vfs_unbusy(mp, false); |
vfs_unbusy(mp, false, NULL); |
return (error); |
return (error); |
} |
} |
|
|
#ifdef COMPAT_40 |
|
/* ARGSUSED */ |
|
int |
|
compat_40_sys_mount(struct lwp *l, const struct compat_40_sys_mount_args *uap, register_t *retval) |
|
{ |
|
/* { |
|
syscallarg(const char *) type; |
|
syscallarg(const char *) path; |
|
syscallarg(int) flags; |
|
syscallarg(void *) data; |
|
} */ |
|
register_t dummy; |
|
|
|
return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path), |
|
SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE, 0, &dummy); |
|
} |
|
#endif |
|
|
|
int |
int |
sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval) |
sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval) |
{ |
{ |
Line 475 do_sys_mount(struct lwp *l, struct vfsop |
|
Line 491 do_sys_mount(struct lwp *l, struct vfsop |
|
size_t data_len, register_t *retval) |
size_t data_len, register_t *retval) |
{ |
{ |
struct vnode *vp; |
struct vnode *vp; |
struct nameidata nd; |
|
void *data_buf = data; |
void *data_buf = data; |
u_int recurse; |
bool vfsopsrele = false; |
int error; |
int error; |
|
|
|
/* XXX: The calling convention of this routine is totally bizarre */ |
|
if (vfsops) |
|
vfsopsrele = true; |
|
|
/* |
/* |
* Get vnode to be covered |
* Get vnode to be covered |
*/ |
*/ |
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path); |
error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) { |
return (error); |
vp = NULL; |
vp = nd.ni_vp; |
goto done; |
|
} |
|
|
/* |
|
* A lookup in VFS_MOUNT might result in an attempt to |
|
* lock this vnode again, so make the lock recursive. |
|
*/ |
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
|
recurse = vn_setrecurse(vp); |
|
|
|
if (vfsops == NULL) { |
if (vfsops == NULL) { |
if (flags & (MNT_GETARGS | MNT_UPDATE)) |
if (flags & (MNT_GETARGS | MNT_UPDATE)) { |
vfsops = vp->v_mount->mnt_op; |
vfsops = vp->v_mount->mnt_op; |
else { |
} else { |
/* 'type' is userspace */ |
/* 'type' is userspace */ |
error = mount_get_vfsops(type, &vfsops); |
error = mount_get_vfsops(type, &vfsops); |
if (error != 0) |
if (error != 0) |
goto done; |
goto done; |
|
vfsopsrele = true; |
} |
} |
} |
} |
|
|
Line 511 do_sys_mount(struct lwp *l, struct vfsop |
|
Line 525 do_sys_mount(struct lwp *l, struct vfsop |
|
/* No length supplied, use default for filesystem */ |
/* No length supplied, use default for filesystem */ |
data_len = vfsops->vfs_min_mount_data; |
data_len = vfsops->vfs_min_mount_data; |
if (data_len > VFS_MAX_MOUNT_DATA) { |
if (data_len > VFS_MAX_MOUNT_DATA) { |
/* maybe a force loaded old LKM */ |
|
error = EINVAL; |
error = EINVAL; |
goto done; |
goto done; |
} |
} |
#ifdef COMPAT_30 |
/* |
/* Hopefully a longer buffer won't make copyin() fail */ |
* Hopefully a longer buffer won't make copyin() fail. |
|
* For compatibility with 3.0 and earlier. |
|
*/ |
if (flags & MNT_UPDATE |
if (flags & MNT_UPDATE |
&& data_len < sizeof (struct mnt_export_args30)) |
&& data_len < sizeof (struct mnt_export_args30)) |
data_len = sizeof (struct mnt_export_args30); |
data_len = sizeof (struct mnt_export_args30); |
#endif |
|
} |
} |
data_buf = malloc(data_len, M_TEMP, M_WAITOK); |
data_buf = kmem_alloc(data_len, KM_SLEEP); |
|
|
/* NFS needs the buffer even for mnt_getargs .... */ |
/* NFS needs the buffer even for mnt_getargs .... */ |
error = copyin(data, data_buf, data_len); |
error = copyin(data, data_buf, data_len); |
Line 545 do_sys_mount(struct lwp *l, struct vfsop |
|
Line 559 do_sys_mount(struct lwp *l, struct vfsop |
|
error = mount_update(l, vp, path, flags, data_buf, &data_len); |
error = mount_update(l, vp, path, flags, data_buf, &data_len); |
} else { |
} else { |
/* Locking is handled internally in mount_domount(). */ |
/* Locking is handled internally in mount_domount(). */ |
|
KASSERT(vfsopsrele == true); |
error = mount_domount(l, &vp, vfsops, path, flags, data_buf, |
error = mount_domount(l, &vp, vfsops, path, flags, data_buf, |
&data_len, recurse); |
&data_len); |
|
vfsopsrele = false; |
} |
} |
|
|
done: |
done: |
|
if (vfsopsrele) |
|
vfs_delref(vfsops); |
if (vp != NULL) { |
if (vp != NULL) { |
vn_restorerecurse(vp, recurse); |
vrele(vp); |
vput(vp); |
|
} |
} |
if (data_buf != data) |
if (data_buf != data) |
free(data_buf, M_TEMP); |
kmem_free(data_buf, data_len); |
return (error); |
return (error); |
} |
} |
|
|
|
|
checkdirs(struct vnode *olddp) |
checkdirs(struct vnode *olddp) |
{ |
{ |
struct cwdinfo *cwdi; |
struct cwdinfo *cwdi; |
struct vnode *newdp; |
struct vnode *newdp, *rele1, *rele2; |
struct proc *p; |
struct proc *p; |
|
bool retry; |
|
|
if (olddp->v_usecount == 1) |
if (olddp->v_usecount == 1) |
return; |
return; |
if (VFS_ROOT(olddp->v_mountedhere, &newdp)) |
if (VFS_ROOT(olddp->v_mountedhere, &newdp)) |
panic("mount: lost mount"); |
panic("mount: lost mount"); |
mutex_enter(proc_lock); |
|
/* XXXAD Should not be acquiring these locks with proc_lock held!! */ |
do { |
PROCLIST_FOREACH(p, &allproc) { |
retry = false; |
cwdi = p->p_cwdi; |
mutex_enter(proc_lock); |
if (!cwdi) |
PROCLIST_FOREACH(p, &allproc) { |
continue; |
if ((cwdi = p->p_cwdi) == NULL) |
rw_enter(&cwdi->cwdi_lock, RW_WRITER); |
continue; |
if (cwdi->cwdi_cdir == olddp) { |
/* |
vrele(cwdi->cwdi_cdir); |
* Can't change to the old directory any more, |
VREF(newdp); |
* so even if we see a stale value it's not a |
cwdi->cwdi_cdir = newdp; |
* problem. |
} |
*/ |
if (cwdi->cwdi_rdir == olddp) { |
if (cwdi->cwdi_cdir != olddp && |
vrele(cwdi->cwdi_rdir); |
cwdi->cwdi_rdir != olddp) |
VREF(newdp); |
continue; |
cwdi->cwdi_rdir = newdp; |
retry = true; |
|
rele1 = NULL; |
|
rele2 = NULL; |
|
atomic_inc_uint(&cwdi->cwdi_refcnt); |
|
mutex_exit(proc_lock); |
|
rw_enter(&cwdi->cwdi_lock, RW_WRITER); |
|
if (cwdi->cwdi_cdir == olddp) { |
|
rele1 = cwdi->cwdi_cdir; |
|
vref(newdp); |
|
cwdi->cwdi_cdir = newdp; |
|
} |
|
if (cwdi->cwdi_rdir == olddp) { |
|
rele2 = cwdi->cwdi_rdir; |
|
vref(newdp); |
|
cwdi->cwdi_rdir = newdp; |
|
} |
|
rw_exit(&cwdi->cwdi_lock); |
|
cwdfree(cwdi); |
|
if (rele1 != NULL) |
|
vrele(rele1); |
|
if (rele2 != NULL) |
|
vrele(rele2); |
|
mutex_enter(proc_lock); |
|
break; |
} |
} |
rw_exit(&cwdi->cwdi_lock); |
mutex_exit(proc_lock); |
} |
} while (retry); |
mutex_exit(proc_lock); |
|
if (rootvnode == olddp) { |
if (rootvnode == olddp) { |
vrele(rootvnode); |
vrele(rootvnode); |
VREF(newdp); |
vref(newdp); |
rootvnode = newdp; |
rootvnode = newdp; |
} |
} |
vput(newdp); |
vput(newdp); |
Line 628 sys_unmount(struct lwp *l, const struct |
|
Line 669 sys_unmount(struct lwp *l, const struct |
|
return (error); |
return (error); |
vp = nd.ni_vp; |
vp = nd.ni_vp; |
mp = vp->v_mount; |
mp = vp->v_mount; |
VOP_UNLOCK(vp, 0); |
atomic_inc_uint(&mp->mnt_refcnt); |
|
VOP_UNLOCK(vp); |
|
|
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, |
error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, |
KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL); |
KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL); |
if (error) { |
if (error) { |
vrele(vp); |
vrele(vp); |
|
vfs_destroy(mp); |
return (error); |
return (error); |
} |
} |
|
|
Line 642 sys_unmount(struct lwp *l, const struct |
|
Line 685 sys_unmount(struct lwp *l, const struct |
|
*/ |
*/ |
if (mp->mnt_flag & MNT_ROOTFS) { |
if (mp->mnt_flag & MNT_ROOTFS) { |
vrele(vp); |
vrele(vp); |
|
vfs_destroy(mp); |
return (EINVAL); |
return (EINVAL); |
} |
} |
|
|
Line 650 sys_unmount(struct lwp *l, const struct |
|
Line 694 sys_unmount(struct lwp *l, const struct |
|
*/ |
*/ |
if ((vp->v_vflag & VV_ROOT) == 0) { |
if ((vp->v_vflag & VV_ROOT) == 0) { |
vrele(vp); |
vrele(vp); |
|
vfs_destroy(mp); |
return (EINVAL); |
return (EINVAL); |
} |
} |
|
|
/* |
|
* XXX Freeze syncer. Must do this before locking the |
|
* mount point. See dounmount() for details. |
|
*/ |
|
mutex_enter(&syncer_mutex); |
|
error = vfs_busy(mp, RW_WRITER, NULL); |
|
vrele(vp); |
vrele(vp); |
if (error != 0) { |
error = dounmount(mp, SCARG(uap, flags), l); |
mutex_exit(&syncer_mutex); |
vfs_destroy(mp); |
return (error); |
return error; |
} |
|
|
|
return (dounmount(mp, SCARG(uap, flags), l)); |
|
} |
} |
|
|
/* |
/* |
* Do the actual file system unmount. File system is assumed to have been |
* Do the actual file system unmount. File system is assumed to have |
* marked busy by the caller. |
* been locked by the caller. |
|
* |
|
* => Caller hold reference to the mount, explicitly for dounmount(). |
*/ |
*/ |
int |
int |
dounmount(struct mount *mp, int flags, struct lwp *l) |
dounmount(struct mount *mp, int flags, struct lwp *l) |
Line 680 dounmount(struct mount *mp, int flags, s |
|
Line 718 dounmount(struct mount *mp, int flags, s |
|
int async; |
int async; |
int used_syncer; |
int used_syncer; |
|
|
KASSERT(rw_write_held(&mp->mnt_lock)); |
|
|
|
#if NVERIEXEC > 0 |
#if NVERIEXEC > 0 |
error = veriexec_unmountchk(mp); |
error = veriexec_unmountchk(mp); |
if (error) |
if (error) |
return (error); |
return (error); |
#endif /* NVERIEXEC > 0 */ |
#endif /* NVERIEXEC > 0 */ |
|
|
|
/* |
|
* XXX Freeze syncer. Must do this before locking the |
|
* mount point. See dounmount() for details. |
|
*/ |
|
mutex_enter(&syncer_mutex); |
|
rw_enter(&mp->mnt_unmounting, RW_WRITER); |
|
if ((mp->mnt_iflag & IMNT_GONE) != 0) { |
|
rw_exit(&mp->mnt_unmounting); |
|
mutex_exit(&syncer_mutex); |
|
return ENOENT; |
|
} |
|
|
used_syncer = (mp->mnt_syncer != NULL); |
used_syncer = (mp->mnt_syncer != NULL); |
|
|
/* |
/* |
* XXX Syncer must be frozen when we get here. This should really |
* XXX Syncer must be frozen when we get here. This should really |
* be done on a per-mountpoint basis, but especially the softdep |
* be done on a per-mountpoint basis, but the syncer doesn't work |
* code possibly called from the syncer doesn't exactly work on a |
* like that. |
* per-mountpoint basis, so the softdep code would become a maze |
|
* of vfs_busy() calls. |
|
* |
* |
* The caller of dounmount() must acquire syncer_mutex because |
* The caller of dounmount() must acquire syncer_mutex because |
* the syncer itself acquires locks in syncer_mutex -> vfs_busy |
* the syncer itself acquires locks in syncer_mutex -> vfs_busy |
Line 715 dounmount(struct mount *mp, int flags, s |
|
Line 761 dounmount(struct mount *mp, int flags, s |
|
vfs_deallocate_syncvnode(mp); |
vfs_deallocate_syncvnode(mp); |
error = 0; |
error = 0; |
if ((mp->mnt_flag & MNT_RDONLY) == 0) { |
if ((mp->mnt_flag & MNT_RDONLY) == 0) { |
#if NFSS > 0 |
error = VFS_SYNC(mp, MNT_WAIT, l->l_cred); |
error = fss_umount_hook(mp, (flags & MNT_FORCE)); |
|
#endif |
|
if (error == 0) |
|
error = VFS_SYNC(mp, MNT_WAIT, l->l_cred); |
|
} |
} |
vfs_scrubvnlist(mp); |
vfs_scrubvnlist(mp); |
if (error == 0 || (flags & MNT_FORCE)) |
if (error == 0 || (flags & MNT_FORCE)) |
Line 729 dounmount(struct mount *mp, int flags, s |
|
Line 771 dounmount(struct mount *mp, int flags, s |
|
(void) vfs_allocate_syncvnode(mp); |
(void) vfs_allocate_syncvnode(mp); |
mp->mnt_iflag &= ~IMNT_UNMOUNT; |
mp->mnt_iflag &= ~IMNT_UNMOUNT; |
mp->mnt_flag |= async; |
mp->mnt_flag |= async; |
|
rw_exit(&mp->mnt_unmounting); |
if (used_syncer) |
if (used_syncer) |
mutex_exit(&syncer_mutex); |
mutex_exit(&syncer_mutex); |
vfs_unbusy(mp, false); |
|
return (error); |
return (error); |
} |
} |
vfs_scrubvnlist(mp); |
vfs_scrubvnlist(mp); |
mutex_enter(&mountlist_lock); |
mutex_enter(&mountlist_lock); |
CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); |
|
if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) |
if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) |
coveredvp->v_mountedhere = NULL; |
coveredvp->v_mountedhere = NULL; |
|
CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); |
|
mp->mnt_iflag |= IMNT_GONE; |
mutex_exit(&mountlist_lock); |
mutex_exit(&mountlist_lock); |
if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL) |
if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL) |
panic("unmount: dangling vnode"); |
panic("unmount: dangling vnode"); |
mp->mnt_iflag |= IMNT_GONE; |
|
if (used_syncer) |
if (used_syncer) |
mutex_exit(&syncer_mutex); |
mutex_exit(&syncer_mutex); |
vfs_hooks_unmount(mp); |
vfs_hooks_unmount(mp); |
vfs_unbusy(mp, false); |
rw_exit(&mp->mnt_unmounting); |
vfs_destroy(mp); |
vfs_destroy(mp); /* reference from mount() */ |
if (coveredvp != NULLVP) |
if (coveredvp != NULLVP) |
vrele(coveredvp); |
vrele(coveredvp); |
return (0); |
return (0); |
Line 772 sys_sync(struct lwp *l, const void *v, r |
|
Line 814 sys_sync(struct lwp *l, const void *v, r |
|
l = &lwp0; |
l = &lwp0; |
|
|
mutex_enter(&mountlist_lock); |
mutex_enter(&mountlist_lock); |
for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { |
for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; |
if (vfs_trybusy(mp, RW_READER, &mountlist_lock)) { |
mp = nmp) { |
nmp = mp->mnt_list.cqe_prev; |
if (vfs_busy(mp, &nmp)) { |
continue; |
continue; |
} |
} |
|
mutex_enter(&mp->mnt_updating); |
if ((mp->mnt_flag & MNT_RDONLY) == 0) { |
if ((mp->mnt_flag & MNT_RDONLY) == 0) { |
asyncflag = mp->mnt_flag & MNT_ASYNC; |
asyncflag = mp->mnt_flag & MNT_ASYNC; |
mp->mnt_flag &= ~MNT_ASYNC; |
mp->mnt_flag &= ~MNT_ASYNC; |
Line 784 sys_sync(struct lwp *l, const void *v, r |
|
Line 827 sys_sync(struct lwp *l, const void *v, r |
|
if (asyncflag) |
if (asyncflag) |
mp->mnt_flag |= MNT_ASYNC; |
mp->mnt_flag |= MNT_ASYNC; |
} |
} |
mutex_enter(&mountlist_lock); |
mutex_exit(&mp->mnt_updating); |
nmp = mp->mnt_list.cqe_prev; |
vfs_unbusy(mp, false, &nmp); |
vfs_unbusy(mp, false); |
|
|
|
} |
} |
mutex_exit(&mountlist_lock); |
mutex_exit(&mountlist_lock); |
#ifdef DEBUG |
#ifdef DEBUG |
Line 812 sys_quotactl(struct lwp *l, const struct |
|
Line 853 sys_quotactl(struct lwp *l, const struct |
|
} */ |
} */ |
struct mount *mp; |
struct mount *mp; |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
mp = nd.ni_vp->v_mount; |
mp = vp->v_mount; |
error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), |
error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), |
SCARG(uap, arg)); |
SCARG(uap, arg)); |
vrele(nd.ni_vp); |
vrele(vp); |
return (error); |
return (error); |
} |
} |
|
|
|
|
if (cwdi->cwdi_rdir != NULL) { |
if (cwdi->cwdi_rdir != NULL) { |
size_t len; |
size_t len; |
char *bp; |
char *bp; |
|
char c; |
char *path = PNBUF_GET(); |
char *path = PNBUF_GET(); |
|
|
bp = path + MAXPATHLEN; |
bp = path + MAXPATHLEN; |
|
|
return error; |
return error; |
} |
} |
len = strlen(bp); |
len = strlen(bp); |
/* |
if (len != 1) { |
* for mount points that are below our root, we can see |
/* |
* them, so we fix up the pathname and return them. The |
* for mount points that are below our root, we can see |
* rest we cannot see, so we don't allow viewing the |
* them, so we fix up the pathname and return them. The |
* data. |
* rest we cannot see, so we don't allow viewing the |
*/ |
* data. |
if (strncmp(bp, sp->f_mntonname, len) == 0) { |
*/ |
strlcpy(sp->f_mntonname, &sp->f_mntonname[len], |
if (strncmp(bp, sp->f_mntonname, len) == 0 && |
sizeof(sp->f_mntonname)); |
((c = sp->f_mntonname[len]) == '/' || c == '\0')) { |
if (sp->f_mntonname[0] == '\0') |
(void)strlcpy(sp->f_mntonname, |
(void)strlcpy(sp->f_mntonname, "/", |
c == '\0' ? "/" : &sp->f_mntonname[len], |
sizeof(sp->f_mntonname)); |
|
} else { |
|
if (root) |
|
(void)strlcpy(sp->f_mntonname, "/", |
|
sizeof(sp->f_mntonname)); |
sizeof(sp->f_mntonname)); |
else |
} else { |
error = EPERM; |
if (root) |
|
(void)strlcpy(sp->f_mntonname, "/", |
|
sizeof(sp->f_mntonname)); |
|
else |
|
error = EPERM; |
|
} |
} |
} |
PNBUF_PUT(path); |
PNBUF_PUT(path); |
} |
} |
Line 901 do_sys_pstatvfs(struct lwp *l, const cha |
|
Line 944 do_sys_pstatvfs(struct lwp *l, const cha |
|
{ |
{ |
struct mount *mp; |
struct mount *mp; |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path); |
error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return error; |
return error; |
mp = nd.ni_vp->v_mount; |
mp = vp->v_mount; |
error = dostatvfs(mp, sb, l, flags, 1); |
error = dostatvfs(mp, sb, l, flags, 1); |
vrele(nd.ni_vp); |
vrele(vp); |
return error; |
return error; |
} |
} |
|
|
Line 993 do_sys_getvfsstat(struct lwp *l, void *s |
|
Line 1036 do_sys_getvfsstat(struct lwp *l, void *s |
|
count = 0; |
count = 0; |
for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; |
for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; |
mp = nmp) { |
mp = nmp) { |
if (vfs_trybusy(mp, RW_READER, &mountlist_lock)) { |
if (vfs_busy(mp, &nmp)) { |
nmp = CIRCLEQ_NEXT(mp, mnt_list); |
|
continue; |
continue; |
} |
} |
if (sfsp && count < maxcount) { |
if (sfsp && count < maxcount) { |
error = dostatvfs(mp, sb, l, flags, 0); |
error = dostatvfs(mp, sb, l, flags, 0); |
if (error) { |
if (error) { |
mutex_enter(&mountlist_lock); |
vfs_unbusy(mp, false, &nmp); |
nmp = CIRCLEQ_NEXT(mp, mnt_list); |
error = 0; |
vfs_unbusy(mp, false); |
|
continue; |
continue; |
} |
} |
error = copyfn(sb, sfsp, entry_sz); |
error = copyfn(sb, sfsp, entry_sz); |
if (error) { |
if (error) { |
vfs_unbusy(mp, false); |
vfs_unbusy(mp, false, NULL); |
goto out; |
goto out; |
} |
} |
sfsp = (char *)sfsp + entry_sz; |
sfsp = (char *)sfsp + entry_sz; |
root |= strcmp(sb->f_mntonname, "/") == 0; |
root |= strcmp(sb->f_mntonname, "/") == 0; |
} |
} |
count++; |
count++; |
mutex_enter(&mountlist_lock); |
vfs_unbusy(mp, false, &nmp); |
nmp = CIRCLEQ_NEXT(mp, mnt_list); |
|
vfs_unbusy(mp, false); |
|
} |
} |
|
|
mutex_exit(&mountlist_lock); |
mutex_exit(&mountlist_lock); |
|
|
if (root == 0 && p->p_cwdi->cwdi_rdir) { |
if (root == 0 && p->p_cwdi->cwdi_rdir) { |
/* |
/* |
* fake a root entry |
* fake a root entry |
Line 1028 do_sys_getvfsstat(struct lwp *l, void *s |
|
Line 1067 do_sys_getvfsstat(struct lwp *l, void *s |
|
sb, l, flags, 1); |
sb, l, flags, 1); |
if (error != 0) |
if (error != 0) |
goto out; |
goto out; |
if (sfsp) |
if (sfsp) { |
error = copyfn(sb, sfsp, entry_sz); |
error = copyfn(sb, sfsp, entry_sz); |
|
if (error != 0) |
|
goto out; |
|
} |
count++; |
count++; |
} |
} |
if (sfsp && count > maxcount) |
if (sfsp && count > maxcount) |
Line 1077 sys_fchdir(struct lwp *l, const struct s |
|
Line 1119 sys_fchdir(struct lwp *l, const struct s |
|
return (error); |
return (error); |
vp = fp->f_data; |
vp = fp->f_data; |
|
|
VREF(vp); |
vref(vp); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
if (vp->v_type != VDIR) |
if (vp->v_type != VDIR) |
error = ENOTDIR; |
error = ENOTDIR; |
Line 1088 sys_fchdir(struct lwp *l, const struct s |
|
Line 1130 sys_fchdir(struct lwp *l, const struct s |
|
goto out; |
goto out; |
} |
} |
while ((mp = vp->v_mountedhere) != NULL) { |
while ((mp = vp->v_mountedhere) != NULL) { |
if (vfs_busy(mp, RW_READER, NULL)) |
error = vfs_busy(mp, NULL); |
continue; |
|
vput(vp); |
vput(vp); |
|
if (error != 0) |
|
goto out; |
error = VFS_ROOT(mp, &tdp); |
error = VFS_ROOT(mp, &tdp); |
vfs_unbusy(mp, false); |
vfs_unbusy(mp, false, NULL); |
if (error) |
if (error) |
goto out; |
goto out; |
vp = tdp; |
vp = tdp; |
} |
} |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
|
|
/* |
/* |
* Disallow changing to a directory not under the process's |
* Disallow changing to a directory not under the process's |
|
|
sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval) |
sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval) |
{ |
{ |
struct proc *p = l->l_proc; |
struct proc *p = l->l_proc; |
struct cwdinfo *cwdi; |
|
struct vnode *vp; |
struct vnode *vp; |
file_t *fp; |
file_t *fp; |
int error, fd = SCARG(uap, fd); |
int error, fd = SCARG(uap, fd); |
Line 1136 sys_fchroot(struct lwp *l, const struct |
|
Line 1178 sys_fchroot(struct lwp *l, const struct |
|
KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0) |
KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0) |
return error; |
return error; |
/* fd_getvnode() will use the descriptor for us */ |
/* fd_getvnode() will use the descriptor for us */ |
if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
if ((error = fd_getvnode(fd, &fp)) != 0) |
return error; |
return error; |
vp = fp->f_data; |
vp = fp->f_data; |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
Line 1144 sys_fchroot(struct lwp *l, const struct |
|
Line 1186 sys_fchroot(struct lwp *l, const struct |
|
error = ENOTDIR; |
error = ENOTDIR; |
else |
else |
error = VOP_ACCESS(vp, VEXEC, l->l_cred); |
error = VOP_ACCESS(vp, VEXEC, l->l_cred); |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
if (error) |
if (error) |
goto out; |
goto out; |
VREF(vp); |
vref(vp); |
|
|
/* |
|
* Prevent escaping from chroot by putting the root under |
|
* the working directory. Silently chdir to / if we aren't |
|
* already there. |
|
*/ |
|
cwdi = p->p_cwdi; |
|
rw_enter(&cwdi->cwdi_lock, RW_WRITER); |
|
if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) { |
|
/* |
|
* XXX would be more failsafe to change directory to a |
|
* deadfs node here instead |
|
*/ |
|
vrele(cwdi->cwdi_cdir); |
|
VREF(vp); |
|
cwdi->cwdi_cdir = vp; |
|
} |
|
|
|
if (cwdi->cwdi_rdir != NULL) |
change_root(p->p_cwdi, vp, l); |
vrele(cwdi->cwdi_rdir); |
|
cwdi->cwdi_rdir = vp; |
|
rw_exit(&cwdi->cwdi_lock); |
|
|
|
out: |
out: |
fd_putfile(fd); |
fd_putfile(fd); |
Line 1189 sys_chdir(struct lwp *l, const struct sy |
|
Line 1211 sys_chdir(struct lwp *l, const struct sy |
|
struct proc *p = l->l_proc; |
struct proc *p = l->l_proc; |
struct cwdinfo *cwdi; |
struct cwdinfo *cwdi; |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE, |
if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE, |
SCARG(uap, path)); |
&vp, l)) != 0) |
if ((error = change_dir(&nd, l)) != 0) |
|
return (error); |
return (error); |
cwdi = p->p_cwdi; |
cwdi = p->p_cwdi; |
rw_enter(&cwdi->cwdi_lock, RW_WRITER); |
rw_enter(&cwdi->cwdi_lock, RW_WRITER); |
vrele(cwdi->cwdi_cdir); |
vrele(cwdi->cwdi_cdir); |
cwdi->cwdi_cdir = nd.ni_vp; |
cwdi->cwdi_cdir = vp; |
rw_exit(&cwdi->cwdi_lock); |
rw_exit(&cwdi->cwdi_lock); |
return (0); |
return (0); |
} |
} |
Line 1214 sys_chroot(struct lwp *l, const struct s |
|
Line 1235 sys_chroot(struct lwp *l, const struct s |
|
syscallarg(const char *) path; |
syscallarg(const char *) path; |
} */ |
} */ |
struct proc *p = l->l_proc; |
struct proc *p = l->l_proc; |
struct cwdinfo *cwdi; |
|
struct vnode *vp; |
|
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT, |
if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT, |
KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0) |
KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0) |
return (error); |
return (error); |
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE, |
if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE, |
SCARG(uap, path)); |
&vp, l)) != 0) |
if ((error = change_dir(&nd, l)) != 0) |
|
return (error); |
return (error); |
|
|
cwdi = p->p_cwdi; |
change_root(p->p_cwdi, vp, l); |
|
|
|
return (0); |
|
} |
|
|
|
/* |
|
* Common routine for chroot and fchroot. |
|
* NB: callers need to properly authorize the change root operation. |
|
*/ |
|
void |
|
change_root(struct cwdinfo *cwdi, struct vnode *vp, struct lwp *l) |
|
{ |
|
|
rw_enter(&cwdi->cwdi_lock, RW_WRITER); |
rw_enter(&cwdi->cwdi_lock, RW_WRITER); |
if (cwdi->cwdi_rdir != NULL) |
if (cwdi->cwdi_rdir != NULL) |
vrele(cwdi->cwdi_rdir); |
vrele(cwdi->cwdi_rdir); |
vp = nd.ni_vp; |
|
cwdi->cwdi_rdir = vp; |
cwdi->cwdi_rdir = vp; |
|
|
/* |
/* |
Line 1245 sys_chroot(struct lwp *l, const struct s |
|
Line 1274 sys_chroot(struct lwp *l, const struct s |
|
* deadfs node here instead |
* deadfs node here instead |
*/ |
*/ |
vrele(cwdi->cwdi_cdir); |
vrele(cwdi->cwdi_cdir); |
VREF(vp); |
vref(vp); |
cwdi->cwdi_cdir = vp; |
cwdi->cwdi_cdir = vp; |
} |
} |
rw_exit(&cwdi->cwdi_lock); |
rw_exit(&cwdi->cwdi_lock); |
|
|
return (0); |
|
} |
} |
|
|
/* |
/* |
* Common routine for chroot and chdir. |
* Common routine for chroot and chdir. |
*/ |
*/ |
static int |
int |
change_dir(struct nameidata *ndp, struct lwp *l) |
chdir_lookup(const char *path, int where, struct vnode **vpp, struct lwp *l) |
{ |
{ |
struct vnode *vp; |
struct nameidata nd; |
int error; |
int error; |
|
|
if ((error = namei(ndp)) != 0) |
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, where, |
|
path); |
|
if ((error = namei(&nd)) != 0) |
return (error); |
return (error); |
vp = ndp->ni_vp; |
*vpp = nd.ni_vp; |
if (vp->v_type != VDIR) |
if ((*vpp)->v_type != VDIR) |
error = ENOTDIR; |
error = ENOTDIR; |
else |
else |
error = VOP_ACCESS(vp, VEXEC, l->l_cred); |
error = VOP_ACCESS(*vpp, VEXEC, l->l_cred); |
|
|
if (error) |
if (error) |
vput(vp); |
vput(*vpp); |
else |
else |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(*vpp); |
return (error); |
return (error); |
} |
} |
|
|
Line 1339 sys_open(struct lwp *l, const struct sys |
|
Line 1368 sys_open(struct lwp *l, const struct sys |
|
type = F_FLOCK; |
type = F_FLOCK; |
if ((flags & FNONBLOCK) == 0) |
if ((flags & FNONBLOCK) == 0) |
type |= F_WAIT; |
type |= F_WAIT; |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type); |
error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type); |
if (error) { |
if (error) { |
(void) vn_close(vp, fp->f_flag, fp->f_cred); |
(void) vn_close(vp, fp->f_flag, fp->f_cred); |
Line 1349 sys_open(struct lwp *l, const struct sys |
|
Line 1378 sys_open(struct lwp *l, const struct sys |
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
atomic_or_uint(&fp->f_flag, FHASLOCK); |
atomic_or_uint(&fp->f_flag, FHASLOCK); |
} |
} |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
*retval = indx; |
*retval = indx; |
fd_affix(p, fp, indx); |
fd_affix(p, fp, indx); |
return (0); |
return (0); |
Line 1639 dofhopen(struct lwp *l, const void *ufhp |
|
Line 1668 dofhopen(struct lwp *l, const void *ufhp |
|
if (error != 0) |
if (error != 0) |
goto bad; |
goto bad; |
if (flags & O_TRUNC) { |
if (flags & O_TRUNC) { |
VOP_UNLOCK(vp, 0); /* XXX */ |
VOP_UNLOCK(vp); /* XXX */ |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */ |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */ |
VATTR_NULL(&va); |
vattr_null(&va); |
va.va_size = 0; |
va.va_size = 0; |
error = VOP_SETATTR(vp, &va, cred); |
error = VOP_SETATTR(vp, &va, cred); |
if (error) |
if (error) |
Line 1672 dofhopen(struct lwp *l, const void *ufhp |
|
Line 1701 dofhopen(struct lwp *l, const void *ufhp |
|
type = F_FLOCK; |
type = F_FLOCK; |
if ((flags & FNONBLOCK) == 0) |
if ((flags & FNONBLOCK) == 0) |
type |= F_WAIT; |
type |= F_WAIT; |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type); |
error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type); |
if (error) { |
if (error) { |
(void) vn_close(vp, fp->f_flag, fp->f_cred); |
(void) vn_close(vp, fp->f_flag, fp->f_cred); |
Line 1682 dofhopen(struct lwp *l, const void *ufhp |
|
Line 1711 dofhopen(struct lwp *l, const void *ufhp |
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
atomic_or_uint(&fp->f_flag, FHASLOCK); |
atomic_or_uint(&fp->f_flag, FHASLOCK); |
} |
} |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
*retval = indx; |
*retval = indx; |
fd_affix(p, fp, indx); |
fd_affix(p, fp, indx); |
vfs_copyinfh_free(fh); |
vfs_copyinfh_free(fh); |
Line 1740 do_fhstat(struct lwp *l, const void *ufh |
|
Line 1769 do_fhstat(struct lwp *l, const void *ufh |
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
int |
int |
sys___fhstat40(struct lwp *l, const struct sys___fhstat40_args *uap, register_t *retval) |
sys___fhstat50(struct lwp *l, const struct sys___fhstat50_args *uap, register_t *retval) |
{ |
{ |
/* { |
/* { |
syscallarg(const void *) fhp; |
syscallarg(const void *) fhp; |
Line 1813 sys___fhstatvfs140(struct lwp *l, const |
|
Line 1842 sys___fhstatvfs140(struct lwp *l, const |
|
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
int |
int |
sys_mknod(struct lwp *l, const struct sys_mknod_args *uap, register_t *retval) |
sys___mknod50(struct lwp *l, const struct sys___mknod50_args *uap, |
|
register_t *retval) |
{ |
{ |
/* { |
/* { |
syscallarg(const char *) path; |
syscallarg(const char *) path; |
syscallarg(int) mode; |
syscallarg(mode_t) mode; |
syscallarg(int) dev; |
syscallarg(dev_t) dev; |
} */ |
} */ |
|
return do_sys_mknod(l, SCARG(uap, path), SCARG(uap, mode), |
|
SCARG(uap, dev), retval, UIO_USERSPACE); |
|
} |
|
|
|
int |
|
do_sys_mknod(struct lwp *l, const char *pathname, mode_t mode, dev_t dev, |
|
register_t *retval, enum uio_seg seg) |
|
{ |
struct proc *p = l->l_proc; |
struct proc *p = l->l_proc; |
struct vnode *vp; |
struct vnode *vp; |
struct vattr vattr; |
struct vattr vattr; |
Line 1827 sys_mknod(struct lwp *l, const struct sy |
|
Line 1865 sys_mknod(struct lwp *l, const struct sy |
|
struct nameidata nd; |
struct nameidata nd; |
char *path; |
char *path; |
const char *cpath; |
const char *cpath; |
enum uio_seg seg = UIO_USERSPACE; |
|
|
|
if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD, |
if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD, |
0, NULL, NULL, NULL)) != 0) |
0, NULL, NULL, NULL)) != 0) |
Line 1835 sys_mknod(struct lwp *l, const struct sy |
|
Line 1872 sys_mknod(struct lwp *l, const struct sy |
|
|
|
optype = VOP_MKNOD_DESCOFFSET; |
optype = VOP_MKNOD_DESCOFFSET; |
|
|
VERIEXEC_PATH_GET(SCARG(uap, path), seg, cpath, path); |
VERIEXEC_PATH_GET(pathname, seg, cpath, path); |
NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, seg, cpath); |
NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, seg, cpath); |
|
|
if ((error = namei(&nd)) != 0) |
if ((error = namei(&nd)) != 0) |
Line 1844 sys_mknod(struct lwp *l, const struct sy |
|
Line 1881 sys_mknod(struct lwp *l, const struct sy |
|
if (vp != NULL) |
if (vp != NULL) |
error = EEXIST; |
error = EEXIST; |
else { |
else { |
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
/* We will read cwdi->cwdi_cmask unlocked. */ |
/* We will read cwdi->cwdi_cmask unlocked. */ |
vattr.va_mode = |
vattr.va_mode = (mode & ALLPERMS) &~ p->p_cwdi->cwdi_cmask; |
(SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask; |
vattr.va_rdev = dev; |
vattr.va_rdev = SCARG(uap, dev); |
|
|
|
switch (SCARG(uap, mode) & S_IFMT) { |
switch (mode & S_IFMT) { |
case S_IFMT: /* used by badsect to flag bad sectors */ |
case S_IFMT: /* used by badsect to flag bad sectors */ |
vattr.va_type = VBAD; |
vattr.va_type = VBAD; |
break; |
break; |
Line 1943 sys_mkfifo(struct lwp *l, const struct s |
|
Line 1979 sys_mkfifo(struct lwp *l, const struct s |
|
vrele(nd.ni_vp); |
vrele(nd.ni_vp); |
return (EEXIST); |
return (EEXIST); |
} |
} |
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
vattr.va_type = VFIFO; |
vattr.va_type = VFIFO; |
/* We will read cwdi->cwdi_cmask unlocked. */ |
/* We will read cwdi->cwdi_cmask unlocked. */ |
vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask; |
vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask; |
Line 1968 sys_link(struct lwp *l, const struct sys |
|
Line 2004 sys_link(struct lwp *l, const struct sys |
|
struct nameidata nd; |
struct nameidata nd; |
int error; |
int error; |
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
vp = nd.ni_vp; |
|
NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE, |
NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE, |
SCARG(uap, link)); |
SCARG(uap, link)); |
if ((error = namei(&nd)) != 0) |
if ((error = namei(&nd)) != 0) |
|
|
return (error); |
return (error); |
} |
} |
|
|
/* |
|
* Make a symbolic link. |
|
*/ |
|
/* ARGSUSED */ |
|
int |
int |
sys_symlink(struct lwp *l, const struct sys_symlink_args *uap, register_t *retval) |
do_sys_symlink(const char *patharg, const char *link, enum uio_seg seg) |
{ |
{ |
/* { |
struct proc *p = curproc; |
syscallarg(const char *) path; |
|
syscallarg(const char *) link; |
|
} */ |
|
struct proc *p = l->l_proc; |
|
struct vattr vattr; |
struct vattr vattr; |
char *path; |
char *path; |
int error; |
int error; |
struct nameidata nd; |
struct nameidata nd; |
|
|
path = PNBUF_GET(); |
path = PNBUF_GET(); |
error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL); |
if (seg == UIO_USERSPACE) { |
if (error) |
if ((error = copyinstr(patharg, path, MAXPATHLEN, NULL)) != 0) |
goto out; |
goto out; |
NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE, |
} else { |
SCARG(uap, link)); |
KASSERT(strlen(patharg) < MAXPATHLEN); |
|
strcpy(path, patharg); |
|
} |
|
NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, seg, link); |
if ((error = namei(&nd)) != 0) |
if ((error = namei(&nd)) != 0) |
goto out; |
goto out; |
if (nd.ni_vp) { |
if (nd.ni_vp) { |
Line 2028 sys_symlink(struct lwp *l, const struct |
|
Line 2058 sys_symlink(struct lwp *l, const struct |
|
error = EEXIST; |
error = EEXIST; |
goto out; |
goto out; |
} |
} |
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
vattr.va_type = VLNK; |
vattr.va_type = VLNK; |
/* We will read cwdi->cwdi_cmask unlocked. */ |
/* We will read cwdi->cwdi_cmask unlocked. */ |
vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask; |
vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask; |
|
|
} |
} |
|
|
/* |
/* |
|
* Make a symbolic link. |
|
*/ |
|
/* ARGSUSED */ |
|
int |
|
sys_symlink(struct lwp *l, const struct sys_symlink_args *uap, register_t *retval) |
|
{ |
|
/* { |
|
syscallarg(const char *) path; |
|
syscallarg(const char *) link; |
|
} */ |
|
|
|
return do_sys_symlink(SCARG(uap, path), SCARG(uap, link), |
|
UIO_USERSPACE); |
|
} |
|
|
|
/* |
* Delete a whiteout from the filesystem. |
* Delete a whiteout from the filesystem. |
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
Line 2095 do_sys_unlink(const char *arg, enum uio_ |
|
Line 2141 do_sys_unlink(const char *arg, enum uio_ |
|
struct vnode *vp; |
struct vnode *vp; |
int error; |
int error; |
struct nameidata nd; |
struct nameidata nd; |
kauth_cred_t cred; |
|
char *path; |
char *path; |
const char *cpath; |
const char *cpath; |
|
|
Line 2133 do_sys_unlink(const char *arg, enum uio_ |
|
Line 2178 do_sys_unlink(const char *arg, enum uio_ |
|
} |
} |
#endif /* NVERIEXEC > 0 */ |
#endif /* NVERIEXEC > 0 */ |
|
|
cred = kauth_cred_get(); |
|
#ifdef FILEASSOC |
#ifdef FILEASSOC |
(void)fileassoc_file_delete(vp); |
(void)fileassoc_file_delete(vp); |
#endif /* FILEASSOC */ |
#endif /* FILEASSOC */ |
Line 2178 sys_lseek(struct lwp *l, const struct sy |
|
Line 2222 sys_lseek(struct lwp *l, const struct sy |
|
newoff = fp->f_offset + SCARG(uap, offset); |
newoff = fp->f_offset + SCARG(uap, offset); |
break; |
break; |
case SEEK_END: |
case SEEK_END: |
|
vn_lock(vp, LK_SHARED | LK_RETRY); |
error = VOP_GETATTR(vp, &vattr, cred); |
error = VOP_GETATTR(vp, &vattr, cred); |
|
VOP_UNLOCK(vp); |
if (error) { |
if (error) { |
goto out; |
goto out; |
} |
} |
Line 2403 do_sys_stat(const char *path, unsigned i |
|
Line 2449 do_sys_stat(const char *path, unsigned i |
|
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
int |
int |
sys___stat30(struct lwp *l, const struct sys___stat30_args *uap, register_t *retval) |
sys___stat50(struct lwp *l, const struct sys___stat50_args *uap, register_t *retval) |
{ |
{ |
/* { |
/* { |
syscallarg(const char *) path; |
syscallarg(const char *) path; |
Line 2423 sys___stat30(struct lwp *l, const struct |
|
Line 2469 sys___stat30(struct lwp *l, const struct |
|
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
int |
int |
sys___lstat30(struct lwp *l, const struct sys___lstat30_args *uap, register_t *retval) |
sys___lstat50(struct lwp *l, const struct sys___lstat50_args *uap, register_t *retval) |
{ |
{ |
/* { |
/* { |
syscallarg(const char *) path; |
syscallarg(const char *) path; |
Line 2517 sys_chflags(struct lwp *l, const struct |
|
Line 2563 sys_chflags(struct lwp *l, const struct |
|
} */ |
} */ |
struct vnode *vp; |
struct vnode *vp; |
int error; |
int error; |
struct nameidata nd; |
|
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
vp = nd.ni_vp; |
|
error = change_flags(vp, SCARG(uap, flags), l); |
error = change_flags(vp, SCARG(uap, flags), l); |
vput(vp); |
vput(vp); |
return (error); |
return (error); |
Line 2549 sys_fchflags(struct lwp *l, const struct |
|
Line 2593 sys_fchflags(struct lwp *l, const struct |
|
return (error); |
return (error); |
vp = fp->f_data; |
vp = fp->f_data; |
error = change_flags(vp, SCARG(uap, flags), l); |
error = change_flags(vp, SCARG(uap, flags), l); |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
fd_putfile(SCARG(uap, fd)); |
fd_putfile(SCARG(uap, fd)); |
return (error); |
return (error); |
} |
} |
Line 2567 sys_lchflags(struct lwp *l, const struct |
|
Line 2611 sys_lchflags(struct lwp *l, const struct |
|
} */ |
} */ |
struct vnode *vp; |
struct vnode *vp; |
int error; |
int error; |
struct nameidata nd; |
|
|
|
NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_NOFOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
vp = nd.ni_vp; |
|
error = change_flags(vp, SCARG(uap, flags), l); |
error = change_flags(vp, SCARG(uap, flags), l); |
vput(vp); |
vput(vp); |
return (error); |
return (error); |
Line 2601 change_flags(struct vnode *vp, u_long fl |
|
Line 2643 change_flags(struct vnode *vp, u_long fl |
|
goto out; |
goto out; |
} |
} |
} |
} |
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
vattr.va_flags = flags; |
vattr.va_flags = flags; |
error = VOP_SETATTR(vp, &vattr, l->l_cred); |
error = VOP_SETATTR(vp, &vattr, l->l_cred); |
out: |
out: |
Line 2620 sys_chmod(struct lwp *l, const struct sy |
|
Line 2662 sys_chmod(struct lwp *l, const struct sy |
|
syscallarg(int) mode; |
syscallarg(int) mode; |
} */ |
} */ |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
|
|
error = change_mode(nd.ni_vp, SCARG(uap, mode), l); |
error = change_mode(vp, SCARG(uap, mode), l); |
|
|
vrele(nd.ni_vp); |
vrele(vp); |
return (error); |
return (error); |
} |
} |
|
|
Line 2667 sys_lchmod(struct lwp *l, const struct s |
|
Line 2709 sys_lchmod(struct lwp *l, const struct s |
|
syscallarg(int) mode; |
syscallarg(int) mode; |
} */ |
} */ |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_NOFOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
|
|
error = change_mode(nd.ni_vp, SCARG(uap, mode), l); |
error = change_mode(vp, SCARG(uap, mode), l); |
|
|
vrele(nd.ni_vp); |
vrele(vp); |
return (error); |
return (error); |
} |
} |
|
|
Line 2690 change_mode(struct vnode *vp, int mode, |
|
Line 2732 change_mode(struct vnode *vp, int mode, |
|
int error; |
int error; |
|
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
vattr.va_mode = mode & ALLPERMS; |
vattr.va_mode = mode & ALLPERMS; |
error = VOP_SETATTR(vp, &vattr, l->l_cred); |
error = VOP_SETATTR(vp, &vattr, l->l_cred); |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
return (error); |
return (error); |
} |
} |
|
|
Line 2710 sys_chown(struct lwp *l, const struct sy |
|
Line 2752 sys_chown(struct lwp *l, const struct sy |
|
syscallarg(gid_t) gid; |
syscallarg(gid_t) gid; |
} */ |
} */ |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
|
|
error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0); |
error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0); |
|
|
vrele(nd.ni_vp); |
vrele(vp); |
return (error); |
return (error); |
} |
} |
|
|
Line 2737 sys___posix_chown(struct lwp *l, const s |
|
Line 2779 sys___posix_chown(struct lwp *l, const s |
|
syscallarg(gid_t) gid; |
syscallarg(gid_t) gid; |
} */ |
} */ |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
|
|
error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1); |
error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1); |
|
|
vrele(nd.ni_vp); |
vrele(vp); |
return (error); |
return (error); |
} |
} |
|
|
Line 2811 sys_lchown(struct lwp *l, const struct s |
|
Line 2853 sys_lchown(struct lwp *l, const struct s |
|
syscallarg(gid_t) gid; |
syscallarg(gid_t) gid; |
} */ |
} */ |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_NOFOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
|
|
error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0); |
error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0); |
|
|
vrele(nd.ni_vp); |
vrele(vp); |
return (error); |
return (error); |
} |
} |
|
|
Line 2838 sys___posix_lchown(struct lwp *l, const |
|
Line 2880 sys___posix_lchown(struct lwp *l, const |
|
syscallarg(gid_t) gid; |
syscallarg(gid_t) gid; |
} */ |
} */ |
int error; |
int error; |
struct nameidata nd; |
struct vnode *vp; |
|
|
NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_NOFOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
|
|
error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1); |
error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1); |
|
|
vrele(nd.ni_vp); |
vrele(vp); |
return (error); |
return (error); |
} |
} |
|
|
Line 2893 change_owner(struct vnode *vp, uid_t uid |
|
Line 2935 change_owner(struct vnode *vp, uid_t uid |
|
if (vattr.va_mode == newmode) |
if (vattr.va_mode == newmode) |
newmode = VNOVAL; |
newmode = VNOVAL; |
|
|
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL; |
vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL; |
vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL; |
vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL; |
vattr.va_mode = newmode; |
vattr.va_mode = newmode; |
Line 2901 change_owner(struct vnode *vp, uid_t uid |
|
Line 2943 change_owner(struct vnode *vp, uid_t uid |
|
#undef CHANGED |
#undef CHANGED |
|
|
out: |
out: |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
return (error); |
return (error); |
} |
} |
|
|
|
|
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
int |
int |
sys_utimes(struct lwp *l, const struct sys_utimes_args *uap, register_t *retval) |
sys___utimes50(struct lwp *l, const struct sys___utimes50_args *uap, |
|
register_t *retval) |
{ |
{ |
/* { |
/* { |
syscallarg(const char *) path; |
syscallarg(const char *) path; |
Line 2927 sys_utimes(struct lwp *l, const struct s |
|
Line 2970 sys_utimes(struct lwp *l, const struct s |
|
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
int |
int |
sys_futimes(struct lwp *l, const struct sys_futimes_args *uap, register_t *retval) |
sys___futimes50(struct lwp *l, const struct sys___futimes50_args *uap, |
|
register_t *retval) |
{ |
{ |
/* { |
/* { |
syscallarg(int) fd; |
syscallarg(int) fd; |
Line 2950 sys_futimes(struct lwp *l, const struct |
|
Line 2994 sys_futimes(struct lwp *l, const struct |
|
* version does not follow links. |
* version does not follow links. |
*/ |
*/ |
int |
int |
sys_lutimes(struct lwp *l, const struct sys_lutimes_args *uap, register_t *retval) |
sys___lutimes50(struct lwp *l, const struct sys___lutimes50_args *uap, |
|
register_t *retval) |
{ |
{ |
/* { |
/* { |
syscallarg(const char *) path; |
syscallarg(const char *) path; |
Line 2969 do_sys_utimes(struct lwp *l, struct vnod |
|
Line 3014 do_sys_utimes(struct lwp *l, struct vnod |
|
const struct timeval *tptr, enum uio_seg seg) |
const struct timeval *tptr, enum uio_seg seg) |
{ |
{ |
struct vattr vattr; |
struct vattr vattr; |
struct nameidata nd; |
int error, dorele = 0; |
int error; |
namei_simple_flags_t sflags; |
|
|
|
bool vanull, setbirthtime; |
|
struct timespec ts[2]; |
|
|
|
/* |
|
* I have checked all callers and they pass either FOLLOW, |
|
* NOFOLLOW, or 0 (when they don't pass a path), and NOFOLLOW |
|
* is 0. More to the point, they don't pass anything else. |
|
* Let's keep it that way at least until the namei interfaces |
|
* are fully sanitized. |
|
*/ |
|
KASSERT(flag == NOFOLLOW || flag == FOLLOW); |
|
sflags = (flag == FOLLOW) ? |
|
NSM_FOLLOW_TRYEMULROOT : NSM_NOFOLLOW_TRYEMULROOT; |
|
|
VATTR_NULL(&vattr); |
|
if (tptr == NULL) { |
if (tptr == NULL) { |
nanotime(&vattr.va_atime); |
vanull = true; |
vattr.va_mtime = vattr.va_atime; |
nanotime(&ts[0]); |
vattr.va_vaflags |= VA_UTIMES_NULL; |
ts[1] = ts[0]; |
} else { |
} else { |
struct timeval tv[2]; |
struct timeval tv[2]; |
|
|
|
vanull = false; |
if (seg != UIO_SYSSPACE) { |
if (seg != UIO_SYSSPACE) { |
error = copyin(tptr, &tv, sizeof (tv)); |
error = copyin(tptr, tv, sizeof (tv)); |
if (error != 0) |
if (error != 0) |
return error; |
return error; |
tptr = tv; |
tptr = tv; |
} |
} |
TIMEVAL_TO_TIMESPEC(tptr, &vattr.va_atime); |
TIMEVAL_TO_TIMESPEC(&tptr[0], &ts[0]); |
TIMEVAL_TO_TIMESPEC(tptr + 1, &vattr.va_mtime); |
TIMEVAL_TO_TIMESPEC(&tptr[1], &ts[1]); |
} |
} |
|
|
if (vp == NULL) { |
if (vp == NULL) { |
NDINIT(&nd, LOOKUP, flag | TRYEMULROOT, UIO_USERSPACE, path); |
/* note: SEG describes TPTR, not PATH; PATH is always user */ |
if ((error = namei(&nd)) != 0) |
error = namei_simple_user(path, sflags, &vp); |
return (error); |
if (error != 0) |
vp = nd.ni_vp; |
return error; |
} else |
dorele = 1; |
nd.ni_vp = NULL; |
} |
|
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
|
setbirthtime = (VOP_GETATTR(vp, &vattr, l->l_cred) == 0 && |
|
timespeccmp(&ts[1], &vattr.va_birthtime, <)); |
|
vattr_null(&vattr); |
|
vattr.va_atime = ts[0]; |
|
vattr.va_mtime = ts[1]; |
|
if (setbirthtime) |
|
vattr.va_birthtime = ts[1]; |
|
if (vanull) |
|
vattr.va_vaflags |= VA_UTIMES_NULL; |
error = VOP_SETATTR(vp, &vattr, l->l_cred); |
error = VOP_SETATTR(vp, &vattr, l->l_cred); |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
|
|
if (nd.ni_vp != NULL) |
if (dorele != 0) |
vrele(nd.ni_vp); |
vrele(vp); |
|
|
return (error); |
return error; |
} |
} |
|
|
/* |
/* |
Line 3023 sys_truncate(struct lwp *l, const struct |
|
Line 3091 sys_truncate(struct lwp *l, const struct |
|
struct vnode *vp; |
struct vnode *vp; |
struct vattr vattr; |
struct vattr vattr; |
int error; |
int error; |
struct nameidata nd; |
|
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
vp = nd.ni_vp; |
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
if (vp->v_type == VDIR) |
if (vp->v_type == VDIR) |
error = EISDIR; |
error = EISDIR; |
else if ((error = vn_writechk(vp)) == 0 && |
else if ((error = vn_writechk(vp)) == 0 && |
(error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) { |
(error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) { |
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
vattr.va_size = SCARG(uap, length); |
vattr.va_size = SCARG(uap, length); |
error = VOP_SETATTR(vp, &vattr, l->l_cred); |
error = VOP_SETATTR(vp, &vattr, l->l_cred); |
} |
} |
Line 3072 sys_ftruncate(struct lwp *l, const struc |
|
Line 3138 sys_ftruncate(struct lwp *l, const struc |
|
if (vp->v_type == VDIR) |
if (vp->v_type == VDIR) |
error = EISDIR; |
error = EISDIR; |
else if ((error = vn_writechk(vp)) == 0) { |
else if ((error = vn_writechk(vp)) == 0) { |
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
vattr.va_size = SCARG(uap, length); |
vattr.va_size = SCARG(uap, length); |
error = VOP_SETATTR(vp, &vattr, fp->f_cred); |
error = VOP_SETATTR(vp, &vattr, fp->f_cred); |
} |
} |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
out: |
out: |
fd_putfile(SCARG(uap, fd)); |
fd_putfile(SCARG(uap, fd)); |
return (error); |
return (error); |
Line 3102 sys_fsync(struct lwp *l, const struct sy |
|
Line 3168 sys_fsync(struct lwp *l, const struct sy |
|
vp = fp->f_data; |
vp = fp->f_data; |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0); |
error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0); |
if (error == 0 && bioopsp != NULL && |
VOP_UNLOCK(vp); |
vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)) |
|
(*bioopsp->io_fsync)(vp, 0); |
|
VOP_UNLOCK(vp, 0); |
|
fd_putfile(SCARG(uap, fd)); |
fd_putfile(SCARG(uap, fd)); |
return (error); |
return (error); |
} |
} |
Line 3173 sys_fsync_range(struct lwp *l, const str |
|
Line 3236 sys_fsync_range(struct lwp *l, const str |
|
vp = fp->f_data; |
vp = fp->f_data; |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e); |
error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e); |
|
VOP_UNLOCK(vp); |
if (error == 0 && bioopsp != NULL && |
|
vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)) |
|
(*bioopsp->io_fsync)(vp, nflags); |
|
|
|
VOP_UNLOCK(vp, 0); |
|
out: |
out: |
fd_putfile(SCARG(uap, fd)); |
fd_putfile(SCARG(uap, fd)); |
return (error); |
return (error); |
Line 3208 sys_fdatasync(struct lwp *l, const struc |
|
Line 3266 sys_fdatasync(struct lwp *l, const struc |
|
vp = fp->f_data; |
vp = fp->f_data; |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0); |
error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0); |
VOP_UNLOCK(vp, 0); |
VOP_UNLOCK(vp); |
fd_putfile(SCARG(uap, fd)); |
fd_putfile(SCARG(uap, fd)); |
return (error); |
return (error); |
} |
} |
Line 3264 do_sys_rename(const char *from, const ch |
|
Line 3322 do_sys_rename(const char *from, const ch |
|
uint32_t saveflag; |
uint32_t saveflag; |
int error; |
int error; |
|
|
NDINIT(&fromnd, DELETE, LOCKPARENT | SAVESTART | TRYEMULROOT, |
NDINIT(&fromnd, DELETE, LOCKPARENT | SAVESTART | TRYEMULROOT | INRENAME, |
seg, from); |
seg, from); |
if ((error = namei(&fromnd)) != 0) |
if ((error = namei(&fromnd)) != 0) |
return (error); |
return (error); |
if (fromnd.ni_dvp != fromnd.ni_vp) |
if (fromnd.ni_dvp != fromnd.ni_vp) |
VOP_UNLOCK(fromnd.ni_dvp, 0); |
VOP_UNLOCK(fromnd.ni_dvp); |
fvp = fromnd.ni_vp; |
fvp = fromnd.ni_vp; |
|
|
fs = fvp->v_mount; |
fs = fvp->v_mount; |
Line 3316 do_sys_rename(const char *from, const ch |
|
Line 3374 do_sys_rename(const char *from, const ch |
|
error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd); |
error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd); |
fromnd.ni_cnd.cn_flags |= saveflag; |
fromnd.ni_cnd.cn_flags |= saveflag; |
if (error) { |
if (error) { |
VOP_UNLOCK(fromnd.ni_dvp, 0); |
VOP_UNLOCK(fromnd.ni_dvp); |
VFS_RENAMELOCK_EXIT(fs); |
VFS_RENAMELOCK_EXIT(fs); |
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); |
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); |
vrele(fromnd.ni_dvp); |
vrele(fromnd.ni_dvp); |
goto out1; |
goto out1; |
} |
} |
VOP_UNLOCK(fromnd.ni_vp, 0); |
VOP_UNLOCK(fromnd.ni_vp); |
if (fromnd.ni_dvp != fromnd.ni_vp) |
if (fromnd.ni_dvp != fromnd.ni_vp) |
VOP_UNLOCK(fromnd.ni_dvp, 0); |
VOP_UNLOCK(fromnd.ni_dvp); |
fvp = fromnd.ni_vp; |
fvp = fromnd.ni_vp; |
|
|
NDINIT(&tond, RENAME, |
NDINIT(&tond, RENAME, |
LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | TRYEMULROOT |
LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | TRYEMULROOT |
| (fvp->v_type == VDIR ? CREATEDIR : 0), |
| INRENAME | (fvp->v_type == VDIR ? CREATEDIR : 0), |
seg, to); |
seg, to); |
if ((error = namei(&tond)) != 0) { |
if ((error = namei(&tond)) != 0) { |
VFS_RENAMELOCK_EXIT(fs); |
VFS_RENAMELOCK_EXIT(fs); |
Line 3371 do_sys_rename(const char *from, const ch |
|
Line 3429 do_sys_rename(const char *from, const ch |
|
#if NVERIEXEC > 0 |
#if NVERIEXEC > 0 |
if (!error) { |
if (!error) { |
char *f1, *f2; |
char *f1, *f2; |
|
size_t f1_len; |
|
size_t f2_len; |
|
|
f1 = malloc(fromnd.ni_cnd.cn_namelen + 1, M_TEMP, M_WAITOK); |
f1_len = fromnd.ni_cnd.cn_namelen + 1; |
strlcpy(f1, fromnd.ni_cnd.cn_nameptr, fromnd.ni_cnd.cn_namelen); |
f1 = kmem_alloc(f1_len, KM_SLEEP); |
|
strlcpy(f1, fromnd.ni_cnd.cn_nameptr, f1_len); |
f2 = malloc(tond.ni_cnd.cn_namelen + 1, M_TEMP, M_WAITOK); |
|
strlcpy(f2, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen); |
f2_len = tond.ni_cnd.cn_namelen + 1; |
|
f2 = kmem_alloc(f2_len, KM_SLEEP); |
|
strlcpy(f2, tond.ni_cnd.cn_nameptr, f2_len); |
|
|
error = veriexec_renamechk(l, fvp, f1, tvp, f2); |
error = veriexec_renamechk(l, fvp, f1, tvp, f2); |
|
|
free(f1, M_TEMP); |
kmem_free(f1, f1_len); |
free(f2, M_TEMP); |
kmem_free(f2, f2_len); |
} |
} |
#endif /* NVERIEXEC > 0 */ |
#endif /* NVERIEXEC > 0 */ |
|
|
Line 3424 sys_mkdir(struct lwp *l, const struct sy |
|
Line 3486 sys_mkdir(struct lwp *l, const struct sy |
|
syscallarg(const char *) path; |
syscallarg(const char *) path; |
syscallarg(int) mode; |
syscallarg(int) mode; |
} */ |
} */ |
struct proc *p = l->l_proc; |
|
|
return do_sys_mkdir(SCARG(uap, path), SCARG(uap, mode), UIO_USERSPACE); |
|
} |
|
|
|
int |
|
do_sys_mkdir(const char *path, mode_t mode, enum uio_seg seg) |
|
{ |
|
struct proc *p = curlwp->l_proc; |
struct vnode *vp; |
struct vnode *vp; |
struct vattr vattr; |
struct vattr vattr; |
int error; |
int error; |
struct nameidata nd; |
struct nameidata nd; |
|
|
NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, UIO_USERSPACE, |
NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, |
SCARG(uap, path)); |
seg, path); |
if ((error = namei(&nd)) != 0) |
if ((error = namei(&nd)) != 0) |
return (error); |
return (error); |
vp = nd.ni_vp; |
vp = nd.ni_vp; |
Line 3444 sys_mkdir(struct lwp *l, const struct sy |
|
Line 3513 sys_mkdir(struct lwp *l, const struct sy |
|
vrele(vp); |
vrele(vp); |
return (EEXIST); |
return (EEXIST); |
} |
} |
VATTR_NULL(&vattr); |
vattr_null(&vattr); |
vattr.va_type = VDIR; |
vattr.va_type = VDIR; |
/* We will read cwdi->cwdi_cmask unlocked. */ |
/* We will read cwdi->cwdi_cmask unlocked. */ |
vattr.va_mode = |
vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask; |
(SCARG(uap, mode) & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask; |
|
error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); |
error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); |
if (!error) |
if (!error) |
vput(nd.ni_vp); |
vput(nd.ni_vp); |
Line 3569 dorevoke(struct vnode *vp, kauth_cred_t |
|
Line 3637 dorevoke(struct vnode *vp, kauth_cred_t |
|
struct vattr vattr; |
struct vattr vattr; |
int error; |
int error; |
|
|
if ((error = VOP_GETATTR(vp, &vattr, cred)) != 0) |
vn_lock(vp, LK_SHARED | LK_RETRY); |
|
error = VOP_GETATTR(vp, &vattr, cred); |
|
VOP_UNLOCK(vp); |
|
if (error != 0) |
return error; |
return error; |
if (kauth_cred_geteuid(cred) != vattr.va_uid && |
if (kauth_cred_geteuid(cred) == vattr.va_uid || |
(error = kauth_authorize_generic(cred, |
(error = kauth_authorize_generic(cred, |
KAUTH_GENERIC_ISSUSER, NULL)) == 0) |
KAUTH_GENERIC_ISSUSER, NULL)) == 0) |
VOP_REVOKE(vp, REVOKEALL); |
VOP_REVOKE(vp, REVOKEALL); |
Line 3591 sys_revoke(struct lwp *l, const struct s |
|
Line 3662 sys_revoke(struct lwp *l, const struct s |
|
} */ |
} */ |
struct vnode *vp; |
struct vnode *vp; |
int error; |
int error; |
struct nameidata nd; |
|
|
|
NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, |
error = namei_simple_user(SCARG(uap, path), |
SCARG(uap, path)); |
NSM_FOLLOW_TRYEMULROOT, &vp); |
if ((error = namei(&nd)) != 0) |
if (error != 0) |
return (error); |
return (error); |
vp = nd.ni_vp; |
|
error = dorevoke(vp, l->l_cred); |
error = dorevoke(vp, l->l_cred); |
vrele(vp); |
vrele(vp); |
return (error); |
return (error); |
} |
} |
|
|
/* |
|
* Convert a user file descriptor to a kernel file entry. |
|
*/ |
|
int |
|
getvnode(int fd, file_t **fpp) |
|
{ |
|
struct vnode *vp; |
|
file_t *fp; |
|
|
|
if ((fp = fd_getfile(fd)) == NULL) |
|
return (EBADF); |
|
|
|
if (fp->f_type != DTYPE_VNODE) { |
|
fd_putfile(fd); |
|
return (EINVAL); |
|
} |
|
|
|
vp = fp->f_data; |
|
if (vp->v_type == VBAD) { |
|
fd_putfile(fd); |
|
return (EBADF); |
|
} |
|
|
|
*fpp = fp; |
|
return (0); |
|
} |
|