aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2014-09-23 01:40:08 -0400
committerChris Mason <clm@fb.com>2014-10-06 09:23:32 -0400
commitf667aef6af626d0cdce0204bc7a2888e62076525 (patch)
tree0fa4338f15fe66544d1e7f8ef2c7c99169da75cd
parent0ec31a61f0d46e03e9e80c2ff57fa3ae2fdf92d3 (diff)
btrfs: Make btrfs handle security mount options internally to avoid losing security label.
[BUG] Originally when mount btrfs with "-o subvol=" mount option, btrfs will lose all security lable. And if the btrfs fs is mounted somewhere else, due to the lost of security lable, SELinux will refuse to mount since the same super block is being mounted using different security lable. [REPRODUCER] With SELinux enabled: #mkfs -t btrfs /dev/sda5 #mount -o context=system_u:object_r:nfs_t:s0 /dev/sda5 /mnt/btrfs #btrfs subvolume create /mnt/btrfs/subvol #mount -o subvol=subvol,context=system_u:object_r:nfs_t:s0 /dev/sda5 /mnt/test kernel message: SELinux: mount invalid. Same superblock, different security settings for (dev sda5, type btrfs) [REASON] This happens because btrfs will call vfs_kern_mount() and then mount_subtree() to handle subvolume name lookup. First mount will cut off all the security lables and when it comes to the second vfs_kern_mount(), it has no security label now. [FIX] This patch will makes btrfs behavior much more like nfs, which has the type flag FS_BINARY_MOUNTDATA, making btrfs handles the security label internally. So security label will be set in the real mount time and won't lose label when use with "subvol=" mount option. Reported-by: Eryu Guan <guaneryu@gmail.com> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r--fs/btrfs/ctree.h5
-rw-r--r--fs/btrfs/super.c97
2 files changed, 97 insertions, 5 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index f7555e2767de..b94c1c76cd59 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -34,6 +34,7 @@
34#include <linux/pagemap.h> 34#include <linux/pagemap.h>
35#include <linux/btrfs.h> 35#include <linux/btrfs.h>
36#include <linux/workqueue.h> 36#include <linux/workqueue.h>
37#include <linux/security.h>
37#include "extent_io.h" 38#include "extent_io.h"
38#include "extent_map.h" 39#include "extent_map.h"
39#include "async-thread.h" 40#include "async-thread.h"
@@ -1725,6 +1726,9 @@ struct btrfs_fs_info {
1725 1726
1726 spinlock_t unused_bgs_lock; 1727 spinlock_t unused_bgs_lock;
1727 struct list_head unused_bgs; 1728 struct list_head unused_bgs;
1729
1730 /* For btrfs to record security options */
1731 struct security_mnt_opts security_opts;
1728}; 1732};
1729 1733
1730struct btrfs_subvolume_writers { 1734struct btrfs_subvolume_writers {
@@ -3591,6 +3595,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
3591 kfree(fs_info->uuid_root); 3595 kfree(fs_info->uuid_root);
3592 kfree(fs_info->super_copy); 3596 kfree(fs_info->super_copy);
3593 kfree(fs_info->super_for_commit); 3597 kfree(fs_info->super_for_commit);
3598 security_free_mnt_opts(&fs_info->security_opts);
3594 kfree(fs_info); 3599 kfree(fs_info);
3595} 3600}
3596 3601
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 4685b9704f15..22502848c27f 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1215,6 +1215,54 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
1215 return root; 1215 return root;
1216} 1216}
1217 1217
1218static int parse_security_options(char *orig_opts,
1219 struct security_mnt_opts *sec_opts)
1220{
1221 char *secdata = NULL;
1222 int ret = 0;
1223
1224 secdata = alloc_secdata();
1225 if (!secdata)
1226 return -ENOMEM;
1227 ret = security_sb_copy_data(orig_opts, secdata);
1228 if (ret) {
1229 free_secdata(secdata);
1230 return ret;
1231 }
1232 ret = security_sb_parse_opts_str(secdata, sec_opts);
1233 free_secdata(secdata);
1234 return ret;
1235}
1236
1237static int setup_security_options(struct btrfs_fs_info *fs_info,
1238 struct super_block *sb,
1239 struct security_mnt_opts *sec_opts)
1240{
1241 int ret = 0;
1242
1243 /*
1244 * Call security_sb_set_mnt_opts() to check whether new sec_opts
1245 * is valid.
1246 */
1247 ret = security_sb_set_mnt_opts(sb, sec_opts, 0, NULL);
1248 if (ret)
1249 return ret;
1250
1251 if (!fs_info->security_opts.num_mnt_opts) {
1252 /* first time security setup, copy sec_opts to fs_info */
1253 memcpy(&fs_info->security_opts, sec_opts, sizeof(*sec_opts));
1254 } else {
1255 /*
1256 * Since SELinux(the only one supports security_mnt_opts) does
1257 * NOT support changing context during remount/mount same sb,
1258 * This must be the same or part of the same security options,
1259 * just free it.
1260 */
1261 security_free_mnt_opts(sec_opts);
1262 }
1263 return ret;
1264}
1265
1218/* 1266/*
1219 * Find a superblock for the given device / mount point. 1267 * Find a superblock for the given device / mount point.
1220 * 1268 *
@@ -1229,6 +1277,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
1229 struct dentry *root; 1277 struct dentry *root;
1230 struct btrfs_fs_devices *fs_devices = NULL; 1278 struct btrfs_fs_devices *fs_devices = NULL;
1231 struct btrfs_fs_info *fs_info = NULL; 1279 struct btrfs_fs_info *fs_info = NULL;
1280 struct security_mnt_opts new_sec_opts;
1232 fmode_t mode = FMODE_READ; 1281 fmode_t mode = FMODE_READ;
1233 char *subvol_name = NULL; 1282 char *subvol_name = NULL;
1234 u64 subvol_objectid = 0; 1283 u64 subvol_objectid = 0;
@@ -1251,9 +1300,16 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
1251 return root; 1300 return root;
1252 } 1301 }
1253 1302
1303 security_init_mnt_opts(&new_sec_opts);
1304 if (data) {
1305 error = parse_security_options(data, &new_sec_opts);
1306 if (error)
1307 return ERR_PTR(error);
1308 }
1309
1254 error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices); 1310 error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices);
1255 if (error) 1311 if (error)
1256 return ERR_PTR(error); 1312 goto error_sec_opts;
1257 1313
1258 /* 1314 /*
1259 * Setup a dummy root and fs_info for test/set super. This is because 1315 * Setup a dummy root and fs_info for test/set super. This is because
@@ -1262,13 +1318,16 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
1262 * then open_ctree will properly initialize everything later. 1318 * then open_ctree will properly initialize everything later.
1263 */ 1319 */
1264 fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS); 1320 fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS);
1265 if (!fs_info) 1321 if (!fs_info) {
1266 return ERR_PTR(-ENOMEM); 1322 error = -ENOMEM;
1323 goto error_sec_opts;
1324 }
1267 1325
1268 fs_info->fs_devices = fs_devices; 1326 fs_info->fs_devices = fs_devices;
1269 1327
1270 fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); 1328 fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
1271 fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); 1329 fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);
1330 security_init_mnt_opts(&fs_info->security_opts);
1272 if (!fs_info->super_copy || !fs_info->super_for_commit) { 1331 if (!fs_info->super_copy || !fs_info->super_for_commit) {
1273 error = -ENOMEM; 1332 error = -ENOMEM;
1274 goto error_fs_info; 1333 goto error_fs_info;
@@ -1306,8 +1365,19 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
1306 } 1365 }
1307 1366
1308 root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error); 1367 root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error);
1309 if (IS_ERR(root)) 1368 if (IS_ERR(root)) {
1369 deactivate_locked_super(s);
1370 error = PTR_ERR(root);
1371 goto error_sec_opts;
1372 }
1373
1374 fs_info = btrfs_sb(s);
1375 error = setup_security_options(fs_info, s, &new_sec_opts);
1376 if (error) {
1377 dput(root);
1310 deactivate_locked_super(s); 1378 deactivate_locked_super(s);
1379 goto error_sec_opts;
1380 }
1311 1381
1312 return root; 1382 return root;
1313 1383
@@ -1315,6 +1385,8 @@ error_close_devices:
1315 btrfs_close_devices(fs_devices); 1385 btrfs_close_devices(fs_devices);
1316error_fs_info: 1386error_fs_info:
1317 free_fs_info(fs_info); 1387 free_fs_info(fs_info);
1388error_sec_opts:
1389 security_free_mnt_opts(&new_sec_opts);
1318 return ERR_PTR(error); 1390 return ERR_PTR(error);
1319} 1391}
1320 1392
@@ -1396,6 +1468,21 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
1396 sync_filesystem(sb); 1468 sync_filesystem(sb);
1397 btrfs_remount_prepare(fs_info); 1469 btrfs_remount_prepare(fs_info);
1398 1470
1471 if (data) {
1472 struct security_mnt_opts new_sec_opts;
1473
1474 security_init_mnt_opts(&new_sec_opts);
1475 ret = parse_security_options(data, &new_sec_opts);
1476 if (ret)
1477 goto restore;
1478 ret = setup_security_options(fs_info, sb,
1479 &new_sec_opts);
1480 if (ret) {
1481 security_free_mnt_opts(&new_sec_opts);
1482 goto restore;
1483 }
1484 }
1485
1399 ret = btrfs_parse_options(root, data); 1486 ret = btrfs_parse_options(root, data);
1400 if (ret) { 1487 if (ret) {
1401 ret = -EINVAL; 1488 ret = -EINVAL;
@@ -1775,7 +1862,7 @@ static struct file_system_type btrfs_fs_type = {
1775 .name = "btrfs", 1862 .name = "btrfs",
1776 .mount = btrfs_mount, 1863 .mount = btrfs_mount,
1777 .kill_sb = btrfs_kill_super, 1864 .kill_sb = btrfs_kill_super,
1778 .fs_flags = FS_REQUIRES_DEV, 1865 .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,
1779}; 1866};
1780MODULE_ALIAS_FS("btrfs"); 1867MODULE_ALIAS_FS("btrfs");
1781 1868