diff options
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/avc.c | 2 | ||||
-rw-r--r-- | security/selinux/hooks.c | 92 | ||||
-rw-r--r-- | security/selinux/include/security.h | 9 | ||||
-rw-r--r-- | security/selinux/netnode.c | 1 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 28 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 244 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 12 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 72 |
8 files changed, 304 insertions, 156 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 3d2715fd35ea..fcb89cb0f223 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -526,7 +526,7 @@ int avc_audit(u32 ssid, u32 tsid, | |||
526 | * during retry. However this is logically just as if the operation | 526 | * during retry. However this is logically just as if the operation |
527 | * happened a little later. | 527 | * happened a little later. |
528 | */ | 528 | */ |
529 | if ((a->type == LSM_AUDIT_DATA_FS) && | 529 | if ((a->type == LSM_AUDIT_DATA_INODE) && |
530 | (flags & IPERM_FLAG_RCU)) | 530 | (flags & IPERM_FLAG_RCU)) |
531 | return -ECHILD; | 531 | return -ECHILD; |
532 | 532 | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8fb248843009..a0d38459d650 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -990,6 +990,7 @@ static void selinux_write_opts(struct seq_file *m, | |||
990 | continue; | 990 | continue; |
991 | default: | 991 | default: |
992 | BUG(); | 992 | BUG(); |
993 | return; | ||
993 | }; | 994 | }; |
994 | /* we need a comma before each option */ | 995 | /* we need a comma before each option */ |
995 | seq_putc(m, ','); | 996 | seq_putc(m, ','); |
@@ -1443,6 +1444,7 @@ static int task_has_capability(struct task_struct *tsk, | |||
1443 | printk(KERN_ERR | 1444 | printk(KERN_ERR |
1444 | "SELinux: out of range capability %d\n", cap); | 1445 | "SELinux: out of range capability %d\n", cap); |
1445 | BUG(); | 1446 | BUG(); |
1447 | return -EINVAL; | ||
1446 | } | 1448 | } |
1447 | 1449 | ||
1448 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); | 1450 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); |
@@ -1487,8 +1489,8 @@ static int inode_has_perm(const struct cred *cred, | |||
1487 | 1489 | ||
1488 | if (!adp) { | 1490 | if (!adp) { |
1489 | adp = &ad; | 1491 | adp = &ad; |
1490 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1492 | COMMON_AUDIT_DATA_INIT(&ad, INODE); |
1491 | ad.u.fs.inode = inode; | 1493 | ad.u.inode = inode; |
1492 | } | 1494 | } |
1493 | 1495 | ||
1494 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); | 1496 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); |
@@ -1498,16 +1500,29 @@ static int inode_has_perm(const struct cred *cred, | |||
1498 | the dentry to help the auditing code to more easily generate the | 1500 | the dentry to help the auditing code to more easily generate the |
1499 | pathname if needed. */ | 1501 | pathname if needed. */ |
1500 | static inline int dentry_has_perm(const struct cred *cred, | 1502 | static inline int dentry_has_perm(const struct cred *cred, |
1501 | struct vfsmount *mnt, | ||
1502 | struct dentry *dentry, | 1503 | struct dentry *dentry, |
1503 | u32 av) | 1504 | u32 av) |
1504 | { | 1505 | { |
1505 | struct inode *inode = dentry->d_inode; | 1506 | struct inode *inode = dentry->d_inode; |
1506 | struct common_audit_data ad; | 1507 | struct common_audit_data ad; |
1507 | 1508 | ||
1508 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1509 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1509 | ad.u.fs.path.mnt = mnt; | 1510 | ad.u.dentry = dentry; |
1510 | ad.u.fs.path.dentry = dentry; | 1511 | return inode_has_perm(cred, inode, av, &ad, 0); |
1512 | } | ||
1513 | |||
1514 | /* Same as inode_has_perm, but pass explicit audit data containing | ||
1515 | the path to help the auditing code to more easily generate the | ||
1516 | pathname if needed. */ | ||
1517 | static inline int path_has_perm(const struct cred *cred, | ||
1518 | struct path *path, | ||
1519 | u32 av) | ||
1520 | { | ||
1521 | struct inode *inode = path->dentry->d_inode; | ||
1522 | struct common_audit_data ad; | ||
1523 | |||
1524 | COMMON_AUDIT_DATA_INIT(&ad, PATH); | ||
1525 | ad.u.path = *path; | ||
1511 | return inode_has_perm(cred, inode, av, &ad, 0); | 1526 | return inode_has_perm(cred, inode, av, &ad, 0); |
1512 | } | 1527 | } |
1513 | 1528 | ||
@@ -1529,8 +1544,8 @@ static int file_has_perm(const struct cred *cred, | |||
1529 | u32 sid = cred_sid(cred); | 1544 | u32 sid = cred_sid(cred); |
1530 | int rc; | 1545 | int rc; |
1531 | 1546 | ||
1532 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1547 | COMMON_AUDIT_DATA_INIT(&ad, PATH); |
1533 | ad.u.fs.path = file->f_path; | 1548 | ad.u.path = file->f_path; |
1534 | 1549 | ||
1535 | if (sid != fsec->sid) { | 1550 | if (sid != fsec->sid) { |
1536 | rc = avc_has_perm(sid, fsec->sid, | 1551 | rc = avc_has_perm(sid, fsec->sid, |
@@ -1568,8 +1583,8 @@ static int may_create(struct inode *dir, | |||
1568 | sid = tsec->sid; | 1583 | sid = tsec->sid; |
1569 | newsid = tsec->create_sid; | 1584 | newsid = tsec->create_sid; |
1570 | 1585 | ||
1571 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1586 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1572 | ad.u.fs.path.dentry = dentry; | 1587 | ad.u.dentry = dentry; |
1573 | 1588 | ||
1574 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, | 1589 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, |
1575 | DIR__ADD_NAME | DIR__SEARCH, | 1590 | DIR__ADD_NAME | DIR__SEARCH, |
@@ -1621,8 +1636,8 @@ static int may_link(struct inode *dir, | |||
1621 | dsec = dir->i_security; | 1636 | dsec = dir->i_security; |
1622 | isec = dentry->d_inode->i_security; | 1637 | isec = dentry->d_inode->i_security; |
1623 | 1638 | ||
1624 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1639 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1625 | ad.u.fs.path.dentry = dentry; | 1640 | ad.u.dentry = dentry; |
1626 | 1641 | ||
1627 | av = DIR__SEARCH; | 1642 | av = DIR__SEARCH; |
1628 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); | 1643 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); |
@@ -1667,9 +1682,9 @@ static inline int may_rename(struct inode *old_dir, | |||
1667 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 1682 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
1668 | new_dsec = new_dir->i_security; | 1683 | new_dsec = new_dir->i_security; |
1669 | 1684 | ||
1670 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1685 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1671 | 1686 | ||
1672 | ad.u.fs.path.dentry = old_dentry; | 1687 | ad.u.dentry = old_dentry; |
1673 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, | 1688 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, |
1674 | DIR__REMOVE_NAME | DIR__SEARCH, &ad); | 1689 | DIR__REMOVE_NAME | DIR__SEARCH, &ad); |
1675 | if (rc) | 1690 | if (rc) |
@@ -1685,7 +1700,7 @@ static inline int may_rename(struct inode *old_dir, | |||
1685 | return rc; | 1700 | return rc; |
1686 | } | 1701 | } |
1687 | 1702 | ||
1688 | ad.u.fs.path.dentry = new_dentry; | 1703 | ad.u.dentry = new_dentry; |
1689 | av = DIR__ADD_NAME | DIR__SEARCH; | 1704 | av = DIR__ADD_NAME | DIR__SEARCH; |
1690 | if (new_dentry->d_inode) | 1705 | if (new_dentry->d_inode) |
1691 | av |= DIR__REMOVE_NAME; | 1706 | av |= DIR__REMOVE_NAME; |
@@ -1895,7 +1910,7 @@ static int selinux_quota_on(struct dentry *dentry) | |||
1895 | { | 1910 | { |
1896 | const struct cred *cred = current_cred(); | 1911 | const struct cred *cred = current_cred(); |
1897 | 1912 | ||
1898 | return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); | 1913 | return dentry_has_perm(cred, dentry, FILE__QUOTAON); |
1899 | } | 1914 | } |
1900 | 1915 | ||
1901 | static int selinux_syslog(int type) | 1916 | static int selinux_syslog(int type) |
@@ -1992,8 +2007,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
1992 | return rc; | 2007 | return rc; |
1993 | } | 2008 | } |
1994 | 2009 | ||
1995 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2010 | COMMON_AUDIT_DATA_INIT(&ad, PATH); |
1996 | ad.u.fs.path = bprm->file->f_path; | 2011 | ad.u.path = bprm->file->f_path; |
1997 | 2012 | ||
1998 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 2013 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) |
1999 | new_tsec->sid = old_tsec->sid; | 2014 | new_tsec->sid = old_tsec->sid; |
@@ -2121,7 +2136,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2121 | 2136 | ||
2122 | /* Revalidate access to inherited open files. */ | 2137 | /* Revalidate access to inherited open files. */ |
2123 | 2138 | ||
2124 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2139 | COMMON_AUDIT_DATA_INIT(&ad, INODE); |
2125 | 2140 | ||
2126 | spin_lock(&files->file_lock); | 2141 | spin_lock(&files->file_lock); |
2127 | for (;;) { | 2142 | for (;;) { |
@@ -2469,8 +2484,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
2469 | if (flags & MS_KERNMOUNT) | 2484 | if (flags & MS_KERNMOUNT) |
2470 | return 0; | 2485 | return 0; |
2471 | 2486 | ||
2472 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2487 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2473 | ad.u.fs.path.dentry = sb->s_root; | 2488 | ad.u.dentry = sb->s_root; |
2474 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); | 2489 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); |
2475 | } | 2490 | } |
2476 | 2491 | ||
@@ -2479,8 +2494,8 @@ static int selinux_sb_statfs(struct dentry *dentry) | |||
2479 | const struct cred *cred = current_cred(); | 2494 | const struct cred *cred = current_cred(); |
2480 | struct common_audit_data ad; | 2495 | struct common_audit_data ad; |
2481 | 2496 | ||
2482 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2497 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2483 | ad.u.fs.path.dentry = dentry->d_sb->s_root; | 2498 | ad.u.dentry = dentry->d_sb->s_root; |
2484 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); | 2499 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
2485 | } | 2500 | } |
2486 | 2501 | ||
@@ -2496,8 +2511,7 @@ static int selinux_mount(char *dev_name, | |||
2496 | return superblock_has_perm(cred, path->mnt->mnt_sb, | 2511 | return superblock_has_perm(cred, path->mnt->mnt_sb, |
2497 | FILESYSTEM__REMOUNT, NULL); | 2512 | FILESYSTEM__REMOUNT, NULL); |
2498 | else | 2513 | else |
2499 | return dentry_has_perm(cred, path->mnt, path->dentry, | 2514 | return path_has_perm(cred, path, FILE__MOUNTON); |
2500 | FILE__MOUNTON); | ||
2501 | } | 2515 | } |
2502 | 2516 | ||
2503 | static int selinux_umount(struct vfsmount *mnt, int flags) | 2517 | static int selinux_umount(struct vfsmount *mnt, int flags) |
@@ -2630,14 +2644,14 @@ static int selinux_inode_readlink(struct dentry *dentry) | |||
2630 | { | 2644 | { |
2631 | const struct cred *cred = current_cred(); | 2645 | const struct cred *cred = current_cred(); |
2632 | 2646 | ||
2633 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); | 2647 | return dentry_has_perm(cred, dentry, FILE__READ); |
2634 | } | 2648 | } |
2635 | 2649 | ||
2636 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) | 2650 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) |
2637 | { | 2651 | { |
2638 | const struct cred *cred = current_cred(); | 2652 | const struct cred *cred = current_cred(); |
2639 | 2653 | ||
2640 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); | 2654 | return dentry_has_perm(cred, dentry, FILE__READ); |
2641 | } | 2655 | } |
2642 | 2656 | ||
2643 | static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) | 2657 | static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) |
@@ -2654,8 +2668,8 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag | |||
2654 | if (!mask) | 2668 | if (!mask) |
2655 | return 0; | 2669 | return 0; |
2656 | 2670 | ||
2657 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2671 | COMMON_AUDIT_DATA_INIT(&ad, INODE); |
2658 | ad.u.fs.inode = inode; | 2672 | ad.u.inode = inode; |
2659 | 2673 | ||
2660 | if (from_access) | 2674 | if (from_access) |
2661 | ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; | 2675 | ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; |
@@ -2680,16 +2694,20 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
2680 | 2694 | ||
2681 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | | 2695 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | |
2682 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) | 2696 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) |
2683 | return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); | 2697 | return dentry_has_perm(cred, dentry, FILE__SETATTR); |
2684 | 2698 | ||
2685 | return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); | 2699 | return dentry_has_perm(cred, dentry, FILE__WRITE); |
2686 | } | 2700 | } |
2687 | 2701 | ||
2688 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 2702 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
2689 | { | 2703 | { |
2690 | const struct cred *cred = current_cred(); | 2704 | const struct cred *cred = current_cred(); |
2705 | struct path path; | ||
2706 | |||
2707 | path.dentry = dentry; | ||
2708 | path.mnt = mnt; | ||
2691 | 2709 | ||
2692 | return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR); | 2710 | return path_has_perm(cred, &path, FILE__GETATTR); |
2693 | } | 2711 | } |
2694 | 2712 | ||
2695 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | 2713 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) |
@@ -2710,7 +2728,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | |||
2710 | 2728 | ||
2711 | /* Not an attribute we recognize, so just check the | 2729 | /* Not an attribute we recognize, so just check the |
2712 | ordinary setattr permission. */ | 2730 | ordinary setattr permission. */ |
2713 | return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); | 2731 | return dentry_has_perm(cred, dentry, FILE__SETATTR); |
2714 | } | 2732 | } |
2715 | 2733 | ||
2716 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | 2734 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, |
@@ -2733,8 +2751,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2733 | if (!inode_owner_or_capable(inode)) | 2751 | if (!inode_owner_or_capable(inode)) |
2734 | return -EPERM; | 2752 | return -EPERM; |
2735 | 2753 | ||
2736 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2754 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2737 | ad.u.fs.path.dentry = dentry; | 2755 | ad.u.dentry = dentry; |
2738 | 2756 | ||
2739 | rc = avc_has_perm(sid, isec->sid, isec->sclass, | 2757 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
2740 | FILE__RELABELFROM, &ad); | 2758 | FILE__RELABELFROM, &ad); |
@@ -2797,14 +2815,14 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name) | |||
2797 | { | 2815 | { |
2798 | const struct cred *cred = current_cred(); | 2816 | const struct cred *cred = current_cred(); |
2799 | 2817 | ||
2800 | return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR); | 2818 | return dentry_has_perm(cred, dentry, FILE__GETATTR); |
2801 | } | 2819 | } |
2802 | 2820 | ||
2803 | static int selinux_inode_listxattr(struct dentry *dentry) | 2821 | static int selinux_inode_listxattr(struct dentry *dentry) |
2804 | { | 2822 | { |
2805 | const struct cred *cred = current_cred(); | 2823 | const struct cred *cred = current_cred(); |
2806 | 2824 | ||
2807 | return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR); | 2825 | return dentry_has_perm(cred, dentry, FILE__GETATTR); |
2808 | } | 2826 | } |
2809 | 2827 | ||
2810 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) | 2828 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 348eb00cb668..3ba4feba048a 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -30,13 +30,14 @@ | |||
30 | #define POLICYDB_VERSION_PERMISSIVE 23 | 30 | #define POLICYDB_VERSION_PERMISSIVE 23 |
31 | #define POLICYDB_VERSION_BOUNDARY 24 | 31 | #define POLICYDB_VERSION_BOUNDARY 24 |
32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 | 32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 |
33 | #define POLICYDB_VERSION_ROLETRANS 26 | ||
33 | 34 | ||
34 | /* Range of policy versions we understand*/ | 35 | /* Range of policy versions we understand*/ |
35 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 36 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
36 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 37 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
37 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 38 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
38 | #else | 39 | #else |
39 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_FILENAME_TRANS | 40 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS |
40 | #endif | 41 | #endif |
41 | 42 | ||
42 | /* Mask for just the mount related flags */ | 43 | /* Mask for just the mount related flags */ |
@@ -85,7 +86,7 @@ extern int selinux_policycap_openperm; | |||
85 | int security_mls_enabled(void); | 86 | int security_mls_enabled(void); |
86 | 87 | ||
87 | int security_load_policy(void *data, size_t len); | 88 | int security_load_policy(void *data, size_t len); |
88 | int security_read_policy(void **data, ssize_t *len); | 89 | int security_read_policy(void **data, size_t *len); |
89 | size_t security_policydb_len(void); | 90 | size_t security_policydb_len(void); |
90 | 91 | ||
91 | int security_policycap_supported(unsigned int req_cap); | 92 | int security_policycap_supported(unsigned int req_cap); |
@@ -111,8 +112,8 @@ void security_compute_av_user(u32 ssid, u32 tsid, | |||
111 | int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, | 112 | int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, |
112 | const struct qstr *qstr, u32 *out_sid); | 113 | const struct qstr *qstr, u32 *out_sid); |
113 | 114 | ||
114 | int security_transition_sid_user(u32 ssid, u32 tsid, | 115 | int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, |
115 | u16 tclass, u32 *out_sid); | 116 | const char *objname, u32 *out_sid); |
116 | 117 | ||
117 | int security_member_sid(u32 ssid, u32 tsid, | 118 | int security_member_sid(u32 ssid, u32 tsid, |
118 | u16 tclass, u32 *out_sid); | 119 | u16 tclass, u32 *out_sid); |
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 65ebfe954f85..3618251d0fdb 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
@@ -141,6 +141,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family) | |||
141 | break; | 141 | break; |
142 | default: | 142 | default: |
143 | BUG(); | 143 | BUG(); |
144 | return NULL; | ||
144 | } | 145 | } |
145 | 146 | ||
146 | list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list) | 147 | list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list) |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 2d3373b2e256..77d44138864f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/percpu.h> | 28 | #include <linux/percpu.h> |
29 | #include <linux/audit.h> | 29 | #include <linux/audit.h> |
30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <linux/kobject.h> | ||
31 | 32 | ||
32 | /* selinuxfs pseudo filesystem for exporting the security policy API. | 33 | /* selinuxfs pseudo filesystem for exporting the security policy API. |
33 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ | 34 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ |
@@ -753,11 +754,13 @@ out: | |||
753 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | 754 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) |
754 | { | 755 | { |
755 | char *scon = NULL, *tcon = NULL; | 756 | char *scon = NULL, *tcon = NULL; |
757 | char *namebuf = NULL, *objname = NULL; | ||
756 | u32 ssid, tsid, newsid; | 758 | u32 ssid, tsid, newsid; |
757 | u16 tclass; | 759 | u16 tclass; |
758 | ssize_t length; | 760 | ssize_t length; |
759 | char *newcon = NULL; | 761 | char *newcon = NULL; |
760 | u32 len; | 762 | u32 len; |
763 | int nargs; | ||
761 | 764 | ||
762 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); | 765 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); |
763 | if (length) | 766 | if (length) |
@@ -773,9 +776,17 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | |||
773 | if (!tcon) | 776 | if (!tcon) |
774 | goto out; | 777 | goto out; |
775 | 778 | ||
779 | length = -ENOMEM; | ||
780 | namebuf = kzalloc(size + 1, GFP_KERNEL); | ||
781 | if (!namebuf) | ||
782 | goto out; | ||
783 | |||
776 | length = -EINVAL; | 784 | length = -EINVAL; |
777 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 785 | nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf); |
786 | if (nargs < 3 || nargs > 4) | ||
778 | goto out; | 787 | goto out; |
788 | if (nargs == 4) | ||
789 | objname = namebuf; | ||
779 | 790 | ||
780 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 791 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
781 | if (length) | 792 | if (length) |
@@ -785,7 +796,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | |||
785 | if (length) | 796 | if (length) |
786 | goto out; | 797 | goto out; |
787 | 798 | ||
788 | length = security_transition_sid_user(ssid, tsid, tclass, &newsid); | 799 | length = security_transition_sid_user(ssid, tsid, tclass, |
800 | objname, &newsid); | ||
789 | if (length) | 801 | if (length) |
790 | goto out; | 802 | goto out; |
791 | 803 | ||
@@ -804,6 +816,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | |||
804 | length = len; | 816 | length = len; |
805 | out: | 817 | out: |
806 | kfree(newcon); | 818 | kfree(newcon); |
819 | kfree(namebuf); | ||
807 | kfree(tcon); | 820 | kfree(tcon); |
808 | kfree(scon); | 821 | kfree(scon); |
809 | return length; | 822 | return length; |
@@ -1901,6 +1914,7 @@ static struct file_system_type sel_fs_type = { | |||
1901 | }; | 1914 | }; |
1902 | 1915 | ||
1903 | struct vfsmount *selinuxfs_mount; | 1916 | struct vfsmount *selinuxfs_mount; |
1917 | static struct kobject *selinuxfs_kobj; | ||
1904 | 1918 | ||
1905 | static int __init init_sel_fs(void) | 1919 | static int __init init_sel_fs(void) |
1906 | { | 1920 | { |
@@ -1908,9 +1922,16 @@ static int __init init_sel_fs(void) | |||
1908 | 1922 | ||
1909 | if (!selinux_enabled) | 1923 | if (!selinux_enabled) |
1910 | return 0; | 1924 | return 0; |
1925 | |||
1926 | selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj); | ||
1927 | if (!selinuxfs_kobj) | ||
1928 | return -ENOMEM; | ||
1929 | |||
1911 | err = register_filesystem(&sel_fs_type); | 1930 | err = register_filesystem(&sel_fs_type); |
1912 | if (err) | 1931 | if (err) { |
1932 | kobject_put(selinuxfs_kobj); | ||
1913 | return err; | 1933 | return err; |
1934 | } | ||
1914 | 1935 | ||
1915 | selinuxfs_mount = kern_mount(&sel_fs_type); | 1936 | selinuxfs_mount = kern_mount(&sel_fs_type); |
1916 | if (IS_ERR(selinuxfs_mount)) { | 1937 | if (IS_ERR(selinuxfs_mount)) { |
@@ -1927,6 +1948,7 @@ __initcall(init_sel_fs); | |||
1927 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 1948 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
1928 | void exit_sel_fs(void) | 1949 | void exit_sel_fs(void) |
1929 | { | 1950 | { |
1951 | kobject_put(selinuxfs_kobj); | ||
1930 | unregister_filesystem(&sel_fs_type); | 1952 | unregister_filesystem(&sel_fs_type); |
1931 | } | 1953 | } |
1932 | #endif | 1954 | #endif |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 7102457661d6..102e9ec1b77a 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -128,6 +128,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
128 | .sym_num = SYM_NUM, | 128 | .sym_num = SYM_NUM, |
129 | .ocon_num = OCON_NUM, | 129 | .ocon_num = OCON_NUM, |
130 | }, | 130 | }, |
131 | { | ||
132 | .version = POLICYDB_VERSION_ROLETRANS, | ||
133 | .sym_num = SYM_NUM, | ||
134 | .ocon_num = OCON_NUM, | ||
135 | }, | ||
131 | }; | 136 | }; |
132 | 137 | ||
133 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 138 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
@@ -179,6 +184,43 @@ out: | |||
179 | return rc; | 184 | return rc; |
180 | } | 185 | } |
181 | 186 | ||
187 | static u32 filenametr_hash(struct hashtab *h, const void *k) | ||
188 | { | ||
189 | const struct filename_trans *ft = k; | ||
190 | unsigned long hash; | ||
191 | unsigned int byte_num; | ||
192 | unsigned char focus; | ||
193 | |||
194 | hash = ft->stype ^ ft->ttype ^ ft->tclass; | ||
195 | |||
196 | byte_num = 0; | ||
197 | while ((focus = ft->name[byte_num++])) | ||
198 | hash = partial_name_hash(focus, hash); | ||
199 | return hash & (h->size - 1); | ||
200 | } | ||
201 | |||
202 | static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2) | ||
203 | { | ||
204 | const struct filename_trans *ft1 = k1; | ||
205 | const struct filename_trans *ft2 = k2; | ||
206 | int v; | ||
207 | |||
208 | v = ft1->stype - ft2->stype; | ||
209 | if (v) | ||
210 | return v; | ||
211 | |||
212 | v = ft1->ttype - ft2->ttype; | ||
213 | if (v) | ||
214 | return v; | ||
215 | |||
216 | v = ft1->tclass - ft2->tclass; | ||
217 | if (v) | ||
218 | return v; | ||
219 | |||
220 | return strcmp(ft1->name, ft2->name); | ||
221 | |||
222 | } | ||
223 | |||
182 | static u32 rangetr_hash(struct hashtab *h, const void *k) | 224 | static u32 rangetr_hash(struct hashtab *h, const void *k) |
183 | { | 225 | { |
184 | const struct range_trans *key = k; | 226 | const struct range_trans *key = k; |
@@ -231,15 +273,22 @@ static int policydb_init(struct policydb *p) | |||
231 | if (rc) | 273 | if (rc) |
232 | goto out; | 274 | goto out; |
233 | 275 | ||
276 | p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); | ||
277 | if (!p->filename_trans) | ||
278 | goto out; | ||
279 | |||
234 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); | 280 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); |
235 | if (!p->range_tr) | 281 | if (!p->range_tr) |
236 | goto out; | 282 | goto out; |
237 | 283 | ||
284 | ebitmap_init(&p->filename_trans_ttypes); | ||
238 | ebitmap_init(&p->policycaps); | 285 | ebitmap_init(&p->policycaps); |
239 | ebitmap_init(&p->permissive_map); | 286 | ebitmap_init(&p->permissive_map); |
240 | 287 | ||
241 | return 0; | 288 | return 0; |
242 | out: | 289 | out: |
290 | hashtab_destroy(p->filename_trans); | ||
291 | hashtab_destroy(p->range_tr); | ||
243 | for (i = 0; i < SYM_NUM; i++) | 292 | for (i = 0; i < SYM_NUM; i++) |
244 | hashtab_destroy(p->symtab[i].table); | 293 | hashtab_destroy(p->symtab[i].table); |
245 | return rc; | 294 | return rc; |
@@ -417,32 +466,26 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
417 | }; | 466 | }; |
418 | 467 | ||
419 | #ifdef DEBUG_HASHES | 468 | #ifdef DEBUG_HASHES |
420 | static void symtab_hash_eval(struct symtab *s) | 469 | static void hash_eval(struct hashtab *h, const char *hash_name) |
421 | { | 470 | { |
422 | int i; | 471 | struct hashtab_info info; |
423 | |||
424 | for (i = 0; i < SYM_NUM; i++) { | ||
425 | struct hashtab *h = s[i].table; | ||
426 | struct hashtab_info info; | ||
427 | 472 | ||
428 | hashtab_stat(h, &info); | 473 | hashtab_stat(h, &info); |
429 | printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " | 474 | printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " |
430 | "longest chain length %d\n", symtab_name[i], h->nel, | 475 | "longest chain length %d\n", hash_name, h->nel, |
431 | info.slots_used, h->size, info.max_chain_len); | 476 | info.slots_used, h->size, info.max_chain_len); |
432 | } | ||
433 | } | 477 | } |
434 | 478 | ||
435 | static void rangetr_hash_eval(struct hashtab *h) | 479 | static void symtab_hash_eval(struct symtab *s) |
436 | { | 480 | { |
437 | struct hashtab_info info; | 481 | int i; |
438 | 482 | ||
439 | hashtab_stat(h, &info); | 483 | for (i = 0; i < SYM_NUM; i++) |
440 | printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " | 484 | hash_eval(s[i].table, symtab_name[i]); |
441 | "longest chain length %d\n", h->nel, | ||
442 | info.slots_used, h->size, info.max_chain_len); | ||
443 | } | 485 | } |
486 | |||
444 | #else | 487 | #else |
445 | static inline void rangetr_hash_eval(struct hashtab *h) | 488 | static inline void hash_eval(struct hashtab *h, char *hash_name) |
446 | { | 489 | { |
447 | } | 490 | } |
448 | #endif | 491 | #endif |
@@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
675 | cat_destroy, | 718 | cat_destroy, |
676 | }; | 719 | }; |
677 | 720 | ||
721 | static int filenametr_destroy(void *key, void *datum, void *p) | ||
722 | { | ||
723 | struct filename_trans *ft = key; | ||
724 | kfree(ft->name); | ||
725 | kfree(key); | ||
726 | kfree(datum); | ||
727 | cond_resched(); | ||
728 | return 0; | ||
729 | } | ||
730 | |||
678 | static int range_tr_destroy(void *key, void *datum, void *p) | 731 | static int range_tr_destroy(void *key, void *datum, void *p) |
679 | { | 732 | { |
680 | struct mls_range *rt = datum; | 733 | struct mls_range *rt = datum; |
@@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p) | |||
709 | int i; | 762 | int i; |
710 | struct role_allow *ra, *lra = NULL; | 763 | struct role_allow *ra, *lra = NULL; |
711 | struct role_trans *tr, *ltr = NULL; | 764 | struct role_trans *tr, *ltr = NULL; |
712 | struct filename_trans *ft, *nft; | ||
713 | 765 | ||
714 | for (i = 0; i < SYM_NUM; i++) { | 766 | for (i = 0; i < SYM_NUM; i++) { |
715 | cond_resched(); | 767 | cond_resched(); |
@@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p) | |||
773 | } | 825 | } |
774 | kfree(lra); | 826 | kfree(lra); |
775 | 827 | ||
828 | hashtab_map(p->filename_trans, filenametr_destroy, NULL); | ||
829 | hashtab_destroy(p->filename_trans); | ||
830 | |||
776 | hashtab_map(p->range_tr, range_tr_destroy, NULL); | 831 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
777 | hashtab_destroy(p->range_tr); | 832 | hashtab_destroy(p->range_tr); |
778 | 833 | ||
@@ -788,14 +843,7 @@ void policydb_destroy(struct policydb *p) | |||
788 | flex_array_free(p->type_attr_map_array); | 843 | flex_array_free(p->type_attr_map_array); |
789 | } | 844 | } |
790 | 845 | ||
791 | ft = p->filename_trans; | 846 | ebitmap_destroy(&p->filename_trans_ttypes); |
792 | while (ft) { | ||
793 | nft = ft->next; | ||
794 | kfree(ft->name); | ||
795 | kfree(ft); | ||
796 | ft = nft; | ||
797 | } | ||
798 | |||
799 | ebitmap_destroy(&p->policycaps); | 847 | ebitmap_destroy(&p->policycaps); |
800 | ebitmap_destroy(&p->permissive_map); | 848 | ebitmap_destroy(&p->permissive_map); |
801 | 849 | ||
@@ -1795,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp) | |||
1795 | rt = NULL; | 1843 | rt = NULL; |
1796 | r = NULL; | 1844 | r = NULL; |
1797 | } | 1845 | } |
1798 | rangetr_hash_eval(p->range_tr); | 1846 | hash_eval(p->range_tr, "rangetr"); |
1799 | rc = 0; | 1847 | rc = 0; |
1800 | out: | 1848 | out: |
1801 | kfree(rt); | 1849 | kfree(rt); |
@@ -1805,9 +1853,10 @@ out: | |||
1805 | 1853 | ||
1806 | static int filename_trans_read(struct policydb *p, void *fp) | 1854 | static int filename_trans_read(struct policydb *p, void *fp) |
1807 | { | 1855 | { |
1808 | struct filename_trans *ft, *last; | 1856 | struct filename_trans *ft; |
1809 | u32 nel, len; | 1857 | struct filename_trans_datum *otype; |
1810 | char *name; | 1858 | char *name; |
1859 | u32 nel, len; | ||
1811 | __le32 buf[4]; | 1860 | __le32 buf[4]; |
1812 | int rc, i; | 1861 | int rc, i; |
1813 | 1862 | ||
@@ -1816,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1816 | 1865 | ||
1817 | rc = next_entry(buf, fp, sizeof(u32)); | 1866 | rc = next_entry(buf, fp, sizeof(u32)); |
1818 | if (rc) | 1867 | if (rc) |
1819 | goto out; | 1868 | return rc; |
1820 | nel = le32_to_cpu(buf[0]); | 1869 | nel = le32_to_cpu(buf[0]); |
1821 | 1870 | ||
1822 | last = p->filename_trans; | ||
1823 | while (last && last->next) | ||
1824 | last = last->next; | ||
1825 | |||
1826 | for (i = 0; i < nel; i++) { | 1871 | for (i = 0; i < nel; i++) { |
1872 | ft = NULL; | ||
1873 | otype = NULL; | ||
1874 | name = NULL; | ||
1875 | |||
1827 | rc = -ENOMEM; | 1876 | rc = -ENOMEM; |
1828 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); | 1877 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); |
1829 | if (!ft) | 1878 | if (!ft) |
1830 | goto out; | 1879 | goto out; |
1831 | 1880 | ||
1832 | /* add it to the tail of the list */ | 1881 | rc = -ENOMEM; |
1833 | if (!last) | 1882 | otype = kmalloc(sizeof(*otype), GFP_KERNEL); |
1834 | p->filename_trans = ft; | 1883 | if (!otype) |
1835 | else | 1884 | goto out; |
1836 | last->next = ft; | ||
1837 | last = ft; | ||
1838 | 1885 | ||
1839 | /* length of the path component string */ | 1886 | /* length of the path component string */ |
1840 | rc = next_entry(buf, fp, sizeof(u32)); | 1887 | rc = next_entry(buf, fp, sizeof(u32)); |
@@ -1862,10 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1862 | ft->stype = le32_to_cpu(buf[0]); | 1909 | ft->stype = le32_to_cpu(buf[0]); |
1863 | ft->ttype = le32_to_cpu(buf[1]); | 1910 | ft->ttype = le32_to_cpu(buf[1]); |
1864 | ft->tclass = le32_to_cpu(buf[2]); | 1911 | ft->tclass = le32_to_cpu(buf[2]); |
1865 | ft->otype = le32_to_cpu(buf[3]); | 1912 | |
1913 | otype->otype = le32_to_cpu(buf[3]); | ||
1914 | |||
1915 | rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1); | ||
1916 | if (rc) | ||
1917 | goto out; | ||
1918 | |||
1919 | hashtab_insert(p->filename_trans, ft, otype); | ||
1866 | } | 1920 | } |
1867 | rc = 0; | 1921 | hash_eval(p->filename_trans, "filenametr"); |
1922 | return 0; | ||
1868 | out: | 1923 | out: |
1924 | kfree(ft); | ||
1925 | kfree(name); | ||
1926 | kfree(otype); | ||
1927 | |||
1869 | return rc; | 1928 | return rc; |
1870 | } | 1929 | } |
1871 | 1930 | ||
@@ -2266,6 +2325,11 @@ int policydb_read(struct policydb *p, void *fp) | |||
2266 | p->symtab[i].nprim = nprim; | 2325 | p->symtab[i].nprim = nprim; |
2267 | } | 2326 | } |
2268 | 2327 | ||
2328 | rc = -EINVAL; | ||
2329 | p->process_class = string_to_security_class(p, "process"); | ||
2330 | if (!p->process_class) | ||
2331 | goto bad; | ||
2332 | |||
2269 | rc = avtab_read(&p->te_avtab, fp, p); | 2333 | rc = avtab_read(&p->te_avtab, fp, p); |
2270 | if (rc) | 2334 | if (rc) |
2271 | goto bad; | 2335 | goto bad; |
@@ -2298,8 +2362,17 @@ int policydb_read(struct policydb *p, void *fp) | |||
2298 | tr->role = le32_to_cpu(buf[0]); | 2362 | tr->role = le32_to_cpu(buf[0]); |
2299 | tr->type = le32_to_cpu(buf[1]); | 2363 | tr->type = le32_to_cpu(buf[1]); |
2300 | tr->new_role = le32_to_cpu(buf[2]); | 2364 | tr->new_role = le32_to_cpu(buf[2]); |
2365 | if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { | ||
2366 | rc = next_entry(buf, fp, sizeof(u32)); | ||
2367 | if (rc) | ||
2368 | goto bad; | ||
2369 | tr->tclass = le32_to_cpu(buf[0]); | ||
2370 | } else | ||
2371 | tr->tclass = p->process_class; | ||
2372 | |||
2301 | if (!policydb_role_isvalid(p, tr->role) || | 2373 | if (!policydb_role_isvalid(p, tr->role) || |
2302 | !policydb_type_isvalid(p, tr->type) || | 2374 | !policydb_type_isvalid(p, tr->type) || |
2375 | !policydb_class_isvalid(p, tr->tclass) || | ||
2303 | !policydb_role_isvalid(p, tr->new_role)) | 2376 | !policydb_role_isvalid(p, tr->new_role)) |
2304 | goto bad; | 2377 | goto bad; |
2305 | ltr = tr; | 2378 | ltr = tr; |
@@ -2341,11 +2414,6 @@ int policydb_read(struct policydb *p, void *fp) | |||
2341 | goto bad; | 2414 | goto bad; |
2342 | 2415 | ||
2343 | rc = -EINVAL; | 2416 | rc = -EINVAL; |
2344 | p->process_class = string_to_security_class(p, "process"); | ||
2345 | if (!p->process_class) | ||
2346 | goto bad; | ||
2347 | |||
2348 | rc = -EINVAL; | ||
2349 | p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); | 2417 | p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); |
2350 | p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); | 2418 | p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); |
2351 | if (!p->process_trans_perms) | 2419 | if (!p->process_trans_perms) |
@@ -2517,8 +2585,9 @@ static int cat_write(void *vkey, void *datum, void *ptr) | |||
2517 | return 0; | 2585 | return 0; |
2518 | } | 2586 | } |
2519 | 2587 | ||
2520 | static int role_trans_write(struct role_trans *r, void *fp) | 2588 | static int role_trans_write(struct policydb *p, void *fp) |
2521 | { | 2589 | { |
2590 | struct role_trans *r = p->role_tr; | ||
2522 | struct role_trans *tr; | 2591 | struct role_trans *tr; |
2523 | u32 buf[3]; | 2592 | u32 buf[3]; |
2524 | size_t nel; | 2593 | size_t nel; |
@@ -2538,6 +2607,12 @@ static int role_trans_write(struct role_trans *r, void *fp) | |||
2538 | rc = put_entry(buf, sizeof(u32), 3, fp); | 2607 | rc = put_entry(buf, sizeof(u32), 3, fp); |
2539 | if (rc) | 2608 | if (rc) |
2540 | return rc; | 2609 | return rc; |
2610 | if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { | ||
2611 | buf[0] = cpu_to_le32(tr->tclass); | ||
2612 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
2613 | if (rc) | ||
2614 | return rc; | ||
2615 | } | ||
2541 | } | 2616 | } |
2542 | 2617 | ||
2543 | return 0; | 2618 | return 0; |
@@ -3045,7 +3120,7 @@ static int genfs_write(struct policydb *p, void *fp) | |||
3045 | return 0; | 3120 | return 0; |
3046 | } | 3121 | } |
3047 | 3122 | ||
3048 | static int range_count(void *key, void *data, void *ptr) | 3123 | static int hashtab_cnt(void *key, void *data, void *ptr) |
3049 | { | 3124 | { |
3050 | int *cnt = ptr; | 3125 | int *cnt = ptr; |
3051 | *cnt = *cnt + 1; | 3126 | *cnt = *cnt + 1; |
@@ -3093,7 +3168,7 @@ static int range_write(struct policydb *p, void *fp) | |||
3093 | 3168 | ||
3094 | /* count the number of entries in the hashtab */ | 3169 | /* count the number of entries in the hashtab */ |
3095 | nel = 0; | 3170 | nel = 0; |
3096 | rc = hashtab_map(p->range_tr, range_count, &nel); | 3171 | rc = hashtab_map(p->range_tr, hashtab_cnt, &nel); |
3097 | if (rc) | 3172 | if (rc) |
3098 | return rc; | 3173 | return rc; |
3099 | 3174 | ||
@@ -3110,43 +3185,60 @@ static int range_write(struct policydb *p, void *fp) | |||
3110 | return 0; | 3185 | return 0; |
3111 | } | 3186 | } |
3112 | 3187 | ||
3113 | static int filename_trans_write(struct policydb *p, void *fp) | 3188 | static int filename_write_helper(void *key, void *data, void *ptr) |
3114 | { | 3189 | { |
3115 | struct filename_trans *ft; | ||
3116 | u32 len, nel = 0; | ||
3117 | __le32 buf[4]; | 3190 | __le32 buf[4]; |
3191 | struct filename_trans *ft = key; | ||
3192 | struct filename_trans_datum *otype = data; | ||
3193 | void *fp = ptr; | ||
3118 | int rc; | 3194 | int rc; |
3195 | u32 len; | ||
3119 | 3196 | ||
3120 | for (ft = p->filename_trans; ft; ft = ft->next) | 3197 | len = strlen(ft->name); |
3121 | nel++; | 3198 | buf[0] = cpu_to_le32(len); |
3122 | |||
3123 | buf[0] = cpu_to_le32(nel); | ||
3124 | rc = put_entry(buf, sizeof(u32), 1, fp); | 3199 | rc = put_entry(buf, sizeof(u32), 1, fp); |
3125 | if (rc) | 3200 | if (rc) |
3126 | return rc; | 3201 | return rc; |
3127 | 3202 | ||
3128 | for (ft = p->filename_trans; ft; ft = ft->next) { | 3203 | rc = put_entry(ft->name, sizeof(char), len, fp); |
3129 | len = strlen(ft->name); | 3204 | if (rc) |
3130 | buf[0] = cpu_to_le32(len); | 3205 | return rc; |
3131 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3132 | if (rc) | ||
3133 | return rc; | ||
3134 | 3206 | ||
3135 | rc = put_entry(ft->name, sizeof(char), len, fp); | 3207 | buf[0] = ft->stype; |
3136 | if (rc) | 3208 | buf[1] = ft->ttype; |
3137 | return rc; | 3209 | buf[2] = ft->tclass; |
3210 | buf[3] = otype->otype; | ||
3138 | 3211 | ||
3139 | buf[0] = ft->stype; | 3212 | rc = put_entry(buf, sizeof(u32), 4, fp); |
3140 | buf[1] = ft->ttype; | 3213 | if (rc) |
3141 | buf[2] = ft->tclass; | 3214 | return rc; |
3142 | buf[3] = ft->otype; | ||
3143 | 3215 | ||
3144 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
3145 | if (rc) | ||
3146 | return rc; | ||
3147 | } | ||
3148 | return 0; | 3216 | return 0; |
3149 | } | 3217 | } |
3218 | |||
3219 | static int filename_trans_write(struct policydb *p, void *fp) | ||
3220 | { | ||
3221 | u32 nel; | ||
3222 | __le32 buf[1]; | ||
3223 | int rc; | ||
3224 | |||
3225 | nel = 0; | ||
3226 | rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel); | ||
3227 | if (rc) | ||
3228 | return rc; | ||
3229 | |||
3230 | buf[0] = cpu_to_le32(nel); | ||
3231 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3232 | if (rc) | ||
3233 | return rc; | ||
3234 | |||
3235 | rc = hashtab_map(p->filename_trans, filename_write_helper, fp); | ||
3236 | if (rc) | ||
3237 | return rc; | ||
3238 | |||
3239 | return 0; | ||
3240 | } | ||
3241 | |||
3150 | /* | 3242 | /* |
3151 | * Write the configuration data in a policy database | 3243 | * Write the configuration data in a policy database |
3152 | * structure to a policy database binary representation | 3244 | * structure to a policy database binary representation |
@@ -3249,7 +3341,7 @@ int policydb_write(struct policydb *p, void *fp) | |||
3249 | if (rc) | 3341 | if (rc) |
3250 | return rc; | 3342 | return rc; |
3251 | 3343 | ||
3252 | rc = role_trans_write(p->role_tr, fp); | 3344 | rc = role_trans_write(p, fp); |
3253 | if (rc) | 3345 | if (rc) |
3254 | return rc; | 3346 | return rc; |
3255 | 3347 | ||
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 732ea4a68682..b846c0387180 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -72,17 +72,20 @@ struct role_datum { | |||
72 | 72 | ||
73 | struct role_trans { | 73 | struct role_trans { |
74 | u32 role; /* current role */ | 74 | u32 role; /* current role */ |
75 | u32 type; /* program executable type */ | 75 | u32 type; /* program executable type, or new object type */ |
76 | u32 tclass; /* process class, or new object class */ | ||
76 | u32 new_role; /* new role */ | 77 | u32 new_role; /* new role */ |
77 | struct role_trans *next; | 78 | struct role_trans *next; |
78 | }; | 79 | }; |
79 | 80 | ||
80 | struct filename_trans { | 81 | struct filename_trans { |
81 | struct filename_trans *next; | ||
82 | u32 stype; /* current process */ | 82 | u32 stype; /* current process */ |
83 | u32 ttype; /* parent dir context */ | 83 | u32 ttype; /* parent dir context */ |
84 | u16 tclass; /* class of new object */ | 84 | u16 tclass; /* class of new object */ |
85 | const char *name; /* last path component */ | 85 | const char *name; /* last path component */ |
86 | }; | ||
87 | |||
88 | struct filename_trans_datum { | ||
86 | u32 otype; /* expected of new object */ | 89 | u32 otype; /* expected of new object */ |
87 | }; | 90 | }; |
88 | 91 | ||
@@ -227,7 +230,10 @@ struct policydb { | |||
227 | struct role_trans *role_tr; | 230 | struct role_trans *role_tr; |
228 | 231 | ||
229 | /* file transitions with the last path component */ | 232 | /* file transitions with the last path component */ |
230 | struct filename_trans *filename_trans; | 233 | /* quickly exclude lookups when parent ttype has no rules */ |
234 | struct ebitmap filename_trans_ttypes; | ||
235 | /* actual set of filename_trans rules */ | ||
236 | struct hashtab *filename_trans; | ||
231 | 237 | ||
232 | /* bools indexed by (value - 1) */ | 238 | /* bools indexed by (value - 1) */ |
233 | struct cond_bool_datum **bool_val_to_struct; | 239 | struct cond_bool_datum **bool_val_to_struct; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 6ef4af47dac4..c3e4b52699f4 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1359,26 +1359,35 @@ out: | |||
1359 | } | 1359 | } |
1360 | 1360 | ||
1361 | static void filename_compute_type(struct policydb *p, struct context *newcontext, | 1361 | static void filename_compute_type(struct policydb *p, struct context *newcontext, |
1362 | u32 scon, u32 tcon, u16 tclass, | 1362 | u32 stype, u32 ttype, u16 tclass, |
1363 | const struct qstr *qstr) | 1363 | const char *objname) |
1364 | { | 1364 | { |
1365 | struct filename_trans *ft; | 1365 | struct filename_trans ft; |
1366 | for (ft = p->filename_trans; ft; ft = ft->next) { | 1366 | struct filename_trans_datum *otype; |
1367 | if (ft->stype == scon && | 1367 | |
1368 | ft->ttype == tcon && | 1368 | /* |
1369 | ft->tclass == tclass && | 1369 | * Most filename trans rules are going to live in specific directories |
1370 | !strcmp(ft->name, qstr->name)) { | 1370 | * like /dev or /var/run. This bitmap will quickly skip rule searches |
1371 | newcontext->type = ft->otype; | 1371 | * if the ttype does not contain any rules. |
1372 | return; | 1372 | */ |
1373 | } | 1373 | if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) |
1374 | } | 1374 | return; |
1375 | |||
1376 | ft.stype = stype; | ||
1377 | ft.ttype = ttype; | ||
1378 | ft.tclass = tclass; | ||
1379 | ft.name = objname; | ||
1380 | |||
1381 | otype = hashtab_search(p->filename_trans, &ft); | ||
1382 | if (otype) | ||
1383 | newcontext->type = otype->otype; | ||
1375 | } | 1384 | } |
1376 | 1385 | ||
1377 | static int security_compute_sid(u32 ssid, | 1386 | static int security_compute_sid(u32 ssid, |
1378 | u32 tsid, | 1387 | u32 tsid, |
1379 | u16 orig_tclass, | 1388 | u16 orig_tclass, |
1380 | u32 specified, | 1389 | u32 specified, |
1381 | const struct qstr *qstr, | 1390 | const char *objname, |
1382 | u32 *out_sid, | 1391 | u32 *out_sid, |
1383 | bool kern) | 1392 | bool kern) |
1384 | { | 1393 | { |
@@ -1478,23 +1487,21 @@ static int security_compute_sid(u32 ssid, | |||
1478 | newcontext.type = avdatum->data; | 1487 | newcontext.type = avdatum->data; |
1479 | } | 1488 | } |
1480 | 1489 | ||
1481 | /* if we have a qstr this is a file trans check so check those rules */ | 1490 | /* if we have a objname this is a file trans check so check those rules */ |
1482 | if (qstr) | 1491 | if (objname) |
1483 | filename_compute_type(&policydb, &newcontext, scontext->type, | 1492 | filename_compute_type(&policydb, &newcontext, scontext->type, |
1484 | tcontext->type, tclass, qstr); | 1493 | tcontext->type, tclass, objname); |
1485 | 1494 | ||
1486 | /* Check for class-specific changes. */ | 1495 | /* Check for class-specific changes. */ |
1487 | if (tclass == policydb.process_class) { | 1496 | if (specified & AVTAB_TRANSITION) { |
1488 | if (specified & AVTAB_TRANSITION) { | 1497 | /* Look for a role transition rule. */ |
1489 | /* Look for a role transition rule. */ | 1498 | for (roletr = policydb.role_tr; roletr; roletr = roletr->next) { |
1490 | for (roletr = policydb.role_tr; roletr; | 1499 | if ((roletr->role == scontext->role) && |
1491 | roletr = roletr->next) { | 1500 | (roletr->type == tcontext->type) && |
1492 | if (roletr->role == scontext->role && | 1501 | (roletr->tclass == tclass)) { |
1493 | roletr->type == tcontext->type) { | 1502 | /* Use the role transition rule. */ |
1494 | /* Use the role transition rule. */ | 1503 | newcontext.role = roletr->new_role; |
1495 | newcontext.role = roletr->new_role; | 1504 | break; |
1496 | break; | ||
1497 | } | ||
1498 | } | 1505 | } |
1499 | } | 1506 | } |
1500 | } | 1507 | } |
@@ -1541,13 +1548,14 @@ int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, | |||
1541 | const struct qstr *qstr, u32 *out_sid) | 1548 | const struct qstr *qstr, u32 *out_sid) |
1542 | { | 1549 | { |
1543 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, | 1550 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, |
1544 | qstr, out_sid, true); | 1551 | qstr ? qstr->name : NULL, out_sid, true); |
1545 | } | 1552 | } |
1546 | 1553 | ||
1547 | int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) | 1554 | int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, |
1555 | const char *objname, u32 *out_sid) | ||
1548 | { | 1556 | { |
1549 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, | 1557 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, |
1550 | NULL, out_sid, false); | 1558 | objname, out_sid, false); |
1551 | } | 1559 | } |
1552 | 1560 | ||
1553 | /** | 1561 | /** |
@@ -3190,7 +3198,7 @@ out: | |||
3190 | * @len: length of data in bytes | 3198 | * @len: length of data in bytes |
3191 | * | 3199 | * |
3192 | */ | 3200 | */ |
3193 | int security_read_policy(void **data, ssize_t *len) | 3201 | int security_read_policy(void **data, size_t *len) |
3194 | { | 3202 | { |
3195 | int rc; | 3203 | int rc; |
3196 | struct policy_file fp; | 3204 | struct policy_file fp; |