mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-20 15:43:16 +00:00
Introduce vn_path_to_global_path()
This function updates path string to vnode's full global path and checks the size of the new path string against the pathlen argument. In vfs_domount(), sys_unmount() and kern_jail_set() this new function is used to update the supplied path argument to the respective global path. Unbreaks jailed zfs(8) with enforce_statfs set to 1. Reviewed by: kib MFC after: 1 month
This commit is contained in:
parent
4347075067
commit
f6e633a9e1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=230129
@ -531,6 +531,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
||||
int gotchildmax, gotenforce, gothid, gotslevel;
|
||||
int fi, jid, jsys, len, level;
|
||||
int childmax, slevel, vfslocked;
|
||||
int fullpath_disabled;
|
||||
#if defined(INET) || defined(INET6)
|
||||
int ii, ij;
|
||||
#endif
|
||||
@ -897,30 +898,40 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
||||
error = EINVAL;
|
||||
goto done_free;
|
||||
}
|
||||
if (len < 2 || (len == 2 && path[0] == '/'))
|
||||
path = NULL;
|
||||
else {
|
||||
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE, UIO_SYSSPACE,
|
||||
path, td);
|
||||
error = namei(&nd);
|
||||
if (error)
|
||||
goto done_free;
|
||||
vfslocked = NDHASGIANT(&nd);
|
||||
root = nd.ni_vp;
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
error = vn_path_to_global_path(td, root, path, MAXPATHLEN);
|
||||
if (error == ENODEV) {
|
||||
/* proceed if sysctl debug.disablefullpath == 1 */
|
||||
fullpath_disabled = 1;
|
||||
if (len < 2 || (len == 2 && path[0] == '/'))
|
||||
path = NULL;
|
||||
} else if (error != 0) {
|
||||
/* exit on other errors */
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
goto done_free;
|
||||
}
|
||||
if (root->v_type != VDIR) {
|
||||
error = ENOTDIR;
|
||||
vput(root);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
goto done_free;
|
||||
}
|
||||
VOP_UNLOCK(root, 0);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
if (fullpath_disabled) {
|
||||
/* Leave room for a real-root full pathname. */
|
||||
if (len + (path[0] == '/' && strcmp(mypr->pr_path, "/")
|
||||
? strlen(mypr->pr_path) : 0) > MAXPATHLEN) {
|
||||
error = ENAMETOOLONG;
|
||||
goto done_free;
|
||||
}
|
||||
NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW, UIO_SYSSPACE,
|
||||
path, td);
|
||||
error = namei(&nd);
|
||||
if (error)
|
||||
goto done_free;
|
||||
vfslocked = NDHASGIANT(&nd);
|
||||
root = nd.ni_vp;
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
if (root->v_type != VDIR) {
|
||||
error = ENOTDIR;
|
||||
vrele(root);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
goto done_free;
|
||||
}
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1583,7 +1594,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
||||
}
|
||||
if (path != NULL) {
|
||||
/* Try to keep a real-rooted full pathname. */
|
||||
if (path[0] == '/' && strcmp(mypr->pr_path, "/"))
|
||||
if (fullpath_disabled && path[0] == '/' &&
|
||||
strcmp(mypr->pr_path, "/"))
|
||||
snprintf(pr->pr_path, sizeof(pr->pr_path), "%s%s",
|
||||
mypr->pr_path, path);
|
||||
else
|
||||
|
@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/proc.h>
|
||||
@ -1278,3 +1279,76 @@ vn_commname(struct vnode *vp, char *buf, u_int buflen)
|
||||
buf[l] = '\0';
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function updates path string to vnode's full global path
|
||||
* and checks the size of the new path string against the pathlen argument.
|
||||
*
|
||||
* Requires a locked, referenced vnode and GIANT lock held.
|
||||
* Vnode is re-locked on success or ENODEV, otherwise unlocked.
|
||||
*
|
||||
* If sysctl debug.disablefullpath is set, ENODEV is returned,
|
||||
* vnode is left locked and path remain untouched.
|
||||
*
|
||||
* If vp is a directory, the call to vn_fullpath_global() always succeeds
|
||||
* because it falls back to the ".." lookup if the namecache lookup fails
|
||||
*/
|
||||
int
|
||||
vn_path_to_global_path(struct thread *td, struct vnode *vp, char *path,
|
||||
u_int pathlen)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct vnode *vp1;
|
||||
char *rpath, *fbuf;
|
||||
int error, vfslocked;
|
||||
|
||||
VFS_ASSERT_GIANT(vp->v_mount);
|
||||
ASSERT_VOP_ELOCKED(vp, __func__);
|
||||
|
||||
/* Return ENODEV if sysctl debug.disablefullpath==1 */
|
||||
if (disablefullpath)
|
||||
return (ENODEV);
|
||||
|
||||
/* Construct global filesystem path from vp. */
|
||||
VOP_UNLOCK(vp, 0);
|
||||
error = vn_fullpath_global(td, vp, &rpath, &fbuf);
|
||||
|
||||
if (error != 0) {
|
||||
vrele(vp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (strlen(rpath) >= pathlen) {
|
||||
vrele(vp);
|
||||
error = ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-lookup the vnode by path to detect a possible rename.
|
||||
* As a side effect, the vnode is relocked.
|
||||
* If vnode was renamed, return ENOENT.
|
||||
*/
|
||||
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
|
||||
UIO_SYSSPACE, path, td);
|
||||
error = namei(&nd);
|
||||
if (error != 0) {
|
||||
vrele(vp);
|
||||
goto out;
|
||||
}
|
||||
vfslocked = NDHASGIANT(&nd);
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
vp1 = nd.ni_vp;
|
||||
vrele(vp);
|
||||
if (vp1 == vp)
|
||||
strcpy(path, rpath);
|
||||
else {
|
||||
vput(vp1);
|
||||
error = ENOENT;
|
||||
}
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
|
||||
out:
|
||||
free(fbuf, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
|
@ -1085,11 +1085,14 @@ vfs_domount(
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
vp = nd.ni_vp;
|
||||
if ((fsflags & MNT_UPDATE) == 0) {
|
||||
error = vfs_domount_first(td, vfsp, fspath, vp, fsflags,
|
||||
optlist);
|
||||
} else {
|
||||
error = vn_path_to_global_path(td, vp, fspath, MNAMELEN);
|
||||
/* debug.disablefullpath == 1 results in ENODEV */
|
||||
if (error == 0 || error == ENODEV) {
|
||||
error = vfs_domount_first(td, vfsp, fspath, vp,
|
||||
fsflags, optlist);
|
||||
}
|
||||
} else
|
||||
error = vfs_domount_update(td, vp, fsflags, optlist);
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
ASSERT_VI_UNLOCKED(vp, __func__);
|
||||
@ -1119,9 +1122,10 @@ sys_unmount(td, uap)
|
||||
int flags;
|
||||
} */ *uap;
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct mount *mp;
|
||||
char *pathbuf;
|
||||
int error, id0, id1;
|
||||
int error, id0, id1, vfslocked;
|
||||
|
||||
AUDIT_ARG_VALUE(uap->flags);
|
||||
if (jailed(td->td_ucred) || usermount == 0) {
|
||||
@ -1155,6 +1159,21 @@ sys_unmount(td, uap)
|
||||
mtx_unlock(&mountlist_mtx);
|
||||
} else {
|
||||
AUDIT_ARG_UPATH1(td, pathbuf);
|
||||
/*
|
||||
* Try to find global path for path argument.
|
||||
*/
|
||||
NDINIT(&nd, LOOKUP,
|
||||
FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
|
||||
UIO_SYSSPACE, pathbuf, td);
|
||||
if (namei(&nd) == 0) {
|
||||
vfslocked = NDHASGIANT(&nd);
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
error = vn_path_to_global_path(td, nd.ni_vp, pathbuf,
|
||||
MNAMELEN);
|
||||
if (error == 0 || error == ENODEV)
|
||||
vput(nd.ni_vp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
}
|
||||
mtx_lock(&mountlist_mtx);
|
||||
TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) {
|
||||
if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0)
|
||||
|
@ -605,6 +605,8 @@ int vn_fullpath(struct thread *td, struct vnode *vn,
|
||||
int vn_fullpath_global(struct thread *td, struct vnode *vn,
|
||||
char **retbuf, char **freebuf);
|
||||
int vn_commname(struct vnode *vn, char *buf, u_int buflen);
|
||||
int vn_path_to_global_path(struct thread *td, struct vnode *vp,
|
||||
char *path, u_int pathlen);
|
||||
int vaccess(enum vtype type, mode_t file_mode, uid_t file_uid,
|
||||
gid_t file_gid, accmode_t accmode, struct ucred *cred,
|
||||
int *privused);
|
||||
|
Loading…
Reference in New Issue
Block a user