diff --git a/sys/kern/kern_jail.c.ident b/sys/kern/kern_jail.c --- a/sys/kern/kern_jail.c.ident +++ b/sys/kern/kern_jail.c @@ -118,6 +118,7 @@ .pr_flags = PR_HOST|_PR_IP_SADDRSEL, #endif .pr_allow = PR_ALLOW_ALL_STATIC, + .pr_ident = 1, }; MTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); @@ -988,6 +989,7 @@ uint64_t pr_allow_diff; unsigned tallow; char numbuf[12]; + static uint64_t init_ident = 2; error = priv_check(td, PRIV_JAIL_SET); if (!error && (flags & JAIL_ATTACH)) @@ -1617,6 +1619,7 @@ TASK_INIT(&pr->pr_task, 0, prison_complete, pr); pr->pr_id = jid; + pr->pr_ident = init_ident++; if (inspr != NULL) TAILQ_INSERT_BEFORE(inspr, pr, pr_list); else diff --git a/sys/kern/vfs_export.c.vnet b/sys/kern/vfs_export.c --- a/sys/kern/vfs_export.c.vnet +++ b/sys/kern/vfs_export.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -301,6 +302,7 @@ { struct netexport *nep; int error; + uint64_t jail_ident; if ((argp->ex_flags & (MNT_DELEXPORT | MNT_EXPORTED)) == 0) return (EINVAL); @@ -311,13 +313,28 @@ return (EINVAL); error = 0; + jail_ident = curthread->td_ucred->cr_prison->pr_ident; lockmgr(&mp->mnt_explock, LK_EXCLUSIVE, NULL); nep = mp->mnt_export; if (argp->ex_flags & MNT_DELEXPORT) { if (nep == NULL) { + KASSERT(mp->mnt_exjail == 0, + ("vfs_export: mnt_exjail delexport not 0")); error = ENOENT; goto out; } + KASSERT(mp->mnt_exjail != 0, + ("vfs_export: mnt_exjail delexport 0")); + if (jail_ident == 1 && mp->mnt_exjail != + jail_ident) { + /* EXDEV will not get logged by mountd(8). */ + error = EXDEV; + goto out; + } else if (mp->mnt_exjail != jail_ident) { + /* EPERM will get logged by mountd(8). */ + error = EPERM; + goto out; + } if (mp->mnt_flag & MNT_EXPUBLIC) { vfs_setpublicfs(NULL, NULL, NULL); MNT_ILOCK(mp); @@ -326,6 +343,7 @@ } vfs_free_addrlist(nep); mp->mnt_export = NULL; + mp->mnt_exjail = 0; free(nep, M_MOUNT); nep = NULL; MNT_ILOCK(mp); @@ -334,8 +352,15 @@ } if (argp->ex_flags & MNT_EXPORTED) { if (nep == NULL) { + KASSERT(mp->mnt_exjail == 0, + ("vfs_export: mnt_exjail not 0")); nep = malloc(sizeof(struct netexport), M_MOUNT, M_WAITOK | M_ZERO); mp->mnt_export = nep; + } else if (mp->mnt_exjail != jail_ident) { + KASSERT(mp->mnt_exjail != 0, + ("vfs_export: mnt_exjail 0")); + error = EPERM; + goto out; } if (argp->ex_flags & MNT_EXPUBLIC) { if ((error = vfs_setpublicfs(mp, nep, argp)) != 0) @@ -350,6 +375,7 @@ } if ((error = vfs_hang_addrlist(mp, nep, argp))) goto out; + mp->mnt_exjail = jail_ident; MNT_ILOCK(mp); mp->mnt_flag |= MNT_EXPORTED; MNT_IUNLOCK(mp); diff --git a/sys/sys/jail.h.ident b/sys/sys/jail.h --- a/sys/sys/jail.h.ident +++ b/sys/sys/jail.h @@ -205,6 +205,7 @@ char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */ char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */ char pr_osrelease[OSRELEASELEN]; /* (c) kern.osrelease value */ + uint64_t pr_ident; /* (c) unique identifier */ }; struct prison_racct { diff --git a/sys/sys/mount.h.ident b/sys/sys/mount.h --- a/sys/sys/mount.h.ident +++ b/sys/sys/mount.h @@ -252,6 +252,7 @@ int mnt_secondary_writes; /* (i) # of secondary writes */ int mnt_secondary_accwrites;/* (i) secondary wr. starts */ struct thread *mnt_susp_owner; /* (i) thread owning suspension */ + uint64_t mnt_exjail; /* exported in jail ident */ #define mnt_endzero mnt_gjprovider char *mnt_gjprovider; /* gjournal provider name */ struct mtx mnt_listmtx;