Date: Mon, 13 Nov 2017 23:21:17 +0000 (UTC) From: Jamie Gritton <jamie@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r325783 - stable/10/sys/kern Message-ID: <201711132321.vADNLHDJ096102@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jamie Date: Mon Nov 13 23:21:17 2017 New Revision: 325783 URL: https://svnweb.freebsd.org/changeset/base/325783 Log: MFC r297935: Separate POSIX sem/shm objects in jails, by prepending the jail's path name to the object's "path". While the objects don't have real path names, it's a filesystem-like namespace, which allows jails to be kept to their own space, but still allows the system / jail parent to access a jail's IPC. MFC r297936: Separate POSIX mqueue objects in jails; actually, separate them by the jail's root, so jails that don't have their own filesystem directory also won't have their own mqueue namespace. MFC r297976: Clean up some style(9) violations. MFC r298567: Use the new PR_METHOD_REMOVE to clean up jail handling in POSIX message queues. PR: 208082 Submitted by: delphij Modified: stable/10/sys/kern/uipc_mqueue.c stable/10/sys/kern/uipc_sem.c stable/10/sys/kern/uipc_shm.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/kern/uipc_mqueue.c ============================================================================== --- stable/10/sys/kern/uipc_mqueue.c Mon Nov 13 22:16:47 2017 (r325782) +++ stable/10/sys/kern/uipc_mqueue.c Mon Nov 13 23:21:17 2017 (r325783) @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/systm.h> #include <sys/limits.h> +#include <sys/malloc.h> #include <sys/buf.h> #include <sys/capsicum.h> #include <sys/dirent.h> @@ -60,8 +61,8 @@ __FBSDID("$FreeBSD$"); #include <sys/fcntl.h> #include <sys/file.h> #include <sys/filedesc.h> +#include <sys/jail.h> #include <sys/lock.h> -#include <sys/malloc.h> #include <sys/module.h> #include <sys/mount.h> #include <sys/mqueue.h> @@ -131,6 +132,7 @@ struct mqfs_node { LIST_HEAD(,mqfs_node) mn_children; LIST_ENTRY(mqfs_node) mn_sibling; LIST_HEAD(,mqfs_vdata) mn_vnodes; + const void *mn_pr_root; int mn_refcount; mqfs_type_t mn_type; int mn_deleted; @@ -218,6 +220,7 @@ static uma_zone_t mvdata_zone; static uma_zone_t mqnoti_zone; static struct vop_vector mqfs_vnodeops; static struct fileops mqueueops; +static unsigned mqfs_osd_jail_slot; /* * Directory structure construction and manipulation @@ -235,6 +238,7 @@ static int mqfs_destroy(struct mqfs_node *mn); static void mqfs_fileno_alloc(struct mqfs_info *mi, struct mqfs_node *mn); static void mqfs_fileno_free(struct mqfs_info *mi, struct mqfs_node *mn); static int mqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn); +static int mqfs_prison_remove(void *obj, void *data); /* * Message queue construction and maniplation @@ -435,6 +439,7 @@ mqfs_create_node(const char *name, int namelen, struct node = mqnode_alloc(); strncpy(node->mn_name, name, namelen); + node->mn_pr_root = cred->cr_prison->pr_root; node->mn_type = nodetype; node->mn_refcount = 1; vfs_timestamp(&node->mn_birth); @@ -643,6 +648,9 @@ mqfs_init(struct vfsconf *vfc) { struct mqfs_node *root; struct mqfs_info *mi; + osd_method_t methods[PR_MAXMETHOD] = { + [PR_METHOD_REMOVE] = mqfs_prison_remove, + }; mqnode_zone = uma_zcreate("mqnode", sizeof(struct mqfs_node), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); @@ -669,6 +677,7 @@ mqfs_init(struct vfsconf *vfc) EVENTHANDLER_PRI_ANY); mq_fdclose = mqueue_fdclose; p31b_setcfg(CTL_P1003_1B_MESSAGE_PASSING, _POSIX_MESSAGE_PASSING); + mqfs_osd_jail_slot = osd_jail_register(NULL, methods); return (0); } @@ -682,6 +691,7 @@ mqfs_uninit(struct vfsconf *vfc) if (!unloadable) return (EOPNOTSUPP); + osd_jail_deregister(mqfs_osd_jail_slot); EVENTHANDLER_DEREGISTER(process_exit, exit_tag); mi = &mqfs_data; mqfs_destroy(mi->mi_root); @@ -801,13 +811,17 @@ found: * Search a directory entry */ static struct mqfs_node * -mqfs_search(struct mqfs_node *pd, const char *name, int len) +mqfs_search(struct mqfs_node *pd, const char *name, int len, struct ucred *cred) { struct mqfs_node *pn; + const void *pr_root; sx_assert(&pd->mn_info->mi_lock, SX_LOCKED); + pr_root = cred->cr_prison->pr_root; LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { - if (strncmp(pn->mn_name, name, len) == 0 && + /* Only match names within the same prison root directory */ + if ((pn->mn_pr_root == NULL || pn->mn_pr_root == pr_root) && + strncmp(pn->mn_name, name, len) == 0 && pn->mn_name[len] == '\0') return (pn); } @@ -879,7 +893,7 @@ mqfs_lookupx(struct vop_cachedlookup_args *ap) /* named node */ sx_xlock(&mqfs->mi_lock); - pn = mqfs_search(pd, pname, namelen); + pn = mqfs_search(pd, pname, namelen, cnp->cn_cred); if (pn != NULL) mqnode_addref(pn); sx_xunlock(&mqfs->mi_lock); @@ -1364,6 +1378,7 @@ mqfs_readdir(struct vop_readdir_args *ap) struct mqfs_node *pn; struct dirent entry; struct uio *uio; + const void *pr_root; int *tmp_ncookies = NULL; off_t offset; int error, i; @@ -1388,10 +1403,18 @@ mqfs_readdir(struct vop_readdir_args *ap) error = 0; offset = 0; + pr_root = ap->a_cred->cr_prison->pr_root; sx_xlock(&mi->mi_lock); LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { entry.d_reclen = sizeof(entry); + + /* + * Only show names within the same prison root directory + * (or not associated with a prison, e.g. "." and ".."). + */ + if (pn->mn_pr_root != NULL && pn->mn_pr_root != pr_root) + continue; if (!pn->mn_fileno) mqfs_fileno_alloc(mi, pn); entry.d_fileno = pn->mn_fileno; @@ -1525,6 +1548,38 @@ mqfs_rmdir(struct vop_rmdir_args *ap) #endif /* notyet */ /* + * See if this prison root is obsolete, and clean up associated queues if it is. + */ +static int +mqfs_prison_remove(void *obj, void *data __unused) +{ + const struct prison *pr = obj; + const struct prison *tpr; + struct mqfs_node *pn, *tpn; + int found; + + found = 0; + TAILQ_FOREACH(tpr, &allprison, pr_list) { + if (tpr->pr_root == pr->pr_root && tpr != pr && tpr->pr_ref > 0) + found = 1; + } + if (!found) { + /* + * No jails are rooted in this directory anymore, + * so no queues should be either. + */ + sx_xlock(&mqfs_data.mi_lock); + LIST_FOREACH_SAFE(pn, &mqfs_data.mi_root->mn_children, + mn_sibling, tpn) { + if (pn->mn_pr_root == pr->pr_root) + (void)do_unlink(pn, curthread->td_ucred); + } + sx_xunlock(&mqfs_data.mi_lock); + } + return (0); +} + +/* * Allocate a message queue */ static struct mqueue * @@ -1984,7 +2039,7 @@ kern_kmq_open(struct thread *td, const char *upath, in return (error); sx_xlock(&mqfs_data.mi_lock); - pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1); + pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1, td->td_ucred); if (pn == NULL) { if (!(flags & O_CREAT)) { error = ENOENT; @@ -2079,7 +2134,7 @@ sys_kmq_unlink(struct thread *td, struct kmq_unlink_ar return (EINVAL); sx_xlock(&mqfs_data.mi_lock); - pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1); + pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1, td->td_ucred); if (pn != NULL) error = do_unlink(pn, td->td_ucred); else Modified: stable/10/sys/kern/uipc_sem.c ============================================================================== --- stable/10/sys/kern/uipc_sem.c Mon Nov 13 22:16:47 2017 (r325782) +++ stable/10/sys/kern/uipc_sem.c Mon Nov 13 23:21:17 2017 (r325783) @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <sys/file.h> #include <sys/filedesc.h> #include <sys/fnv_hash.h> +#include <sys/jail.h> #include <sys/kernel.h> #include <sys/ksem.h> #include <sys/lock.h> @@ -444,12 +445,24 @@ ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucr static void ksem_info_impl(struct ksem *ks, char *path, size_t size, uint32_t *value) { + const char *ks_path, *pr_path; + size_t pr_pathlen; if (ks->ks_path == NULL) return; sx_slock(&ksem_dict_lock); - if (ks->ks_path != NULL) - strlcpy(path, ks->ks_path, size); + ks_path = ks->ks_path; + if (ks_path != NULL) { + pr_path = curthread->td_ucred->cr_prison->pr_path; + if (strcmp(pr_path, "/") != 0) { + /* Return the jail-rooted pathname. */ + pr_pathlen = strlen(pr_path); + if (strncmp(ks_path, pr_path, pr_pathlen) == 0 && + ks_path[pr_pathlen] == '/') + ks_path += pr_pathlen; + } + strlcpy(path, ks_path, size); + } if (value != NULL) *value = ks->ks_value; sx_sunlock(&ksem_dict_lock); @@ -493,6 +506,8 @@ ksem_create(struct thread *td, const char *name, semid struct ksem *ks; struct file *fp; char *path; + const char *pr_path; + size_t pr_pathlen; Fnv32_t fnv; int error, fd; @@ -529,10 +544,16 @@ ksem_create(struct thread *td, const char *name, semid ks->ks_flags |= KS_ANONYMOUS; } else { path = malloc(MAXPATHLEN, M_KSEM, M_WAITOK); - error = copyinstr(name, path, MAXPATHLEN, NULL); + pr_path = td->td_ucred->cr_prison->pr_path; + /* Construct a full pathname for jailed callers. */ + pr_pathlen = strcmp(pr_path, "/") == 0 ? 0 + : strlcpy(path, pr_path, MAXPATHLEN); + error = copyinstr(name, path + pr_pathlen, + MAXPATHLEN - pr_pathlen, NULL); + /* Require paths to start with a '/' character. */ - if (error == 0 && path[0] != '/') + if (error == 0 && path[pr_pathlen] != '/') error = EINVAL; if (error) { fdclose(td, fp, fd); @@ -668,11 +689,17 @@ int sys_ksem_unlink(struct thread *td, struct ksem_unlink_args *uap) { char *path; + const char *pr_path; + size_t pr_pathlen; Fnv32_t fnv; int error; path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); - error = copyinstr(uap->name, path, MAXPATHLEN, NULL); + pr_path = td->td_ucred->cr_prison->pr_path; + pr_pathlen = strcmp(pr_path, "/") == 0 ? 0 + : strlcpy(path, pr_path, MAXPATHLEN); + error = copyinstr(uap->name, path + pr_pathlen, MAXPATHLEN - pr_pathlen, + NULL); if (error) { free(path, M_TEMP); return (error); Modified: stable/10/sys/kern/uipc_shm.c ============================================================================== --- stable/10/sys/kern/uipc_shm.c Mon Nov 13 22:16:47 2017 (r325782) +++ stable/10/sys/kern/uipc_shm.c Mon Nov 13 23:21:17 2017 (r325783) @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/uio.h> #include <sys/signal.h> +#include <sys/jail.h> #include <sys/ktrace.h> #include <sys/lock.h> #include <sys/malloc.h> @@ -712,6 +713,8 @@ sys_shm_open(struct thread *td, struct shm_open_args * struct shmfd *shmfd; struct file *fp; char *path; + const char *pr_path; + size_t pr_pathlen; Fnv32_t fnv; mode_t cmode; int fd, error; @@ -749,13 +752,19 @@ sys_shm_open(struct thread *td, struct shm_open_args * shmfd = shm_alloc(td->td_ucred, cmode); } else { path = malloc(MAXPATHLEN, M_SHMFD, M_WAITOK); - error = copyinstr(uap->path, path, MAXPATHLEN, NULL); + pr_path = td->td_ucred->cr_prison->pr_path; + + /* Construct a full pathname for jailed callers. */ + pr_pathlen = strcmp(pr_path, "/") == 0 ? 0 + : strlcpy(path, pr_path, MAXPATHLEN); + error = copyinstr(uap->path, path + pr_pathlen, + MAXPATHLEN - pr_pathlen, NULL); #ifdef KTRACE if (error == 0 && KTRPOINT(curthread, KTR_NAMEI)) ktrnamei(path); #endif /* Require paths to start with a '/' character. */ - if (error == 0 && path[0] != '/') + if (error == 0 && path[pr_pathlen] != '/') error = EINVAL; if (error) { fdclose(td, fp, fd); @@ -842,11 +851,17 @@ int sys_shm_unlink(struct thread *td, struct shm_unlink_args *uap) { char *path; + const char *pr_path; + size_t pr_pathlen; Fnv32_t fnv; int error; path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); - error = copyinstr(uap->path, path, MAXPATHLEN, NULL); + pr_path = td->td_ucred->cr_prison->pr_path; + pr_pathlen = strcmp(pr_path, "/") == 0 ? 0 + : strlcpy(path, pr_path, MAXPATHLEN); + error = copyinstr(uap->path, path + pr_pathlen, MAXPATHLEN - pr_pathlen, + NULL); if (error) { free(path, M_TEMP); return (error); @@ -1053,11 +1068,23 @@ shm_unmap(struct file *fp, void *mem, size_t size) void shm_path(struct shmfd *shmfd, char *path, size_t size) { + const char *shm_path, *pr_path; + size_t pr_pathlen; if (shmfd->shm_path == NULL) return; sx_slock(&shm_dict_lock); - if (shmfd->shm_path != NULL) - strlcpy(path, shmfd->shm_path, size); + shm_path = shmfd->shm_path; + if (shm_path != NULL) { + pr_path = curthread->td_ucred->cr_prison->pr_path; + if (strcmp(pr_path, "/") != 0) { + /* Return the jail-rooted pathname. */ + pr_pathlen = strlen(pr_path); + if (strncmp(shm_path, pr_path, pr_pathlen) == 0 && + shm_path[pr_pathlen] == '/') + shm_path += pr_pathlen; + } + strlcpy(path, shm_path, size); + } sx_sunlock(&shm_dict_lock); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201711132321.vADNLHDJ096102>