aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorChristopher J. PeBenito <cpebenito@tresys.com>2007-05-23 09:12:09 -0400
committerJames Morris <jmorris@namei.org>2007-07-11 22:52:20 -0400
commite47c8fc582a2c9f3cba059e543c4a056cd6bf8c4 (patch)
tree20f43ed6ecb1bea6160f660721dee748a57e0568 /security
parent0dd4ae516e7b5be89caed2532f9d953d0b1dbf01 (diff)
selinux: add selinuxfs structure for object class discovery
The structure is as follows (relative to selinuxfs root): /class/file/index /class/file/perms/read /class/file/perms/write ... Each class is allocated 33 inodes, 1 for the class index and 32 for permissions. Relative to SEL_CLASS_INO_OFFSET, the inode of the index file DIV 33 is the class number. The inode of the permission file % 33 is the index of the permission for that class. Signed-off-by: Christopher J. PeBenito <cpebenito@tresys.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/include/security.h1
-rw-r--r--security/selinux/selinuxfs.c249
2 files changed, 250 insertions, 0 deletions
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 731a173f5a5f..83bdd4d2a29e 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -41,6 +41,7 @@ extern int selinux_mls_enabled;
41 41
42int security_load_policy(void * data, size_t len); 42int security_load_policy(void * data, size_t len);
43 43
44#define SEL_VEC_MAX 32
44struct av_decision { 45struct av_decision {
45 u32 allowed; 46 u32 allowed;
46 u32 decided; 47 u32 decided;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index cf1acde778de..c9e92daedee2 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -67,6 +67,10 @@ static struct dentry *bool_dir = NULL;
67static int bool_num = 0; 67static int bool_num = 0;
68static int *bool_pending_values = NULL; 68static int *bool_pending_values = NULL;
69 69
70/* global data for classes */
71static struct dentry *class_dir = NULL;
72static unsigned long last_class_ino;
73
70extern void selnl_notify_setenforce(int val); 74extern void selnl_notify_setenforce(int val);
71 75
72/* Check whether a task is allowed to use a security operation. */ 76/* Check whether a task is allowed to use a security operation. */
@@ -106,6 +110,7 @@ static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
106 110
107#define SEL_INITCON_INO_OFFSET 0x01000000 111#define SEL_INITCON_INO_OFFSET 0x01000000
108#define SEL_BOOL_INO_OFFSET 0x02000000 112#define SEL_BOOL_INO_OFFSET 0x02000000
113#define SEL_CLASS_INO_OFFSET 0x04000000
109#define SEL_INO_MASK 0x00ffffff 114#define SEL_INO_MASK 0x00ffffff
110 115
111#define TMPBUFLEN 12 116#define TMPBUFLEN 12
@@ -237,6 +242,11 @@ static const struct file_operations sel_policyvers_ops = {
237 242
238/* declaration for sel_write_load */ 243/* declaration for sel_write_load */
239static int sel_make_bools(void); 244static int sel_make_bools(void);
245static int sel_make_classes(void);
246
247/* declaration for sel_make_class_dirs */
248static int sel_make_dir(struct inode *dir, struct dentry *dentry,
249 unsigned long *ino);
240 250
241static ssize_t sel_read_mls(struct file *filp, char __user *buf, 251static ssize_t sel_read_mls(struct file *filp, char __user *buf,
242 size_t count, loff_t *ppos) 252 size_t count, loff_t *ppos)
@@ -287,10 +297,18 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
287 goto out; 297 goto out;
288 298
289 ret = sel_make_bools(); 299 ret = sel_make_bools();
300 if (ret) {
301 length = ret;
302 goto out1;
303 }
304
305 ret = sel_make_classes();
290 if (ret) 306 if (ret)
291 length = ret; 307 length = ret;
292 else 308 else
293 length = count; 309 length = count;
310
311out1:
294 audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, 312 audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
295 "policy loaded auid=%u", 313 "policy loaded auid=%u",
296 audit_get_loginuid(current->audit_context)); 314 audit_get_loginuid(current->audit_context));
@@ -1293,6 +1311,225 @@ out:
1293 return ret; 1311 return ret;
1294} 1312}
1295 1313
1314static inline unsigned int sel_div(unsigned long a, unsigned long b)
1315{
1316 return a / b - (a % b < 0);
1317}
1318
1319static inline unsigned long sel_class_to_ino(u16 class)
1320{
1321 return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;
1322}
1323
1324static inline u16 sel_ino_to_class(unsigned long ino)
1325{
1326 return sel_div(ino & SEL_INO_MASK, SEL_VEC_MAX + 1);
1327}
1328
1329static inline unsigned long sel_perm_to_ino(u16 class, u32 perm)
1330{
1331 return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET;
1332}
1333
1334static inline u32 sel_ino_to_perm(unsigned long ino)
1335{
1336 return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1);
1337}
1338
1339static ssize_t sel_read_class(struct file * file, char __user *buf,
1340 size_t count, loff_t *ppos)
1341{
1342 ssize_t rc, len;
1343 char *page;
1344 unsigned long ino = file->f_path.dentry->d_inode->i_ino;
1345
1346 page = (char *)__get_free_page(GFP_KERNEL);
1347 if (!page) {
1348 rc = -ENOMEM;
1349 goto out;
1350 }
1351
1352 len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino));
1353 rc = simple_read_from_buffer(buf, count, ppos, page, len);
1354 free_page((unsigned long)page);
1355out:
1356 return rc;
1357}
1358
1359static const struct file_operations sel_class_ops = {
1360 .read = sel_read_class,
1361};
1362
1363static ssize_t sel_read_perm(struct file * file, char __user *buf,
1364 size_t count, loff_t *ppos)
1365{
1366 ssize_t rc, len;
1367 char *page;
1368 unsigned long ino = file->f_path.dentry->d_inode->i_ino;
1369
1370 page = (char *)__get_free_page(GFP_KERNEL);
1371 if (!page) {
1372 rc = -ENOMEM;
1373 goto out;
1374 }
1375
1376 len = snprintf(page, PAGE_SIZE,"%d", sel_ino_to_perm(ino));
1377 rc = simple_read_from_buffer(buf, count, ppos, page, len);
1378 free_page((unsigned long)page);
1379out:
1380 return rc;
1381}
1382
1383static const struct file_operations sel_perm_ops = {
1384 .read = sel_read_perm,
1385};
1386
1387static int sel_make_perm_files(char *objclass, int classvalue,
1388 struct dentry *dir)
1389{
1390 int i, rc = 0, nperms;
1391 char **perms;
1392
1393 rc = security_get_permissions(objclass, &perms, &nperms);
1394 if (rc)
1395 goto out;
1396
1397 for (i = 0; i < nperms; i++) {
1398 struct inode *inode;
1399 struct dentry *dentry;
1400
1401 dentry = d_alloc_name(dir, perms[i]);
1402 if (!dentry) {
1403 rc = -ENOMEM;
1404 goto out1;
1405 }
1406
1407 inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
1408 if (!inode) {
1409 rc = -ENOMEM;
1410 goto out1;
1411 }
1412 inode->i_fop = &sel_perm_ops;
1413 /* i+1 since perm values are 1-indexed */
1414 inode->i_ino = sel_perm_to_ino(classvalue, i+1);
1415 d_add(dentry, inode);
1416 }
1417
1418out1:
1419 for (i = 0; i < nperms; i++)
1420 kfree(perms[i]);
1421 kfree(perms);
1422out:
1423 return rc;
1424}
1425
1426static int sel_make_class_dir_entries(char *classname, int index,
1427 struct dentry *dir)
1428{
1429 struct dentry *dentry = NULL;
1430 struct inode *inode = NULL;
1431 int rc;
1432
1433 dentry = d_alloc_name(dir, "index");
1434 if (!dentry) {
1435 rc = -ENOMEM;
1436 goto out;
1437 }
1438
1439 inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
1440 if (!inode) {
1441 rc = -ENOMEM;
1442 goto out;
1443 }
1444
1445 inode->i_fop = &sel_class_ops;
1446 inode->i_ino = sel_class_to_ino(index);
1447 d_add(dentry, inode);
1448
1449 dentry = d_alloc_name(dir, "perms");
1450 if (!dentry) {
1451 rc = -ENOMEM;
1452 goto out;
1453 }
1454
1455 rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino);
1456 if (rc)
1457 goto out;
1458
1459 rc = sel_make_perm_files(classname, index, dentry);
1460
1461out:
1462 return rc;
1463}
1464
1465static void sel_remove_classes(void)
1466{
1467 struct list_head *class_node;
1468
1469 list_for_each(class_node, &class_dir->d_subdirs) {
1470 struct dentry *class_subdir = list_entry(class_node,
1471 struct dentry, d_u.d_child);
1472 struct list_head *class_subdir_node;
1473
1474 list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
1475 struct dentry *d = list_entry(class_subdir_node,
1476 struct dentry, d_u.d_child);
1477
1478 if (d->d_inode)
1479 if (d->d_inode->i_mode & S_IFDIR)
1480 sel_remove_entries(d);
1481 }
1482
1483 sel_remove_entries(class_subdir);
1484 }
1485
1486 sel_remove_entries(class_dir);
1487}
1488
1489static int sel_make_classes(void)
1490{
1491 int rc = 0, nclasses, i;
1492 char **classes;
1493
1494 /* delete any existing entries */
1495 sel_remove_classes();
1496
1497 rc = security_get_classes(&classes, &nclasses);
1498 if (rc < 0)
1499 goto out;
1500
1501 /* +2 since classes are 1-indexed */
1502 last_class_ino = sel_class_to_ino(nclasses+2);
1503
1504 for (i = 0; i < nclasses; i++) {
1505 struct dentry *class_name_dir;
1506
1507 class_name_dir = d_alloc_name(class_dir, classes[i]);
1508 if (!class_name_dir) {
1509 rc = -ENOMEM;
1510 goto out1;
1511 }
1512
1513 rc = sel_make_dir(class_dir->d_inode, class_name_dir,
1514 &last_class_ino);
1515 if (rc)
1516 goto out1;
1517
1518 /* i+1 since class values are 1-indexed */
1519 rc = sel_make_class_dir_entries(classes[i], i+1,
1520 class_name_dir);
1521 if (rc)
1522 goto out1;
1523 }
1524
1525out1:
1526 for (i = 0; i < nclasses; i++)
1527 kfree(classes[i]);
1528 kfree(classes);
1529out:
1530 return rc;
1531}
1532
1296static int sel_make_dir(struct inode *dir, struct dentry *dentry, 1533static int sel_make_dir(struct inode *dir, struct dentry *dentry,
1297 unsigned long *ino) 1534 unsigned long *ino)
1298{ 1535{
@@ -1407,6 +1644,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
1407 if (ret) 1644 if (ret)
1408 goto err; 1645 goto err;
1409 1646
1647 dentry = d_alloc_name(sb->s_root, "class");
1648 if (!dentry) {
1649 ret = -ENOMEM;
1650 goto err;
1651 }
1652
1653 ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
1654 if (ret)
1655 goto err;
1656
1657 class_dir = dentry;
1658
1410out: 1659out:
1411 return ret; 1660 return ret;
1412err: 1661err: