63
63
#include <sys/dmu_objset.h>
64
64
#include <sys/dsl_dir.h>
65
65
#include <sys/jail.h>
66
+ #include <sys/osd.h>
66
67
#include <ufs/ufs/quota.h>
67
68
#include <sys/zfs_quota.h>
68
69
@@ -88,6 +89,20 @@ int zfs_debug_level;
88
89
SYSCTL_INT (_vfs_zfs , OID_AUTO , debug , CTLFLAG_RWTUN , & zfs_debug_level , 0 ,
89
90
"Debug level" );
90
91
92
+ struct zfs_jailparam {
93
+ int mount_snapshot ;
94
+ };
95
+
96
+ static struct zfs_jailparam zfs_jailparam0 = {
97
+ .mount_snapshot = 0 ,
98
+ };
99
+
100
+ static int zfs_jailparam_slot ;
101
+
102
+ SYSCTL_JAIL_PARAM_SYS_NODE (zfs , CTLFLAG_RW , "Jail ZFS parameters" );
103
+ SYSCTL_JAIL_PARAM (_zfs , mount_snapshot , CTLTYPE_INT | CTLFLAG_RW , "I" ,
104
+ "Allow mounting snapshots in the .zfs directory for unjailed datasets" );
105
+
91
106
SYSCTL_NODE (_vfs_zfs , OID_AUTO , version , CTLFLAG_RD , 0 , "ZFS versions" );
92
107
static int zfs_version_acl = ZFS_ACL_VERSION ;
93
108
SYSCTL_INT (_vfs_zfs_version , OID_AUTO , acl , CTLFLAG_RD , & zfs_version_acl , 0 ,
@@ -1298,7 +1313,7 @@ zfs_mount(vfs_t *vfsp)
1298
1313
char * osname ;
1299
1314
int error = 0 ;
1300
1315
int canwrite ;
1301
- bool checkpointrewind ;
1316
+ bool checkpointrewind , isctlsnap = false ;
1302
1317
1303
1318
if (vfs_getopt (vfsp -> mnt_optnew , "from" , (void * * )& osname , NULL ))
1304
1319
return (SET_ERROR (EINVAL ));
@@ -1313,6 +1328,7 @@ zfs_mount(vfs_t *vfsp)
1313
1328
}
1314
1329
1315
1330
fetch_osname_options (osname , & checkpointrewind );
1331
+ isctlsnap = (zfsctl_is_node (mvp ) && strchr (osname , '@' ) != NULL );
1316
1332
1317
1333
/*
1318
1334
* Check for mount privilege?
@@ -1321,7 +1337,9 @@ zfs_mount(vfs_t *vfsp)
1321
1337
* we have local permission to allow it
1322
1338
*/
1323
1339
error = secpolicy_fs_mount (cr , mvp , vfsp );
1324
- if (error ) {
1340
+ if (error && isctlsnap ) {
1341
+ secpolicy_fs_mount_clearopts (cr , vfsp );
1342
+ } else if (error ) {
1325
1343
if (dsl_deleg_access (osname , ZFS_DELEG_PERM_MOUNT , cr ) != 0 )
1326
1344
goto out ;
1327
1345
@@ -1358,8 +1376,27 @@ zfs_mount(vfs_t *vfsp)
1358
1376
*/
1359
1377
if (!INGLOBALZONE (curproc ) &&
1360
1378
(!zone_dataset_visible (osname , & canwrite ) || !canwrite )) {
1361
- error = SET_ERROR (EPERM );
1362
- goto out ;
1379
+ boolean_t mount_snapshot = B_FALSE ;
1380
+
1381
+ /*
1382
+ * Snapshots may be mounted in .zfs for unjailed datasets
1383
+ * if allowed by the jail param zfs.mount_snapshot.
1384
+ */
1385
+ if (isctlsnap ) {
1386
+ struct prison * pr ;
1387
+ struct zfs_jailparam * zjp ;
1388
+
1389
+ pr = curthread -> td_ucred -> cr_prison ;
1390
+ mtx_lock (& pr -> pr_mtx );
1391
+ zjp = osd_jail_get (pr , zfs_jailparam_slot );
1392
+ mtx_unlock (& pr -> pr_mtx );
1393
+ if (zjp && zjp -> mount_snapshot )
1394
+ mount_snapshot = B_TRUE ;
1395
+ }
1396
+ if (!mount_snapshot ) {
1397
+ error = SET_ERROR (EPERM );
1398
+ goto out ;
1399
+ }
1363
1400
}
1364
1401
1365
1402
vfsp -> vfs_flag |= MNT_NFS4ACLS ;
@@ -2316,3 +2353,236 @@ zfsvfs_update_fromname(const char *oldname, const char *newname)
2316
2353
mtx_unlock (& mountlist_mtx );
2317
2354
}
2318
2355
#endif
2356
+
2357
+ /*
2358
+ * Find a prison with ZFS info.
2359
+ * Return the ZFS info and the (locked) prison.
2360
+ */
2361
+ static struct zfs_jailparam *
2362
+ zfs_jailparam_find (struct prison * spr , struct prison * * prp )
2363
+ {
2364
+ struct prison * pr ;
2365
+ struct zfs_jailparam * zjp ;
2366
+
2367
+ for (pr = spr ; ; pr = pr -> pr_parent ) {
2368
+ mtx_lock (& pr -> pr_mtx );
2369
+ if (pr == & prison0 ) {
2370
+ zjp = & zfs_jailparam0 ;
2371
+ break ;
2372
+ }
2373
+ zjp = osd_jail_get (pr , zfs_jailparam_slot );
2374
+ if (zjp != NULL )
2375
+ break ;
2376
+ mtx_unlock (& pr -> pr_mtx );
2377
+ }
2378
+ * prp = pr ;
2379
+
2380
+ return (zjp );
2381
+ }
2382
+
2383
+ /*
2384
+ * Ensure a prison has its own ZFS info. If zjpp is non-null, point it to the
2385
+ * ZFS info and lock the prison.
2386
+ */
2387
+ static void
2388
+ zfs_jailparam_alloc (struct prison * pr , struct zfs_jailparam * * zjpp )
2389
+ {
2390
+ struct prison * ppr ;
2391
+ struct zfs_jailparam * zjp , * nzjp ;
2392
+ void * * rsv ;
2393
+
2394
+ /* If this prison already has ZFS info, return that. */
2395
+ zjp = zfs_jailparam_find (pr , & ppr );
2396
+ if (ppr == pr )
2397
+ goto done ;
2398
+
2399
+ /*
2400
+ * Allocate a new info record. Then check again, in case something
2401
+ * changed during the allocation.
2402
+ */
2403
+ mtx_unlock (& ppr -> pr_mtx );
2404
+ nzjp = malloc (sizeof (struct zfs_jailparam ), M_PRISON , M_WAITOK );
2405
+ rsv = osd_reserve (zfs_jailparam_slot );
2406
+ zjp = zfs_jailparam_find (pr , & ppr );
2407
+ if (ppr == pr ) {
2408
+ free (nzjp , M_PRISON );
2409
+ osd_free_reserved (rsv );
2410
+ goto done ;
2411
+ }
2412
+ /* Inherit the initial values from the ancestor. */
2413
+ mtx_lock (& pr -> pr_mtx );
2414
+ (void ) osd_jail_set_reserved (pr , zfs_jailparam_slot , rsv , nzjp );
2415
+ (void ) memcpy (nzjp , zjp , sizeof (* zjp ));
2416
+ zjp = nzjp ;
2417
+ mtx_unlock (& ppr -> pr_mtx );
2418
+ done :
2419
+ if (zjpp != NULL )
2420
+ * zjpp = zjp ;
2421
+ else
2422
+ mtx_unlock (& pr -> pr_mtx );
2423
+ }
2424
+
2425
+ /*
2426
+ * Jail OSD methods for ZFS VFS info.
2427
+ */
2428
+ static int
2429
+ zfs_jailparam_create (void * obj , void * data )
2430
+ {
2431
+ struct prison * pr = obj ;
2432
+ struct vfsoptlist * opts = data ;
2433
+ int jsys ;
2434
+
2435
+ if (vfs_copyopt (opts , "zfs" , & jsys , sizeof (jsys )) == 0 &&
2436
+ jsys == JAIL_SYS_INHERIT )
2437
+ return (0 );
2438
+ /*
2439
+ * Inherit a prison's initial values from its parent
2440
+ * (different from JAIL_SYS_INHERIT which also inherits changes).
2441
+ */
2442
+ zfs_jailparam_alloc (pr , NULL );
2443
+ return (0 );
2444
+ }
2445
+
2446
+ static int
2447
+ zfs_jailparam_get (void * obj , void * data )
2448
+ {
2449
+ struct prison * ppr , * pr = obj ;
2450
+ struct vfsoptlist * opts = data ;
2451
+ struct zfs_jailparam * zjp ;
2452
+ int jsys , error ;
2453
+
2454
+ zjp = zfs_jailparam_find (pr , & ppr );
2455
+ jsys = (ppr == pr ) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT ;
2456
+ error = vfs_setopt (opts , "zfs" , & jsys , sizeof (jsys ));
2457
+ if (error != 0 && error != ENOENT )
2458
+ goto done ;
2459
+ if (jsys == JAIL_SYS_NEW ) {
2460
+ error = vfs_setopt (opts , "zfs.mount_snapshot" ,
2461
+ & zjp -> mount_snapshot , sizeof (zjp -> mount_snapshot ));
2462
+ if (error != 0 && error != ENOENT )
2463
+ goto done ;
2464
+ } else {
2465
+ /*
2466
+ * If this prison is inheriting its ZFS info, report
2467
+ * empty/zero parameters.
2468
+ */
2469
+ static int mount_snapshot = 0 ;
2470
+
2471
+ error = vfs_setopt (opts , "zfs.mount_snapshot" ,
2472
+ & mount_snapshot , sizeof (mount_snapshot ));
2473
+ if (error != 0 && error != ENOENT )
2474
+ goto done ;
2475
+ }
2476
+ error = 0 ;
2477
+ done :
2478
+ mtx_unlock (& ppr -> pr_mtx );
2479
+ return (error );
2480
+ }
2481
+
2482
+ static int
2483
+ zfs_jailparam_set (void * obj , void * data )
2484
+ {
2485
+ struct prison * pr = obj ;
2486
+ struct prison * ppr ;
2487
+ struct vfsoptlist * opts = data ;
2488
+ int error , jsys , mount_snapshot ;
2489
+
2490
+ /* Set the parameters, which should be correct. */
2491
+ error = vfs_copyopt (opts , "zfs" , & jsys , sizeof (jsys ));
2492
+ if (error == ENOENT )
2493
+ jsys = -1 ;
2494
+ error = vfs_copyopt (opts , "zfs.mount_snapshot" , & mount_snapshot ,
2495
+ sizeof (mount_snapshot ));
2496
+ if (error == ENOENT )
2497
+ mount_snapshot = -1 ;
2498
+ else
2499
+ jsys = JAIL_SYS_NEW ;
2500
+ if (jsys == JAIL_SYS_NEW ) {
2501
+ /* "zfs=new" or "zfs.*": the prison gets its own ZFS info. */
2502
+ struct zfs_jailparam * zjp ;
2503
+
2504
+ /*
2505
+ * A child jail cannot have more permissions than its parent
2506
+ */
2507
+ if (pr -> pr_parent != & prison0 ) {
2508
+ zjp = zfs_jailparam_find (pr -> pr_parent , & ppr );
2509
+ mtx_unlock (& ppr -> pr_mtx );
2510
+ if (zjp -> mount_snapshot < mount_snapshot ) {
2511
+ return (EPERM );
2512
+ }
2513
+ }
2514
+ zfs_jailparam_alloc (pr , & zjp );
2515
+ if (mount_snapshot != -1 )
2516
+ zjp -> mount_snapshot = mount_snapshot ;
2517
+ mtx_unlock (& pr -> pr_mtx );
2518
+ } else {
2519
+ /* "zfs=inherit": inherit the parent's ZFS info. */
2520
+ mtx_lock (& pr -> pr_mtx );
2521
+ osd_jail_del (pr , zfs_jailparam_slot );
2522
+ mtx_unlock (& pr -> pr_mtx );
2523
+ }
2524
+ return (0 );
2525
+ }
2526
+
2527
+ static int
2528
+ zfs_jailparam_check (void * obj __unused , void * data )
2529
+ {
2530
+ struct vfsoptlist * opts = data ;
2531
+ int error , jsys , mount_snapshot ;
2532
+
2533
+ /* Check that the parameters are correct. */
2534
+ error = vfs_copyopt (opts , "zfs" , & jsys , sizeof (jsys ));
2535
+ if (error != ENOENT ) {
2536
+ if (error != 0 )
2537
+ return (error );
2538
+ if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT )
2539
+ return (EINVAL );
2540
+ }
2541
+ error = vfs_copyopt (opts , "zfs.mount_snapshot" , & mount_snapshot ,
2542
+ sizeof (mount_snapshot ));
2543
+ if (error != ENOENT ) {
2544
+ if (error != 0 )
2545
+ return (error );
2546
+ if (mount_snapshot != 0 && mount_snapshot != 1 )
2547
+ return (EINVAL );
2548
+ }
2549
+ return (0 );
2550
+ }
2551
+
2552
+ static void
2553
+ zfs_jailparam_destroy (void * data )
2554
+ {
2555
+
2556
+ free (data , M_PRISON );
2557
+ }
2558
+
2559
+ static void
2560
+ zfs_jailparam_sysinit (void * arg __unused )
2561
+ {
2562
+ struct prison * pr ;
2563
+ osd_method_t methods [PR_MAXMETHOD ] = {
2564
+ [PR_METHOD_CREATE ] = zfs_jailparam_create ,
2565
+ [PR_METHOD_GET ] = zfs_jailparam_get ,
2566
+ [PR_METHOD_SET ] = zfs_jailparam_set ,
2567
+ [PR_METHOD_CHECK ] = zfs_jailparam_check ,
2568
+ };
2569
+
2570
+ zfs_jailparam_slot = osd_jail_register (zfs_jailparam_destroy , methods );
2571
+ /* Copy the defaults to any existing prisons. */
2572
+ sx_slock (& allprison_lock );
2573
+ TAILQ_FOREACH (pr , & allprison , pr_list )
2574
+ zfs_jailparam_alloc (pr , NULL );
2575
+ sx_sunlock (& allprison_lock );
2576
+ }
2577
+
2578
+ static void
2579
+ zfs_jailparam_sysuninit (void * arg __unused )
2580
+ {
2581
+
2582
+ osd_jail_deregister (zfs_jailparam_slot );
2583
+ }
2584
+
2585
+ SYSINIT (zfs_jailparam_sysinit , SI_SUB_DRIVERS , SI_ORDER_ANY ,
2586
+ zfs_jailparam_sysinit , NULL );
2587
+ SYSUNINIT (zfs_jailparam_sysuninit , SI_SUB_DRIVERS , SI_ORDER_ANY ,
2588
+ zfs_jailparam_sysuninit , NULL );
0 commit comments