64
64
#include <sys/dsl_dir.h>
65
65
#include <sys/spa_boot.h>
66
66
#include <sys/jail.h>
67
+ #include <sys/osd.h>
67
68
#include <ufs/ufs/quota.h>
68
69
#include <sys/zfs_quota.h>
69
70
@@ -90,6 +91,20 @@ int zfs_debug_level;
90
91
SYSCTL_INT (_vfs_zfs , OID_AUTO , debug , CTLFLAG_RWTUN , & zfs_debug_level , 0 ,
91
92
"Debug level" );
92
93
94
+ struct zfs_jailparam {
95
+ int mount_snapshot ;
96
+ };
97
+
98
+ static struct zfs_jailparam zfs_jailparam0 = {
99
+ .mount_snapshot = 0 ,
100
+ };
101
+
102
+ static int zfs_jailparam_slot ;
103
+
104
+ SYSCTL_JAIL_PARAM_SYS_NODE (zfs , CTLFLAG_RW , "Jail ZFS parameters" );
105
+ SYSCTL_JAIL_PARAM (_zfs , mount_snapshot , CTLTYPE_INT | CTLFLAG_RW , "I" ,
106
+ "Allow mounting snapshots in the .zfs directory for unjailed datasets" );
107
+
93
108
SYSCTL_NODE (_vfs_zfs , OID_AUTO , version , CTLFLAG_RD , 0 , "ZFS versions" );
94
109
static int zfs_version_acl = ZFS_ACL_VERSION ;
95
110
SYSCTL_INT (_vfs_zfs_version , OID_AUTO , acl , CTLFLAG_RD , & zfs_version_acl , 0 ,
@@ -1332,7 +1347,7 @@ zfs_mount(vfs_t *vfsp)
1332
1347
char * osname ;
1333
1348
int error = 0 ;
1334
1349
int canwrite ;
1335
- bool checkpointrewind ;
1350
+ bool checkpointrewind , isctlsnap = false ;
1336
1351
1337
1352
if (vfs_getopt (vfsp -> mnt_optnew , "from" , (void * * )& osname , NULL ))
1338
1353
return (SET_ERROR (EINVAL ));
@@ -1347,6 +1362,7 @@ zfs_mount(vfs_t *vfsp)
1347
1362
}
1348
1363
1349
1364
fetch_osname_options (osname , & checkpointrewind );
1365
+ isctlsnap = (zfsctl_is_node (mvp ) && strchr (osname , '@' ) != NULL );
1350
1366
1351
1367
/*
1352
1368
* Check for mount privilege?
@@ -1355,7 +1371,9 @@ zfs_mount(vfs_t *vfsp)
1355
1371
* we have local permission to allow it
1356
1372
*/
1357
1373
error = secpolicy_fs_mount (cr , mvp , vfsp );
1358
- if (error ) {
1374
+ if (error && isctlsnap ) {
1375
+ secpolicy_fs_mount_clearopts (cr , vfsp );
1376
+ } else if (error ) {
1359
1377
if (dsl_deleg_access (osname , ZFS_DELEG_PERM_MOUNT , cr ) != 0 )
1360
1378
goto out ;
1361
1379
@@ -1392,8 +1410,27 @@ zfs_mount(vfs_t *vfsp)
1392
1410
*/
1393
1411
if (!INGLOBALZONE (curproc ) &&
1394
1412
(!zone_dataset_visible (osname , & canwrite ) || !canwrite )) {
1395
- error = SET_ERROR (EPERM );
1396
- goto out ;
1413
+ boolean_t mount_snapshot = B_FALSE ;
1414
+
1415
+ /*
1416
+ * Snapshots may be mounted in .zfs for unjailed datasets
1417
+ * if allowed by the jail param zfs.mount_snapshot.
1418
+ */
1419
+ if (isctlsnap ) {
1420
+ struct prison * pr ;
1421
+ struct zfs_jailparam * zjp ;
1422
+
1423
+ pr = curthread -> td_ucred -> cr_prison ;
1424
+ mtx_lock (& pr -> pr_mtx );
1425
+ zjp = osd_jail_get (pr , zfs_jailparam_slot );
1426
+ mtx_unlock (& pr -> pr_mtx );
1427
+ if (zjp && zjp -> mount_snapshot )
1428
+ mount_snapshot = B_TRUE ;
1429
+ }
1430
+ if (!mount_snapshot ) {
1431
+ error = SET_ERROR (EPERM );
1432
+ goto out ;
1433
+ }
1397
1434
}
1398
1435
1399
1436
vfsp -> vfs_flag |= MNT_NFS4ACLS ;
@@ -2343,3 +2380,236 @@ zfsvfs_update_fromname(const char *oldname, const char *newname)
2343
2380
mtx_unlock (& mountlist_mtx );
2344
2381
}
2345
2382
#endif
2383
+
2384
+ /*
2385
+ * Find a prison with ZFS info.
2386
+ * Return the ZFS info and the (locked) prison.
2387
+ */
2388
+ static struct zfs_jailparam *
2389
+ zfs_jailparam_find (struct prison * spr , struct prison * * prp )
2390
+ {
2391
+ struct prison * pr ;
2392
+ struct zfs_jailparam * zjp ;
2393
+
2394
+ for (pr = spr ; ; pr = pr -> pr_parent ) {
2395
+ mtx_lock (& pr -> pr_mtx );
2396
+ if (pr == & prison0 ) {
2397
+ zjp = & zfs_jailparam0 ;
2398
+ break ;
2399
+ }
2400
+ zjp = osd_jail_get (pr , zfs_jailparam_slot );
2401
+ if (zjp != NULL )
2402
+ break ;
2403
+ mtx_unlock (& pr -> pr_mtx );
2404
+ }
2405
+ * prp = pr ;
2406
+
2407
+ return (zjp );
2408
+ }
2409
+
2410
+ /*
2411
+ * Ensure a prison has its own ZFS info. If zjpp is non-null, point it to the
2412
+ * ZFS info and lock the prison.
2413
+ */
2414
+ static void
2415
+ zfs_jailparam_alloc (struct prison * pr , struct zfs_jailparam * * zjpp )
2416
+ {
2417
+ struct prison * ppr ;
2418
+ struct zfs_jailparam * zjp , * nzjp ;
2419
+ void * * rsv ;
2420
+
2421
+ /* If this prison already has ZFS info, return that. */
2422
+ zjp = zfs_jailparam_find (pr , & ppr );
2423
+ if (ppr == pr )
2424
+ goto done ;
2425
+
2426
+ /*
2427
+ * Allocate a new info record. Then check again, in case something
2428
+ * changed during the allocation.
2429
+ */
2430
+ mtx_unlock (& ppr -> pr_mtx );
2431
+ nzjp = malloc (sizeof (struct zfs_jailparam ), M_PRISON , M_WAITOK );
2432
+ rsv = osd_reserve (zfs_jailparam_slot );
2433
+ zjp = zfs_jailparam_find (pr , & ppr );
2434
+ if (ppr == pr ) {
2435
+ free (nzjp , M_PRISON );
2436
+ osd_free_reserved (rsv );
2437
+ goto done ;
2438
+ }
2439
+ /* Inherit the initial values from the ancestor. */
2440
+ mtx_lock (& pr -> pr_mtx );
2441
+ (void ) osd_jail_set_reserved (pr , zfs_jailparam_slot , rsv , nzjp );
2442
+ (void ) memcpy (nzjp , zjp , sizeof (* zjp ));
2443
+ zjp = nzjp ;
2444
+ mtx_unlock (& ppr -> pr_mtx );
2445
+ done :
2446
+ if (zjpp != NULL )
2447
+ * zjpp = zjp ;
2448
+ else
2449
+ mtx_unlock (& pr -> pr_mtx );
2450
+ }
2451
+
2452
+ /*
2453
+ * Jail OSD methods for ZFS VFS info.
2454
+ */
2455
+ static int
2456
+ zfs_jailparam_create (void * obj , void * data )
2457
+ {
2458
+ struct prison * pr = obj ;
2459
+ struct vfsoptlist * opts = data ;
2460
+ int jsys ;
2461
+
2462
+ if (vfs_copyopt (opts , "zfs" , & jsys , sizeof (jsys )) == 0 &&
2463
+ jsys == JAIL_SYS_INHERIT )
2464
+ return (0 );
2465
+ /*
2466
+ * Inherit a prison's initial values from its parent
2467
+ * (different from JAIL_SYS_INHERIT which also inherits changes).
2468
+ */
2469
+ zfs_jailparam_alloc (pr , NULL );
2470
+ return (0 );
2471
+ }
2472
+
2473
+ static int
2474
+ zfs_jailparam_get (void * obj , void * data )
2475
+ {
2476
+ struct prison * ppr , * pr = obj ;
2477
+ struct vfsoptlist * opts = data ;
2478
+ struct zfs_jailparam * zjp ;
2479
+ int jsys , error ;
2480
+
2481
+ zjp = zfs_jailparam_find (pr , & ppr );
2482
+ jsys = (ppr == pr ) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT ;
2483
+ error = vfs_setopt (opts , "zfs" , & jsys , sizeof (jsys ));
2484
+ if (error != 0 && error != ENOENT )
2485
+ goto done ;
2486
+ if (jsys == JAIL_SYS_NEW ) {
2487
+ error = vfs_setopt (opts , "zfs.mount_snapshot" ,
2488
+ & zjp -> mount_snapshot , sizeof (zjp -> mount_snapshot ));
2489
+ if (error != 0 && error != ENOENT )
2490
+ goto done ;
2491
+ } else {
2492
+ /*
2493
+ * If this prison is inheriting its ZFS info, report
2494
+ * empty/zero parameters.
2495
+ */
2496
+ static int mount_snapshot = 0 ;
2497
+
2498
+ error = vfs_setopt (opts , "zfs.mount_snapshot" ,
2499
+ & mount_snapshot , sizeof (mount_snapshot ));
2500
+ if (error != 0 && error != ENOENT )
2501
+ goto done ;
2502
+ }
2503
+ error = 0 ;
2504
+ done :
2505
+ mtx_unlock (& ppr -> pr_mtx );
2506
+ return (error );
2507
+ }
2508
+
2509
+ static int
2510
+ zfs_jailparam_set (void * obj , void * data )
2511
+ {
2512
+ struct prison * pr = obj ;
2513
+ struct prison * ppr ;
2514
+ struct vfsoptlist * opts = data ;
2515
+ int error , jsys , mount_snapshot ;
2516
+
2517
+ /* Set the parameters, which should be correct. */
2518
+ error = vfs_copyopt (opts , "zfs" , & jsys , sizeof (jsys ));
2519
+ if (error == ENOENT )
2520
+ jsys = -1 ;
2521
+ error = vfs_copyopt (opts , "zfs.mount_snapshot" , & mount_snapshot ,
2522
+ sizeof (mount_snapshot ));
2523
+ if (error == ENOENT )
2524
+ mount_snapshot = -1 ;
2525
+ else
2526
+ jsys = JAIL_SYS_NEW ;
2527
+ if (jsys == JAIL_SYS_NEW ) {
2528
+ /* "zfs=new" or "zfs.*": the prison gets its own ZFS info. */
2529
+ struct zfs_jailparam * zjp ;
2530
+
2531
+ /*
2532
+ * A child jail cannot have more permissions than its parent
2533
+ */
2534
+ if (pr -> pr_parent != & prison0 ) {
2535
+ zjp = zfs_jailparam_find (pr -> pr_parent , & ppr );
2536
+ mtx_unlock (& ppr -> pr_mtx );
2537
+ if (zjp -> mount_snapshot < mount_snapshot ) {
2538
+ return (EPERM );
2539
+ }
2540
+ }
2541
+ zfs_jailparam_alloc (pr , & zjp );
2542
+ if (mount_snapshot != -1 )
2543
+ zjp -> mount_snapshot = mount_snapshot ;
2544
+ mtx_unlock (& pr -> pr_mtx );
2545
+ } else {
2546
+ /* "zfs=inherit": inherit the parent's ZFS info. */
2547
+ mtx_lock (& pr -> pr_mtx );
2548
+ osd_jail_del (pr , zfs_jailparam_slot );
2549
+ mtx_unlock (& pr -> pr_mtx );
2550
+ }
2551
+ return (0 );
2552
+ }
2553
+
2554
+ static int
2555
+ zfs_jailparam_check (void * obj __unused , void * data )
2556
+ {
2557
+ struct vfsoptlist * opts = data ;
2558
+ int error , jsys , mount_snapshot ;
2559
+
2560
+ /* Check that the parameters are correct. */
2561
+ error = vfs_copyopt (opts , "zfs" , & jsys , sizeof (jsys ));
2562
+ if (error != ENOENT ) {
2563
+ if (error != 0 )
2564
+ return (error );
2565
+ if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT )
2566
+ return (EINVAL );
2567
+ }
2568
+ error = vfs_copyopt (opts , "zfs.mount_snapshot" , & mount_snapshot ,
2569
+ sizeof (mount_snapshot ));
2570
+ if (error != ENOENT ) {
2571
+ if (error != 0 )
2572
+ return (error );
2573
+ if (mount_snapshot != 0 && mount_snapshot != 1 )
2574
+ return (EINVAL );
2575
+ }
2576
+ return (0 );
2577
+ }
2578
+
2579
+ static void
2580
+ zfs_jailparam_destroy (void * data )
2581
+ {
2582
+
2583
+ free (data , M_PRISON );
2584
+ }
2585
+
2586
+ static void
2587
+ zfs_jailparam_sysinit (void * arg __unused )
2588
+ {
2589
+ struct prison * pr ;
2590
+ osd_method_t methods [PR_MAXMETHOD ] = {
2591
+ [PR_METHOD_CREATE ] = zfs_jailparam_create ,
2592
+ [PR_METHOD_GET ] = zfs_jailparam_get ,
2593
+ [PR_METHOD_SET ] = zfs_jailparam_set ,
2594
+ [PR_METHOD_CHECK ] = zfs_jailparam_check ,
2595
+ };
2596
+
2597
+ zfs_jailparam_slot = osd_jail_register (zfs_jailparam_destroy , methods );
2598
+ /* Copy the defaults to any existing prisons. */
2599
+ sx_slock (& allprison_lock );
2600
+ TAILQ_FOREACH (pr , & allprison , pr_list )
2601
+ zfs_jailparam_alloc (pr , NULL );
2602
+ sx_sunlock (& allprison_lock );
2603
+ }
2604
+
2605
+ static void
2606
+ zfs_jailparam_sysuninit (void * arg __unused )
2607
+ {
2608
+
2609
+ osd_jail_deregister (zfs_jailparam_slot );
2610
+ }
2611
+
2612
+ SYSINIT (zfs_jailparam_sysinit , SI_SUB_DRIVERS , SI_ORDER_ANY ,
2613
+ zfs_jailparam_sysinit , NULL );
2614
+ SYSUNINIT (zfs_jailparam_sysuninit , SI_SUB_DRIVERS , SI_ORDER_ANY ,
2615
+ zfs_jailparam_sysuninit , NULL );
0 commit comments