Skip to content

Commit 69d2a21

Browse files
Ryan MoellerRyan Moeller
authored andcommitted
zfs.mount_snapshot jail param
Signed-off-by: Ryan Moeller <[email protected]>
1 parent b948c0e commit 69d2a21

File tree

1 file changed

+257
-11
lines changed

1 file changed

+257
-11
lines changed

module/os/freebsd/zfs/zfs_vfsops.c

Lines changed: 257 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include <sys/dsl_dir.h>
6565
#include <sys/spa_boot.h>
6666
#include <sys/jail.h>
67+
#include <sys/osd.h>
6768
#include <ufs/ufs/quota.h>
6869
#include <sys/zfs_quota.h>
6970

@@ -89,12 +90,19 @@ int zfs_debug_level;
8990
SYSCTL_INT(_vfs_zfs, OID_AUTO, debug, CTLFLAG_RWTUN, &zfs_debug_level, 0,
9091
"Debug level");
9192

92-
/* BEGIN CSTYLED */
93-
int zfs_jail_mount_snapshot;
94-
SYSCTL_INT(_vfs_zfs, OID_AUTO, jail_mount_snapshot, CTLFLAG_RW,
95-
&zfs_jail_mount_snapshot, 0,
96-
"Allow mounting snapshots in the .zfs directory within jails");
97-
/* END CSTYLED */
93+
struct zfs_jailparam {
94+
int mount_snapshot;
95+
};
96+
97+
static struct zfs_jailparam zfs_jailparam0 = {
98+
.mount_snapshot = 0,
99+
};
100+
101+
static int zfs_jailparam_slot;
102+
103+
SYSCTL_JAIL_PARAM_SYS_NODE(zfs, CTLFLAG_RW, "Jail ZFS parameters");
104+
SYSCTL_JAIL_PARAM(_zfs, mount_snapshot, CTLTYPE_INT | CTLFLAG_RW, "I",
105+
"Allow mounting snapshots in the .zfs directory for unjailed datasets");
98106

99107
SYSCTL_NODE(_vfs_zfs, OID_AUTO, version, CTLFLAG_RD, 0, "ZFS versions");
100108
static int zfs_version_acl = ZFS_ACL_VERSION;
@@ -1393,10 +1401,28 @@ zfs_mount(vfs_t *vfsp)
13931401
* dataset is not visible.
13941402
*/
13951403
if (!INGLOBALZONE(curproc) &&
1396-
!(isctlsnap && zfs_jail_mount_snapshot) &&
13971404
(!zone_dataset_visible(osname, &canwrite) || !canwrite)) {
1398-
error = SET_ERROR(EPERM);
1399-
goto out;
1405+
boolean_t mount_snapshot = B_FALSE;
1406+
1407+
/*
1408+
* Snapshots may be mounted in .zfs for unjailed datasets
1409+
* if allowed by the jail param zfs.mount_snapshot.
1410+
*/
1411+
if (isctlsnap) {
1412+
struct prison *pr;
1413+
struct zfs_jailparam *zjp;
1414+
1415+
pr = curthread->td_ucred->cr_prison;
1416+
mtx_lock(&pr->pr_mtx);
1417+
zjp = osd_jail_get(pr, zfs_jailparam_slot);
1418+
mtx_unlock(&pr->pr_mtx);
1419+
if (zjp && zjp->mount_snapshot)
1420+
mount_snapshot = B_TRUE;
1421+
}
1422+
if (!mount_snapshot) {
1423+
error = SET_ERROR(EPERM);
1424+
goto out;
1425+
}
14001426
}
14011427

14021428
vfsp->vfs_flag |= MNT_NFS4ACLS;
@@ -2315,7 +2341,6 @@ zfs_get_vfs_flag_unmounted(objset_t *os)
23152341
return (unmounted);
23162342
}
23172343

