diff options
| author | Christopher J. PeBenito <cpebenito@tresys.com> | 2007-05-23 09:12:09 -0400 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2007-07-11 22:52:20 -0400 |
| commit | e47c8fc582a2c9f3cba059e543c4a056cd6bf8c4 (patch) | |
| tree | 20f43ed6ecb1bea6160f660721dee748a57e0568 /security | |
| parent | 0dd4ae516e7b5be89caed2532f9d953d0b1dbf01 (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.h | 1 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 249 |
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 | ||
| 42 | int security_load_policy(void * data, size_t len); | 42 | int security_load_policy(void * data, size_t len); |
| 43 | 43 | ||
| 44 | #define SEL_VEC_MAX 32 | ||
| 44 | struct av_decision { | 45 | struct 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; | |||
| 67 | static int bool_num = 0; | 67 | static int bool_num = 0; |
| 68 | static int *bool_pending_values = NULL; | 68 | static int *bool_pending_values = NULL; |
| 69 | 69 | ||
| 70 | /* global data for classes */ | ||
| 71 | static struct dentry *class_dir = NULL; | ||
| 72 | static unsigned long last_class_ino; | ||
| 73 | |||
| 70 | extern void selnl_notify_setenforce(int val); | 74 | extern 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 */ |
| 239 | static int sel_make_bools(void); | 244 | static int sel_make_bools(void); |
| 245 | static int sel_make_classes(void); | ||
| 246 | |||
| 247 | /* declaration for sel_make_class_dirs */ | ||
| 248 | static int sel_make_dir(struct inode *dir, struct dentry *dentry, | ||
| 249 | unsigned long *ino); | ||
| 240 | 250 | ||
| 241 | static ssize_t sel_read_mls(struct file *filp, char __user *buf, | 251 | static 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 | |||
| 311 | out1: | ||
| 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 | ||
| 1314 | static inline unsigned int sel_div(unsigned long a, unsigned long b) | ||
| 1315 | { | ||
| 1316 | return a / b - (a % b < 0); | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | static inline unsigned long sel_class_to_ino(u16 class) | ||
| 1320 | { | ||
| 1321 | return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | static inline u16 sel_ino_to_class(unsigned long ino) | ||
| 1325 | { | ||
| 1326 | return sel_div(ino & SEL_INO_MASK, SEL_VEC_MAX + 1); | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | static 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 | |||
| 1334 | static inline u32 sel_ino_to_perm(unsigned long ino) | ||
| 1335 | { | ||
| 1336 | return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1); | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | static 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); | ||
| 1355 | out: | ||
| 1356 | return rc; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | static const struct file_operations sel_class_ops = { | ||
| 1360 | .read = sel_read_class, | ||
| 1361 | }; | ||
| 1362 | |||
| 1363 | static 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); | ||
| 1379 | out: | ||
| 1380 | return rc; | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | static const struct file_operations sel_perm_ops = { | ||
| 1384 | .read = sel_read_perm, | ||
| 1385 | }; | ||
| 1386 | |||
| 1387 | static 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 | |||
| 1418 | out1: | ||
| 1419 | for (i = 0; i < nperms; i++) | ||
| 1420 | kfree(perms[i]); | ||
| 1421 | kfree(perms); | ||
| 1422 | out: | ||
| 1423 | return rc; | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | static int sel_make_clas | ||
