#include <sys/ubc.h>
#include <sys/types.h>
#include <sys/dirent.h>
+#include <sys/kauth.h>
#include "nullfs.h"
return result;
}
+vfs_context_t
+nullfs_get_patched_context(struct null_mount * null_mp, vfs_context_t ctx)
+{
+ struct vfs_context* ectx = ctx;
+ if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
+ ectx = vfs_context_create(ctx);
+ ectx->vc_ucred = kauth_cred_setuidgid(ectx->vc_ucred, null_mp->uid, null_mp->gid);
+ }
+ return ectx;
+}
+
+void
+nullfs_cleanup_patched_context(struct null_mount * null_mp, vfs_context_t ctx)
+{
+ if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
+ vfs_context_rele(ctx);
+ }
+}
+
static int
nullfs_default(__unused struct vnop_generic_args * args)
{
ino_t ino = NULL_ROOT_INO;
struct vnode_attr covered_rootattr;
vnode_t checkvp = null_mp->nullm_lowerrootvp;
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
VATTR_INIT(&covered_rootattr);
VATTR_WANTED(&covered_rootattr, va_uid);
if (vnode_getwithvid(checkvp, null_mp->nullm_lowerrootvid)) {
checkvp = vfs_vnodecovered(mp);
if (checkvp == NULL) {
+ nullfs_cleanup_patched_context(null_mp, ectx);
return EIO;
}
}
- int error = vnode_getattr(checkvp, &covered_rootattr, args->a_context);
+ int error = vnode_getattr(checkvp, &covered_rootattr, ectx);
vnode_put(checkvp);
if (error) {
/* we should have been able to get attributes fore one of the two choices so
* fail if we didn't */
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
VATTR_RETURN(args->a_vap, va_iosize, vfs_statfs(mp)->f_iosize);
VATTR_RETURN(args->a_vap, va_fileid, ino);
VATTR_RETURN(args->a_vap, va_linkid, ino);
- VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(mp)->f_fsid.val[0]); // return the fsid of the mount point
+ if (VATTR_IS_ACTIVE(args->a_vap, va_fsid)) {
+ VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(mp)->f_fsid.val[0]); // return the fsid of the mount point
+ }
+ if (VATTR_IS_ACTIVE(args->a_vap, va_fsid64)) {
+ VATTR_RETURN(args->a_vap, va_fsid64, vfs_statfs(mp)->f_fsid);
+ }
VATTR_RETURN(args->a_vap, va_filerev, 0);
VATTR_RETURN(args->a_vap, va_gen, 0);
VATTR_RETURN(args->a_vap, va_flags, UF_HIDDEN); /* mark our fake directories as hidden. People
args->a_vap->va_modify_time.tv_nsec = covered_rootattr.va_access_time.tv_nsec;
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return 0;
}
{
int error;
struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
+ kauth_cred_t cred = vfs_context_ucred(args->a_context);
NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
lck_mtx_lock(&null_mp->nullm_lock);
/* this will return a different inode for third than read dir will */
struct vnode * lowervp = NULLVPTOLOWERVP(args->a_vp);
-
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
error = vnode_getwithref(lowervp);
+
if (error == 0) {
- error = VNOP_GETATTR(lowervp, args->a_vap, args->a_context);
+ error = VNOP_GETATTR(lowervp, args->a_vap, ectx);
vnode_put(lowervp);
if (error == 0) {
/* fix up fsid so it doesn't say the underlying fs*/
- VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(vnode_mount(args->a_vp))->f_fsid.val[0]);
+ if (VATTR_IS_ACTIVE(args->a_vap, va_fsid)) {
+ VATTR_RETURN(args->a_vap, va_fsid, vfs_statfs(vnode_mount(args->a_vp))->f_fsid.val[0]);
+ }
+ if (VATTR_IS_ACTIVE(args->a_vap, va_fsid64)) {
+ VATTR_RETURN(args->a_vap, va_fsid64, vfs_statfs(vnode_mount(args->a_vp))->f_fsid);
+ }
+
+ /* Conjure up permissions */
+ if ((null_mp->nullm_flags & NULLM_UNVEIL) == NULLM_UNVEIL) {
+ if (VATTR_IS_ACTIVE(args->a_vap, va_mode)) {
+ mode_t mode = args->a_vap->va_mode; // We will take away permisions if we don't have them
+
+ // Check for authorizations
+ // If we can read:
+ if (vnode_authorize(lowervp, NULL, KAUTH_VNODE_GENERIC_READ_BITS, ectx) == 0) {
+ mode |= S_IRUSR;
+ } else {
+ mode &= ~S_IRUSR;
+ }
+
+ // Or execute
+ // Directories need an execute bit...
+ if (vnode_authorize(lowervp, NULL, KAUTH_VNODE_GENERIC_EXECUTE_BITS, ectx) == 0) {
+ mode |= S_IXUSR;
+ } else {
+ mode &= ~S_IXUSR;
+ }
+
+ NULLFSDEBUG("Settings bits to %d\n", mode);
+ VATTR_RETURN(args->a_vap, va_mode, mode);
+ }
+ if (VATTR_IS_ACTIVE(args->a_vap, va_uid)) {
+ VATTR_RETURN(args->a_vap, va_uid, kauth_cred_getuid(cred));
+ }
+ if (VATTR_IS_ACTIVE(args->a_vap, va_gid)) {
+ VATTR_RETURN(args->a_vap, va_gid, kauth_cred_getgid(cred));
+ }
+ }
}
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
{
int error;
struct vnode *vp, *lvp;
-
+ mount_t mp = vnode_mount(args->a_vp);
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
if (nullfs_checkspecialvp(args->a_vp)) {
return 0; /* nothing extra needed */
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
vp = args->a_vp;
lvp = NULLVPTOLOWERVP(vp);
error = vnode_getwithref(lvp);
if (error == 0) {
- error = VNOP_OPEN(lvp, args->a_mode, args->a_context);
+ error = VNOP_OPEN(lvp, args->a_mode, ectx);
vnode_put(lvp);
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
{
int error;
struct vnode *vp, *lvp;
+ mount_t mp = vnode_mount(args->a_vp);
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
return 0; /* nothing extra needed */
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
vp = args->a_vp;
lvp = NULLVPTOLOWERVP(vp);
error = vnode_getwithref(lvp);
if (error == 0) {
- error = VNOP_CLOSE(lvp, args->a_fflag, args->a_context);
+ error = VNOP_CLOSE(lvp, args->a_fflag, ectx);
vnode_put(lvp);
}
+
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
struct mount * mp = vnode_mount(dvp);
struct null_mount * null_mp = MOUNTTONULLMOUNT(mp);
int error = ENOENT;
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
if (dvp == null_mp->nullm_rootvp) {
/* handle . and .. */
* so we got a match
* 4. Anything else results in ENOENT.
*/
- error = null_get_lowerparent(null_mp->nullm_lowerrootvp, &ldvp, ap->a_context);
+ error = null_get_lowerparent(null_mp->nullm_lowerrootvp, &ldvp, ectx);
if (error == 0) {
- error = VNOP_LOOKUP(ldvp, &lvp, cnp, ap->a_context);
+ error = VNOP_LOOKUP(ldvp, &lvp, cnp, ectx);
vnode_put(ldvp);
if (error == 0) {
}
end:
+ nullfs_cleanup_patched_context(null_mp, ectx);
if (error == 0) {
*ap->a_vpp = vp;
}
struct mount * mp;
struct null_mount * null_mp;
int error;
+ vfs_context_t ectx;
NULLFSDEBUG("%s parent: %p component: %.*s\n", __FUNCTION__, ap->a_dvp, cnp->cn_namelen, cnp->cn_nameptr);
}
null_mp = MOUNTTONULLMOUNT(mp);
+
lck_mtx_lock(&null_mp->nullm_lock);
if (nullfs_isspecialvp(dvp)) {
error = null_special_lookup(ap);
}
notdot:
+ ectx = nullfs_get_patched_context(null_mp, ap->a_context);
ldvp = NULLVPTOLOWERVP(dvp);
vp = lvp = NULL;
*/
error = vnode_getwithref(ldvp);
if (error) {
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
- error = VNOP_LOOKUP(ldvp, &lvp, cnp, ap->a_context);
+ error = VNOP_LOOKUP(ldvp, &lvp, cnp, ectx);
vnode_put(ldvp);
vnode_put(lvp);
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
}
lck_mtx_unlock(&null_mp->nullm_lock);
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
vp = ap->a_vp;
lvp = NULLVPTOLOWERVP(vp);
error = vnode_getwithref(lvp);
if (error == 0) {
- error = VNOP_READDIR(lvp, ap->a_uio, ap->a_flags, ap->a_eofflag, ap->a_numdirent, ap->a_context);
+ error = VNOP_READDIR(lvp, ap->a_uio, ap->a_flags, ap->a_eofflag, ap->a_numdirent, ectx);
vnode_put(lvp);
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
int error;
struct vnode *vp, *lvp;
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
if (nullfs_checkspecialvp(ap->a_vp)) {
return ENOTSUP; /* the special vnodes aren't links */
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
vp = ap->a_vp;
lvp = NULLVPTOLOWERVP(vp);
error = vnode_getwithref(lvp);
if (error == 0) {
- error = VNOP_READLINK(lvp, ap->a_uio, ap->a_context);
+ error = VNOP_READLINK(lvp, ap->a_uio, ectx);
vnode_put(lvp);
if (error) {
}
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
{
int error;
struct vnode *vp, *lvp;
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
return 0; /* nothing extra needed */
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
vp = args->a_vp;
lvp = NULLVPTOLOWERVP(vp);
error = vnode_getwithref(lvp);
if (error == 0) {
- error = VNOP_MMAP(lvp, args->a_fflags, args->a_context);
+ error = VNOP_MMAP(lvp, args->a_fflags, ectx);
vnode_put(lvp);
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
{
int error;
struct vnode *vp, *lvp;
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
return 0; /* nothing extra needed */
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
vp = args->a_vp;
lvp = NULLVPTOLOWERVP(vp);
error = vnode_getwithref(lvp);
if (error == 0) {
- error = VNOP_MNOMAP(lvp, args->a_context);
+ error = VNOP_MNOMAP(lvp, ectx);
vnode_put(lvp);
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
{
int error;
struct vnode *vp, *lvp;
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
return ENOATTR; /* no xattrs on the special vnodes */
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
vp = args->a_vp;
lvp = NULLVPTOLOWERVP(vp);
error = vnode_getwithref(lvp);
if (error == 0) {
- error = VNOP_GETXATTR(lvp, args->a_name, args->a_uio, args->a_size, args->a_options, args->a_context);
+ error = VNOP_GETXATTR(lvp, args->a_name, args->a_uio, args->a_size, args->a_options, ectx);
vnode_put(lvp);
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
{
int error;
struct vnode *vp, *lvp;
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(args->a_vp));
NULLFSDEBUG("%s %p\n", __FUNCTION__, args->a_vp);
return 0; /* no xattrs on the special vnodes */
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, args->a_context);
vp = args->a_vp;
lvp = NULLVPTOLOWERVP(vp);
error = vnode_getwithref(lvp);
if (error == 0) {
- error = VNOP_LISTXATTR(lvp, args->a_uio, args->a_size, args->a_options, args->a_context);
+ error = VNOP_LISTXATTR(lvp, args->a_uio, args->a_size, args->a_options, ectx);
vnode_put(lvp);
}
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
{
int error = EIO;
struct vnode *vp, *lvp;
-
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
vp = ap->a_vp;
return ENOTSUP;
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
/*
* Ask VM/UBC/VFS to do our bidding
*/
(void)ubc_setsize(vp, lowersize); /* ignore failures, nothing can be done */
}
- error = VNOP_READ(lvp, auio, ((ap->a_flags & UPL_IOSYNC) ? IO_SYNC : 0), ap->a_context);
+ error = VNOP_READ(lvp, auio, ((ap->a_flags & UPL_IOSYNC) ? IO_SYNC : 0), ectx);
bytes_remaining = uio_resid(auio);
if (bytes_remaining > 0 && bytes_remaining <= (user_ssize_t)ap->a_size) {
} else if ((ap->a_flags & UPL_NOCOMMIT) == 0) {
ubc_upl_abort_range(ap->a_pl, ap->a_pl_offset, (upl_size_t)ap->a_size, UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
}
+
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}
int error = EIO;
struct vnode *vp, *lvp;
-
+ struct null_mount * null_mp = MOUNTTONULLMOUNT(vnode_mount(ap->a_vp));
NULLFSDEBUG("%s %p\n", __FUNCTION__, ap->a_vp);
if (nullfs_checkspecialvp(ap->a_vp)) {
return ENOTSUP; /* the special vnodes can't be read */
}
+ vfs_context_t ectx = nullfs_get_patched_context(null_mp, ap->a_context);
vp = ap->a_vp;
lvp = NULLVPTOLOWERVP(vp);
* Now ask VM/UBC/VFS to do our bidding
*/
- error = VNOP_READ(lvp, ap->a_uio, ap->a_ioflag, ap->a_context);
+ error = VNOP_READ(lvp, ap->a_uio, ap->a_ioflag, ectx);
if (error) {
NULLFSDEBUG("VNOP_READ failed: %d\n", error);
}
end:
vnode_put(lvp);
}
+
+ nullfs_cleanup_patched_context(null_mp, ectx);
return error;
}