Page MenuHomeFreeBSD

D38371.id116446.diff
No OneTemporary

D38371.id116446.diff

diff --git a/sys/kern/kern_jail.c.ident2 b/sys/kern/kern_jail.c
--- a/sys/kern/kern_jail.c.ident2
+++ b/sys/kern/kern_jail.c
@@ -3328,6 +3328,7 @@
{
sx_assert(&allprison_lock, SA_XLOCKED);
mtx_assert(&pr->pr_mtx, MA_NOTOWNED);
+ vfs_exjail_delete(pr);
shm_remove_prison(pr);
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL);
}
diff --git a/sys/kern/vfs_export.c.ident b/sys/kern/vfs_export.c
--- a/sys/kern/vfs_export.c.ident
+++ b/sys/kern/vfs_export.c
@@ -52,6 +52,7 @@
#include <sys/mbuf.h>
#include <sys/mount.h>
#include <sys/mutex.h>
+#include <sys/proc.h>
#include <sys/rmlock.h>
#include <sys/refcount.h>
#include <sys/signalvar.h>
@@ -70,7 +71,6 @@
static struct radix_node_head *vfs_create_addrlist_af(
struct radix_node_head **prnh, int off);
#endif
-static void vfs_free_addrlist(struct netexport *nep);
static int vfs_free_netcred(struct radix_node *rn, void *w);
static void vfs_free_addrlist_af(struct radix_node_head **prnh);
static int vfs_hang_addrlist(struct mount *mp, struct netexport *nep,
@@ -274,7 +274,7 @@
/*
* Free the net address hash lists that are hanging off the mount points.
*/
-static void
+void
vfs_free_addrlist(struct netexport *nep)
{
struct ucred *cred;
@@ -285,8 +285,10 @@
vfs_free_addrlist_af(&nep->ne6);
cred = nep->ne_defexported.netc_anon;
- if (cred != NULL)
+ if (cred != NULL) {
crfree(cred);
+ nep->ne_defexported.netc_anon = NULL;
+ }
}
@@ -295,12 +297,18 @@
* and the passed in netexport.
* Struct export_args *argp is the variable used to twiddle options,
* the structure is described in sys/mount.h
+ * The do_exjail argument should be true if *mp is in the mountlist
+ * and false if not. It is not in the mountlist for the NFSv4 rootfs
+ * fake mount point just used for exports.
*/
int
-vfs_export(struct mount *mp, struct export_args *argp)
+vfs_export(struct mount *mp, struct export_args *argp, bool do_exjail)
{
struct netexport *nep;
+ struct ucred *cr;
+ struct prison *pr;
int error;
+ bool new_nep;
if ((argp->ex_flags & (MNT_DELEXPORT | MNT_EXPORTED)) == 0)
return (EINVAL);
@@ -311,6 +319,7 @@
return (EINVAL);
error = 0;
+ pr = curthread->td_ucred->cr_prison;
lockmgr(&mp->mnt_explock, LK_EXCLUSIVE, NULL);
nep = mp->mnt_export;
if (argp->ex_flags & MNT_DELEXPORT) {
@@ -318,6 +327,21 @@
error = ENOENT;
goto out;
}
+ MNT_ILOCK(mp);
+ if (mp->mnt_exjail != NULL && mp->mnt_exjail->cr_prison != pr &&
+ pr == &prison0) {
+ MNT_IUNLOCK(mp);
+ /* EXDEV will not get logged by mountd(8). */
+ error = EXDEV;
+ goto out;
+ } else if (mp->mnt_exjail != NULL &&
+ mp->mnt_exjail->cr_prison != pr) {
+ MNT_IUNLOCK(mp);
+ /* EPERM will get logged by mountd(8). */
+ error = EPERM;
+ goto out;
+ }
+ MNT_IUNLOCK(mp);
if (mp->mnt_flag & MNT_EXPUBLIC) {
vfs_setpublicfs(NULL, NULL, NULL);
MNT_ILOCK(mp);
@@ -329,18 +353,51 @@
free(nep, M_MOUNT);
nep = NULL;
MNT_ILOCK(mp);
+ cr = mp->mnt_exjail;
+ mp->mnt_exjail = NULL;
mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);
MNT_IUNLOCK(mp);
+ if (cr != NULL) {
+ atomic_add_int(&pr->pr_exportcnt, -1);
+ crfree(cr);
+ }
}
if (argp->ex_flags & MNT_EXPORTED) {
+ new_nep = false;
+ MNT_ILOCK(mp);
+ if (mp->mnt_exjail == NULL) {
+ MNT_IUNLOCK(mp);
+ if (do_exjail && nep != NULL) {
+ vfs_free_addrlist(nep);
+ memset(nep, 0, sizeof(*nep));
+ new_nep = true;
+ }
+ } else if (mp->mnt_exjail->cr_prison != pr) {
+ MNT_IUNLOCK(mp);
+ error = EPERM;
+ goto out;
+ } else
+ MNT_IUNLOCK(mp);
if (nep == NULL) {
- nep = malloc(sizeof(struct netexport), M_MOUNT, M_WAITOK | M_ZERO);
+ nep = malloc(sizeof(struct netexport), M_MOUNT,
+ M_WAITOK | M_ZERO);
mp->mnt_export = nep;
+ new_nep = true;
}
if (argp->ex_flags & MNT_EXPUBLIC) {
- if ((error = vfs_setpublicfs(mp, nep, argp)) != 0)
+ if ((error = vfs_setpublicfs(mp, nep, argp)) != 0) {
+ if (new_nep) {
+ mp->mnt_export = NULL;
+ free(nep, M_MOUNT);
+ }
goto out;
+ }
+ new_nep = false;
MNT_ILOCK(mp);
+ if (do_exjail && mp->mnt_exjail == NULL) {
+ mp->mnt_exjail = crhold(curthread->td_ucred);
+ atomic_add_int(&pr->pr_exportcnt, 1);
+ }
mp->mnt_flag |= MNT_EXPUBLIC;
MNT_IUNLOCK(mp);
}
@@ -348,9 +405,18 @@
argp->ex_numsecflavors = 1;
argp->ex_secflavors[0] = AUTH_SYS;
}
- if ((error = vfs_hang_addrlist(mp, nep, argp)))
+ if ((error = vfs_hang_addrlist(mp, nep, argp))) {
+ if (new_nep) {
+ mp->mnt_export = NULL;
+ free(nep, M_MOUNT);
+ }
goto out;
+ }
MNT_ILOCK(mp);
+ if (do_exjail && mp->mnt_exjail == NULL) {
+ mp->mnt_exjail = crhold(curthread->td_ucred);
+ atomic_add_int(&pr->pr_exportcnt, 1);
+ }
mp->mnt_flag |= MNT_EXPORTED;
MNT_IUNLOCK(mp);
}
@@ -368,6 +434,39 @@
vfs_deleteopt(mp->mnt_optnew, "export");
vfs_deleteopt(mp->mnt_opt, "export");
return (error);
+}
+
+/*
+ * Get rid of credential references for this prison.
+ */
+void
+vfs_exjail_delete(struct prison *pr)
+{
+ struct mount *mp;
+ struct ucred *cr;
+ int i;
+
+ i = atomic_load_int(&pr->pr_exportcnt);
+ KASSERT(i >= 0, ("vfs_exjail_delete: pr_exportcnt negative"));
+ if (i == 0)
+ return;
+ mtx_lock(&mountlist_mtx);
+ TAILQ_FOREACH(mp, &mountlist, mnt_list) {
+ cr = NULL;
+ MNT_ILOCK(mp);
+ if (mp->mnt_exjail != NULL &&
+ mp->mnt_exjail->cr_prison == pr) {
+ cr = mp->mnt_exjail;
+ mp->mnt_exjail = NULL;
+ }
+ MNT_IUNLOCK(mp);
+ if (cr != NULL) {
+ crfree(cr);
+ if (--i == 0)
+ break;
+ }
+ }
+ mtx_unlock(&mountlist_mtx);
}
/*
diff --git a/sys/kern/vfs_mount.c.ident b/sys/kern/vfs_mount.c
--- a/sys/kern/vfs_mount.c.ident
+++ b/sys/kern/vfs_mount.c
@@ -761,6 +761,8 @@
#endif
if (mp->mnt_opt != NULL)
vfs_freeopts(mp->mnt_opt);
+ if (mp->mnt_exjail != NULL)
+ crfree(mp->mnt_exjail);
crfree(mp->mnt_cred);
uma_zfree(mount_zone, mp);
}
@@ -1471,7 +1473,7 @@
} else
export_error = EINVAL;
if (export_error == 0)
- export_error = vfs_export(mp, &export);
+ export_error = vfs_export(mp, &export, true);
free(export.ex_groups, M_TEMP);
break;
case (sizeof(export)):
@@ -1493,7 +1495,7 @@
else
export_error = EINVAL;
if (export_error == 0)
- export_error = vfs_export(mp, &export);
+ export_error = vfs_export(mp, &export, true);
free(grps, M_TEMP);
break;
default:
diff --git a/sys/sys/jail.h.ident b/sys/sys/jail.h
--- a/sys/sys/jail.h.ident
+++ b/sys/sys/jail.h
@@ -175,6 +175,7 @@
int pr_id; /* (c) prison id */
volatile u_int pr_ref; /* (r) refcount */
volatile u_int pr_uref; /* (r) user (alive) refcount */
+ volatile int pr_exportcnt; /* (r) count of mount exports */
unsigned pr_flags; /* (p) PR_* flags */
LIST_HEAD(, prison) pr_children; /* (a) list of child jails */
LIST_HEAD(, proc) pr_proclist; /* (A) list of jailed processes */
diff --git a/sys/sys/mount.h.ident b/sys/sys/mount.h
--- a/sys/sys/mount.h.ident
+++ b/sys/sys/mount.h
@@ -216,6 +216,7 @@
* i - interlock
* v - vnode freelist mutex
* d - deferred unmount list mutex
+ * e - mnt_explock
*
* Unmarked fields are considered stable as long as a ref is held.
*
@@ -245,13 +246,14 @@
void * mnt_data; /* private data */
time_t mnt_time; /* last time written*/
int mnt_iosize_max; /* max size for clusters, etc */
- struct netexport *mnt_export; /* export list */
+ struct netexport *mnt_export; /* (e) export list */
struct label *mnt_label; /* MAC label for the fs */
u_int mnt_hashseed; /* Random seed for vfs_hash */
int mnt_lockref; /* (i) Lock reference count */
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 */
+ struct ucred *mnt_exjail; /* (i) jail which did exports */
#define mnt_endzero mnt_gjprovider
char *mnt_gjprovider; /* gjournal provider name */
struct mtx mnt_listmtx;
@@ -1016,8 +1018,10 @@
(struct mount *, struct netexport *, struct export_args *);
void vfs_periodic(struct mount *, int);
int vfs_busy(struct mount *, int);
+void vfs_exjail_delete(struct prison *);
int vfs_export /* process mount export info */
- (struct mount *, struct export_args *);
+ (struct mount *, struct export_args *, bool);
+void vfs_free_addrlist(struct netexport *);
void vfs_allocate_syncvnode(struct mount *);
void vfs_deallocate_syncvnode(struct mount *);
int vfs_donmount(struct thread *td, uint64_t fsflags,

File Metadata

Mime Type
text/plain
Expires
Fri, May 22, 12:27 PM (6 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33420526
Default Alt Text
D38371.id116446.diff (8 KB)

Event Timeline