diff options
author | mm <mm@FreeBSD.org> | 2012-01-15 12:08:20 +0000 |
---|---|---|
committer | mm <mm@FreeBSD.org> | 2012-01-15 12:08:20 +0000 |
commit | 9f44ed5ca827811dd8729bb0ab4397c71161fa9c (patch) | |
tree | 7cb3e09e5396eca584100f0f0377b0dd5a33d1ba /sys/kern/kern_jail.c | |
parent | 4642718fb42bef8b06538195461ee680c22cd1f9 (diff) | |
download | FreeBSD-src-9f44ed5ca827811dd8729bb0ab4397c71161fa9c.zip FreeBSD-src-9f44ed5ca827811dd8729bb0ab4397c71161fa9c.tar.gz |
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
Diffstat (limited to 'sys/kern/kern_jail.c')
-rw-r--r-- | sys/kern/kern_jail.c | 50 |
1 files changed, 31 insertions, 19 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 84f5575..de92dc4 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -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 |