2318-
#ifdef _KERNEL
23192344
void
23202345
zfsvfs_update_fromname(const char *oldname, const char *newname)
23212346
{
@@ -2345,4 +2370,225 @@ zfsvfs_update_fromname(const char *oldname, const char *newname)
23452370
}
23462371
mtx_unlock(&mountlist_mtx);
23472372
}
2348-
#endif
2373+
2374+
/*
2375+
* Find a prison with ZFS info.
2376+
* Return the ZFS info and the (locked) prison.
2377+
*/
2378+
static struct zfs_jailparam *
2379+
zfs_jailparam_find(struct prison *spr, struct prison **prp)
2380+
{
2381+
struct prison *pr;
2382+
struct zfs_jailparam *zjp;
2383+
2384+
for (pr = spr; ; pr = pr->pr_parent) {
2385+
mtx_lock(&pr->pr_mtx);
2386+
if (pr == &prison0) {
2387+
zjp = &zfs_jailparam0;
2388+
break;
2389+
}
2390+
zjp = osd_jail_get(pr, zfs_jailparam_slot);
2391+
if (zjp != NULL)
2392+
break;
2393+
mtx_unlock(&pr->pr_mtx);
2394+
}
2395+
*prp = pr;
2396+
2397+
return (zjp);
2398+
}
2399+
2400+
/*
2401+
* Ensure a prison has its own ZFS info. If zjpp is non-null, point it to the
2402+
* ZFS info and lock the prison.
2403+
*/
2404+
static void
2405+
zfs_jailparam_alloc(struct prison *pr, struct zfs_jailparam **zjpp)
2406+
{
2407+
struct prison *ppr;
2408+
struct zfs_jailparam *zjp, *nzjp;
2409+
void **rsv;
2410+
2411+
/* If this prison already has ZFS info, return that. */
2412+
zjp = zfs_jailparam_find(pr, &ppr);
2413+
if (ppr == pr)
2414+
goto done;
2415+
2416+
/*
2417+
* Allocate a new info record. Then check again, in case something
2418+
* changed during the allocation.
2419+
*/
2420+
mtx_unlock(&ppr->pr_mtx);
2421+
nzjp = malloc(sizeof (struct zfs_jailparam), M_PRISON, M_WAITOK);
2422+
rsv = osd_reserve(zfs_jailparam_slot);
2423+
zjp = zfs_jailparam_find(pr, &ppr);
2424+
if (ppr == pr) {
2425+
free(nzjp, M_PRISON);
2426+
osd_free_reserved(rsv);
2427+
goto done;
2428+
}
2429+
/* Inherit the initial values from the ancestor. */
2430+
mtx_lock(&pr->pr_mtx);
2431+
(void) osd_jail_set_reserved(pr, zfs_jailparam_slot, rsv, nzjp);
2432+
(void) memcpy(nzjp, zjp, sizeof (*zjp));
2433+
zjp = nzjp;
2434+
mtx_unlock(&ppr->pr_mtx);
2435+
done:
2436+
if (zjpp != NULL)
2437+
*zjpp = zjp;
2438+
else
2439+
mtx_unlock(&pr->pr_mtx);
2440+
}
2441+
2442+
/*
2443+
* Jail OSD methods for ZFS VFS info.
2444+
*/
2445+
static int
2446+
zfs_jailparam_create(void *obj, void *data)
2447+
{
2448+
struct prison *pr = obj;
2449+
struct vfsoptlist *opts = data;
2450+
int jsys;
2451+
2452+
if (vfs_copyopt(opts, "zfs", &jsys, sizeof (jsys)) == 0 &&
2453+
jsys == JAIL_SYS_INHERIT)
2454+
return (0);
2455+
/*
2456+
* Inherit a prison's initial values from its parent
2457+
* (different from JAIL_SYS_INHERIT which also inherits changes).
2458+
*/
2459+
zfs_jailparam_alloc(pr, NULL);
2460+
return (0);
2461+
}
2462+
2463+
static int
2464+
zfs_jailparam_get(void *obj, void *data)
2465+
{
2466+
struct prison *ppr, *pr = obj;
2467+
struct vfsoptlist *opts = data;
2468+
struct zfs_jailparam *zjp;
2469+
int jsys, error;
2470+
2471+
zjp = zfs_jailparam_find(pr, &ppr);
2472+
jsys = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
2473+
error = vfs_setopt(opts, "zfs", &jsys, sizeof (jsys));
2474+
if (error != 0 && error != ENOENT)
2475+
goto done;
2476+
if (jsys == JAIL_SYS_NEW) {
2477+
error = vfs_setopt(opts, "zfs.mount_snapshot",
2478+
&zjp->mount_snapshot, sizeof (zjp->mount_snapshot));
2479+
if (error != 0 && error != ENOENT)
2480+
goto done;
2481+
} else {
2482+
/*
2483+
* If this prison is inheriting its ZFS info, report
2484+
* empty/zero parameters.
2485+
*/
2486+
static int mount_snapshot = 0;
2487+
2488+
error = vfs_setopt(opts, "zfs.mount_snapshot",
2489+
&mount_snapshot, sizeof (mount_snapshot));
2490+
if (error != 0 && error != ENOENT)
2491+
goto done;
2492+
}
2493+
error = 0;
2494+
done:
2495+
mtx_unlock(&ppr->pr_mtx);
2496+
return (error);
2497+
}
2498+
2499+
static int
2500+
zfs_jailparam_set(void *obj, void *data)
2501+
{
2502+
struct prison *pr = obj;
2503+
struct vfsoptlist *opts = data;
2504+
int error, jsys, mount_snapshot;
2505+
2506+
/* Set the parameters, which should be correct. */
2507+
error = vfs_copyopt(opts, "zfs", &jsys, sizeof (jsys));
2508+
if (error == ENOENT)
2509+
jsys = -1;
2510+
error = vfs_copyopt(opts, "zfs.mount_snapshot", &mount_snapshot,
2511+
sizeof (mount_snapshot));
2512+
if (error == ENOENT)
2513+
mount_snapshot = -1;
2514+
else
2515+
jsys = JAIL_SYS_NEW;
2516+
if (jsys == JAIL_SYS_NEW) {
2517+
/* "zfs=new" or "zfs.*": the prison gets its own ZFS info. */
2518+
struct zfs_jailparam *zjp;
2519+
2520+
zfs_jailparam_alloc(pr, &zjp);
2521+
if (mount_snapshot != -1)
2522+
zjp->mount_snapshot = mount_snapshot;
2523+
mtx_unlock(&pr->pr_mtx);
2524+
} else {
2525+
/* "zfs=inherit": inherit the parent's ZFS info. */
2526+
mtx_lock(&pr->pr_mtx);
2527+
osd_jail_del(pr, zfs_jailparam_slot);
2528+
mtx_unlock(&pr->pr_mtx);
2529+
}
2530+
return (0);
2531+
}
2532+
2533+
static int
2534+
zfs_jailparam_check(void *obj __unused, void *data)
2535+
{
2536+
struct vfsoptlist *opts = data;
2537+
int error, jsys, mount_snapshot;
2538+
2539+
/* Check that the parameters are correct. */
2540+
error = vfs_copyopt(opts, "zfs", &jsys, sizeof (jsys));
2541+
if (error != ENOENT) {
2542+
if (error != 0)
2543+
return (error);
2544+
if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT)
2545+
return (EINVAL);
2546+
}
2547+
error = vfs_copyopt(opts, "zfs.mount_snapshot", &mount_snapshot,
2548+
sizeof (mount_snapshot));
2549+
if (error != ENOENT) {
2550+
if (error != 0)
2551+
return (error);
2552+
if (mount_snapshot != 0 && mount_snapshot != 1)
2553+
return (EINVAL);
2554+
}
2555+
return (0);
2556+
}
2557+
2558+
static void
2559+
zfs_jailparam_destroy(void *data)
2560+
{
2561+
2562+
free(data, M_PRISON);
2563+
}
2564+
2565+
static void
2566+
zfs_jailparam_sysinit(void *arg __unused)
2567+
{
2568+
struct prison *pr;
2569+
osd_method_t methods[PR_MAXMETHOD] = {
2570+
[PR_METHOD_CREATE] = zfs_jailparam_create,
2571+
[PR_METHOD_GET] = zfs_jailparam_get,
2572+
[PR_METHOD_SET] = zfs_jailparam_set,
2573+
[PR_METHOD_CHECK] = zfs_jailparam_check,
2574+
};
2575+
2576+
zfs_jailparam_slot = osd_jail_register(zfs_jailparam_destroy, methods);
2577+
/* Copy the defaults to any existing prisons. */
2578+
sx_slock(&allprison_lock);
2579+
TAILQ_FOREACH(pr, &allprison, pr_list)
2580+
zfs_jailparam_alloc(pr, NULL);
2581+
sx_sunlock(&allprison_lock);
2582+
}
2583+
2584+
static void
2585+
zfs_jailparam_sysuninit(void *arg __unused)
2586+
{
2587+
2588+
osd_jail_deregister(zfs_jailparam_slot);
2589+
}
2590+
2591+
SYSINIT(zfs_jailparam_sysinit, SI_SUB_DRIVERS, SI_ORDER_ANY,
2592+
zfs_jailparam_sysinit, NULL);
2593+
SYSUNINIT(zfs_jailparam_sysuninit, SI_SUB_DRIVERS, SI_ORDER_ANY,
2594+
zfs_jailparam_sysuninit, NULL);

0 commit comments

Comments
 (0)