diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2011-05-14 06:06:36 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2011-05-14 06:06:36 -0400 |
commit | a18f22a968de17b29f2310cdb7ba69163e65ec15 (patch) | |
tree | a7d56d88fad5e444d7661484109758a2f436129e /security/selinux | |
parent | a1c57e0fec53defe745e64417eacdbd3618c3e66 (diff) | |
parent | 798778b8653f64b7b2162ac70eca10367cff6ce8 (diff) |
Merge branch 'consolidate-clksrc-i8253' of master.kernel.org:~rmk/linux-2.6-arm into timers/clocksource
Conflicts:
arch/ia64/kernel/cyclone.c
arch/mips/kernel/i8253.c
arch/x86/kernel/i8253.c
Reason: Resolve conflicts so further cleanups do not conflict further
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/avc.c | 36 | ||||
-rw-r--r-- | security/selinux/hooks.c | 396 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 18 | ||||
-rw-r--r-- | security/selinux/include/classmap.h | 7 | ||||
-rw-r--r-- | security/selinux/include/security.h | 8 | ||||
-rw-r--r-- | security/selinux/include/xfrm.h | 2 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 2 | ||||
-rw-r--r-- | security/selinux/ss/avtab.h | 23 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.h | 1 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 5 | ||||
-rw-r--r-- | security/selinux/ss/mls.h | 3 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 136 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 14 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 77 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 8 |
15 files changed, 493 insertions, 243 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 9da6420e2056..1d027e29ce8d 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -471,6 +471,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
471 | * @avd: access vector decisions | 471 | * @avd: access vector decisions |
472 | * @result: result from avc_has_perm_noaudit | 472 | * @result: result from avc_has_perm_noaudit |
473 | * @a: auxiliary audit data | 473 | * @a: auxiliary audit data |
474 | * @flags: VFS walk flags | ||
474 | * | 475 | * |
475 | * Audit the granting or denial of permissions in accordance | 476 | * Audit the granting or denial of permissions in accordance |
476 | * with the policy. This function is typically called by | 477 | * with the policy. This function is typically called by |
@@ -481,9 +482,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
481 | * be performed under a lock, to allow the lock to be released | 482 | * be performed under a lock, to allow the lock to be released |
482 | * before calling the auditing code. | 483 | * before calling the auditing code. |
483 | */ | 484 | */ |
484 | void avc_audit(u32 ssid, u32 tsid, | 485 | int avc_audit(u32 ssid, u32 tsid, |
485 | u16 tclass, u32 requested, | 486 | u16 tclass, u32 requested, |
486 | struct av_decision *avd, int result, struct common_audit_data *a) | 487 | struct av_decision *avd, int result, struct common_audit_data *a, |
488 | unsigned flags) | ||
487 | { | 489 | { |
488 | struct common_audit_data stack_data; | 490 | struct common_audit_data stack_data; |
489 | u32 denied, audited; | 491 | u32 denied, audited; |
@@ -515,11 +517,24 @@ void avc_audit(u32 ssid, u32 tsid, | |||
515 | else | 517 | else |
516 | audited = requested & avd->auditallow; | 518 | audited = requested & avd->auditallow; |
517 | if (!audited) | 519 | if (!audited) |
518 | return; | 520 | return 0; |
521 | |||
519 | if (!a) { | 522 | if (!a) { |
520 | a = &stack_data; | 523 | a = &stack_data; |
521 | COMMON_AUDIT_DATA_INIT(a, NONE); | 524 | COMMON_AUDIT_DATA_INIT(a, NONE); |
522 | } | 525 | } |
526 | |||
527 | /* | ||
528 | * When in a RCU walk do the audit on the RCU retry. This is because | ||
529 | * the collection of the dname in an inode audit message is not RCU | ||
530 | * safe. Note this may drop some audits when the situation changes | ||
531 | * during retry. However this is logically just as if the operation | ||
532 | * happened a little later. | ||
533 | */ | ||
534 | if ((a->type == LSM_AUDIT_DATA_FS) && | ||
535 | (flags & IPERM_FLAG_RCU)) | ||
536 | return -ECHILD; | ||
537 | |||
523 | a->selinux_audit_data.tclass = tclass; | 538 | a->selinux_audit_data.tclass = tclass; |
524 | a->selinux_audit_data.requested = requested; | 539 | a->selinux_audit_data.requested = requested; |
525 | a->selinux_audit_data.ssid = ssid; | 540 | a->selinux_audit_data.ssid = ssid; |
@@ -529,6 +544,7 @@ void avc_audit(u32 ssid, u32 tsid, | |||
529 | a->lsm_pre_audit = avc_audit_pre_callback; | 544 | a->lsm_pre_audit = avc_audit_pre_callback; |
530 | a->lsm_post_audit = avc_audit_post_callback; | 545 | a->lsm_post_audit = avc_audit_post_callback; |
531 | common_lsm_audit(a); | 546 | common_lsm_audit(a); |
547 | return 0; | ||
532 | } | 548 | } |
533 | 549 | ||
534 | /** | 550 | /** |
@@ -793,6 +809,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
793 | * @tclass: target security class | 809 | * @tclass: target security class |
794 | * @requested: requested permissions, interpreted based on @tclass | 810 | * @requested: requested permissions, interpreted based on @tclass |
795 | * @auditdata: auxiliary audit data | 811 | * @auditdata: auxiliary audit data |
812 | * @flags: VFS walk flags | ||
796 | * | 813 | * |
797 | * Check the AVC to determine whether the @requested permissions are granted | 814 | * Check the AVC to determine whether the @requested permissions are granted |
798 | * for the SID pair (@ssid, @tsid), interpreting the permissions | 815 | * for the SID pair (@ssid, @tsid), interpreting the permissions |
@@ -802,14 +819,19 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
802 | * permissions are granted, -%EACCES if any permissions are denied, or | 819 | * permissions are granted, -%EACCES if any permissions are denied, or |
803 | * another -errno upon other errors. | 820 | * another -errno upon other errors. |
804 | */ | 821 | */ |
805 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, | 822 | int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass, |
806 | u32 requested, struct common_audit_data *auditdata) | 823 | u32 requested, struct common_audit_data *auditdata, |
824 | unsigned flags) | ||
807 | { | 825 | { |
808 | struct av_decision avd; | 826 | struct av_decision avd; |
809 | int rc; | 827 | int rc, rc2; |
810 | 828 | ||
811 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); | 829 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); |
812 | avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); | 830 | |
831 | rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, | ||
832 | flags); | ||
833 | if (rc2) | ||
834 | return rc2; | ||
813 | return rc; | 835 | return rc; |
814 | } | 836 | } |
815 | 837 | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c8d699270687..8fb248843009 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -24,9 +24,11 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/kd.h> | ||
27 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
28 | #include <linux/tracehook.h> | 29 | #include <linux/tracehook.h> |
29 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
31 | #include <linux/ext2_fs.h> | ||
30 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
31 | #include <linux/security.h> | 33 | #include <linux/security.h> |
32 | #include <linux/xattr.h> | 34 | #include <linux/xattr.h> |
@@ -36,14 +38,15 @@ | |||
36 | #include <linux/mman.h> | 38 | #include <linux/mman.h> |
37 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
38 | #include <linux/pagemap.h> | 40 | #include <linux/pagemap.h> |
41 | #include <linux/proc_fs.h> | ||
39 | #include <linux/swap.h> | 42 | #include <linux/swap.h> |
40 | #include <linux/spinlock.h> | 43 | #include <linux/spinlock.h> |
41 | #include <linux/syscalls.h> | 44 | #include <linux/syscalls.h> |
45 | #include <linux/dcache.h> | ||
42 | #include <linux/file.h> | 46 | #include <linux/file.h> |
43 | #include <linux/fdtable.h> | 47 | #include <linux/fdtable.h> |
44 | #include <linux/namei.h> | 48 | #include <linux/namei.h> |
45 | #include <linux/mount.h> | 49 | #include <linux/mount.h> |
46 | #include <linux/proc_fs.h> | ||
47 | #include <linux/netfilter_ipv4.h> | 50 | #include <linux/netfilter_ipv4.h> |
48 | #include <linux/netfilter_ipv6.h> | 51 | #include <linux/netfilter_ipv6.h> |
49 | #include <linux/tty.h> | 52 | #include <linux/tty.h> |
@@ -70,13 +73,13 @@ | |||
70 | #include <net/ipv6.h> | 73 | #include <net/ipv6.h> |
71 | #include <linux/hugetlb.h> | 74 | #include <linux/hugetlb.h> |
72 | #include <linux/personality.h> | 75 | #include <linux/personality.h> |
73 | #include <linux/sysctl.h> | ||
74 | #include <linux/audit.h> | 76 | #include <linux/audit.h> |
75 | #include <linux/string.h> | 77 | #include <linux/string.h> |
76 | #include <linux/selinux.h> | 78 | #include <linux/selinux.h> |
77 | #include <linux/mutex.h> | 79 | #include <linux/mutex.h> |
78 | #include <linux/posix-timers.h> | 80 | #include <linux/posix-timers.h> |
79 | #include <linux/syslog.h> | 81 | #include <linux/syslog.h> |
82 | #include <linux/user_namespace.h> | ||
80 | 83 | ||
81 | #include "avc.h" | 84 | #include "avc.h" |
82 | #include "objsec.h" | 85 | #include "objsec.h" |
@@ -1120,39 +1123,35 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc | |||
1120 | } | 1123 | } |
1121 | 1124 | ||
1122 | #ifdef CONFIG_PROC_FS | 1125 | #ifdef CONFIG_PROC_FS |
1123 | static int selinux_proc_get_sid(struct proc_dir_entry *de, | 1126 | static int selinux_proc_get_sid(struct dentry *dentry, |
1124 | u16 tclass, | 1127 | u16 tclass, |
1125 | u32 *sid) | 1128 | u32 *sid) |
1126 | { | 1129 | { |
1127 | int buflen, rc; | 1130 | int rc; |
1128 | char *buffer, *path, *end; | 1131 | char *buffer, *path; |
1129 | 1132 | ||
1130 | buffer = (char *)__get_free_page(GFP_KERNEL); | 1133 | buffer = (char *)__get_free_page(GFP_KERNEL); |
1131 | if (!buffer) | 1134 | if (!buffer) |
1132 | return -ENOMEM; | 1135 | return -ENOMEM; |
1133 | 1136 | ||
1134 | buflen = PAGE_SIZE; | 1137 | path = dentry_path_raw(dentry, buffer, PAGE_SIZE); |
1135 | end = buffer+buflen; | 1138 | if (IS_ERR(path)) |
1136 | *--end = '\0'; | 1139 | rc = PTR_ERR(path); |
1137 | buflen--; | 1140 | else { |
1138 | path = end-1; | 1141 | /* each process gets a /proc/PID/ entry. Strip off the |
1139 | *path = '/'; | 1142 | * PID part to get a valid selinux labeling. |
1140 | while (de && de != de->parent) { | 1143 | * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ |
1141 | buflen -= de->namelen + 1; | 1144 | while (path[1] >= '0' && path[1] <= '9') { |
1142 | if (buflen < 0) | 1145 | path[1] = '/'; |
1143 | break; | 1146 | path++; |
1144 | end -= de->namelen; | 1147 | } |
1145 | memcpy(end, de->name, de->namelen); | 1148 | rc = security_genfs_sid("proc", path, tclass, sid); |
1146 | *--end = '/'; | ||
1147 | path = end; | ||
1148 | de = de->parent; | ||
1149 | } | 1149 | } |
1150 | rc = security_genfs_sid("proc", path, tclass, sid); | ||
1151 | free_page((unsigned long)buffer); | 1150 | free_page((unsigned long)buffer); |
1152 | return rc; | 1151 | return rc; |
1153 | } | 1152 | } |
1154 | #else | 1153 | #else |
1155 | static int selinux_proc_get_sid(struct proc_dir_entry *de, | 1154 | static int selinux_proc_get_sid(struct dentry *dentry, |
1156 | u16 tclass, | 1155 | u16 tclass, |
1157 | u32 *sid) | 1156 | u32 *sid) |
1158 | { | 1157 | { |
@@ -1300,10 +1299,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1300 | 1299 | ||
1301 | /* Try to obtain a transition SID. */ | 1300 | /* Try to obtain a transition SID. */ |
1302 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1301 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
1303 | rc = security_transition_sid(isec->task_sid, | 1302 | rc = security_transition_sid(isec->task_sid, sbsec->sid, |
1304 | sbsec->sid, | 1303 | isec->sclass, NULL, &sid); |
1305 | isec->sclass, | ||
1306 | &sid); | ||
1307 | if (rc) | 1304 | if (rc) |
1308 | goto out_unlock; | 1305 | goto out_unlock; |
1309 | isec->sid = sid; | 1306 | isec->sid = sid; |
@@ -1316,10 +1313,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1316 | isec->sid = sbsec->sid; | 1313 | isec->sid = sbsec->sid; |
1317 | 1314 | ||
1318 | if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { | 1315 | if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { |
1319 | struct proc_inode *proci = PROC_I(inode); | 1316 | if (opt_dentry) { |
1320 | if (proci->pde) { | ||
1321 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1317 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
1322 | rc = selinux_proc_get_sid(proci->pde, | 1318 | rc = selinux_proc_get_sid(opt_dentry, |
1323 | isec->sclass, | 1319 | isec->sclass, |
1324 | &sid); | 1320 | &sid); |
1325 | if (rc) | 1321 | if (rc) |
@@ -1450,8 +1446,11 @@ static int task_has_capability(struct task_struct *tsk, | |||
1450 | } | 1446 | } |
1451 | 1447 | ||
1452 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); | 1448 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); |
1453 | if (audit == SECURITY_CAP_AUDIT) | 1449 | if (audit == SECURITY_CAP_AUDIT) { |
1454 | avc_audit(sid, sid, sclass, av, &avd, rc, &ad); | 1450 | int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0); |
1451 | if (rc2) | ||
1452 | return rc2; | ||
1453 | } | ||
1455 | return rc; | 1454 | return rc; |
1456 | } | 1455 | } |
1457 | 1456 | ||
@@ -1471,7 +1470,8 @@ static int task_has_system(struct task_struct *tsk, | |||
1471 | static int inode_has_perm(const struct cred *cred, | 1470 | static int inode_has_perm(const struct cred *cred, |
1472 | struct inode *inode, | 1471 | struct inode *inode, |
1473 | u32 perms, | 1472 | u32 perms, |
1474 | struct common_audit_data *adp) | 1473 | struct common_audit_data *adp, |
1474 | unsigned flags) | ||
1475 | { | 1475 | { |
1476 | struct inode_security_struct *isec; | 1476 | struct inode_security_struct *isec; |
1477 | struct common_audit_data ad; | 1477 | struct common_audit_data ad; |
@@ -1491,7 +1491,7 @@ static int inode_has_perm(const struct cred *cred, | |||
1491 | ad.u.fs.inode = inode; | 1491 | ad.u.fs.inode = inode; |
1492 | } | 1492 | } |
1493 | 1493 | ||
1494 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); | 1494 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); |
1495 | } | 1495 | } |
1496 | 1496 | ||
1497 | /* Same as inode_has_perm, but pass explicit audit data containing | 1497 | /* Same as inode_has_perm, but pass explicit audit data containing |
@@ -1508,7 +1508,7 @@ static inline int dentry_has_perm(const struct cred *cred, | |||
1508 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1508 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
1509 | ad.u.fs.path.mnt = mnt; | 1509 | ad.u.fs.path.mnt = mnt; |
1510 | ad.u.fs.path.dentry = dentry; | 1510 | ad.u.fs.path.dentry = dentry; |
1511 | return inode_has_perm(cred, inode, av, &ad); | 1511 | return inode_has_perm(cred, inode, av, &ad, 0); |
1512 | } | 1512 | } |
1513 | 1513 | ||
1514 | /* Check whether a task can use an open file descriptor to | 1514 | /* Check whether a task can use an open file descriptor to |
@@ -1544,7 +1544,7 @@ static int file_has_perm(const struct cred *cred, | |||
1544 | /* av is zero if only checking access to the descriptor. */ | 1544 | /* av is zero if only checking access to the descriptor. */ |
1545 | rc = 0; | 1545 | rc = 0; |
1546 | if (av) | 1546 | if (av) |
1547 | rc = inode_has_perm(cred, inode, av, &ad); | 1547 | rc = inode_has_perm(cred, inode, av, &ad, 0); |
1548 | 1548 | ||
1549 | out: | 1549 | out: |
1550 | return rc; | 1550 | return rc; |
@@ -1578,7 +1578,8 @@ static int may_create(struct inode *dir, | |||
1578 | return rc; | 1578 | return rc; |
1579 | 1579 | ||
1580 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | 1580 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
1581 | rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); | 1581 | rc = security_transition_sid(sid, dsec->sid, tclass, |
1582 | &dentry->d_name, &newsid); | ||
1582 | if (rc) | 1583 | if (rc) |
1583 | return rc; | 1584 | return rc; |
1584 | } | 1585 | } |
@@ -1851,93 +1852,17 @@ static int selinux_capset(struct cred *new, const struct cred *old, | |||
1851 | */ | 1852 | */ |
1852 | 1853 | ||
1853 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, | 1854 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, |
1854 | int cap, int audit) | 1855 | struct user_namespace *ns, int cap, int audit) |
1855 | { | 1856 | { |
1856 | int rc; | 1857 | int rc; |
1857 | 1858 | ||
1858 | rc = cap_capable(tsk, cred, cap, audit); | 1859 | rc = cap_capable(tsk, cred, ns, cap, audit); |
1859 | if (rc) | 1860 | if (rc) |
1860 | return rc; | 1861 | return rc; |
1861 | 1862 | ||
1862 | return task_has_capability(tsk, cred, cap, audit); | 1863 | return task_has_capability(tsk, cred, cap, audit); |
1863 | } | 1864 | } |
1864 | 1865 | ||
1865 | static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) | ||
1866 | { | ||
1867 | int buflen, rc; | ||
1868 | char *buffer, *path, *end; | ||
1869 | |||
1870 | rc = -ENOMEM; | ||
1871 | buffer = (char *)__get_free_page(GFP_KERNEL); | ||
1872 | if (!buffer) | ||
1873 | goto out; | ||
1874 | |||
1875 | buflen = PAGE_SIZE; | ||
1876 | end = buffer+buflen; | ||
1877 | *--end = '\0'; | ||
1878 | buflen--; | ||
1879 | path = end-1; | ||
1880 | *path = '/'; | ||
1881 | while (table) { | ||
1882 | const char *name = table->procname; | ||
1883 | size_t namelen = strlen(name); | ||
1884 | buflen -= namelen + 1; | ||
1885 | if (buflen < 0) | ||
1886 | goto out_free; | ||
1887 | end -= namelen; | ||
1888 | memcpy(end, name, namelen); | ||
1889 | *--end = '/'; | ||
1890 | path = end; | ||
1891 | table = table->parent; | ||
1892 | } | ||
1893 | buflen -= 4; | ||
1894 | if (buflen < 0) | ||
1895 | goto out_free; | ||
1896 | end -= 4; | ||
1897 | memcpy(end, "/sys", 4); | ||
1898 | path = end; | ||
1899 | rc = security_genfs_sid("proc", path, tclass, sid); | ||
1900 | out_free: | ||
1901 | free_page((unsigned long)buffer); | ||
1902 | out: | ||
1903 | return rc; | ||
1904 | } | ||
1905 | |||
1906 | static int selinux_sysctl(ctl_table *table, int op) | ||
1907 | { | ||
1908 | int error = 0; | ||
1909 | u32 av; | ||
1910 | u32 tsid, sid; | ||
1911 | int rc; | ||
1912 | |||
1913 | sid = current_sid(); | ||
1914 | |||
1915 | rc = selinux_sysctl_get_sid(table, (op == 0001) ? | ||
1916 | SECCLASS_DIR : SECCLASS_FILE, &tsid); | ||
1917 | if (rc) { | ||
1918 | /* Default to the well-defined sysctl SID. */ | ||
1919 | tsid = SECINITSID_SYSCTL; | ||
1920 | } | ||
1921 | |||
1922 | /* The op values are "defined" in sysctl.c, thereby creating | ||
1923 | * a bad coupling between this module and sysctl.c */ | ||
1924 | if (op == 001) { | ||
1925 | error = avc_has_perm(sid, tsid, | ||
1926 | SECCLASS_DIR, DIR__SEARCH, NULL); | ||
1927 | } else { | ||
1928 | av = 0; | ||
1929 | if (op & 004) | ||
1930 | av |= FILE__READ; | ||
1931 | if (op & 002) | ||
1932 | av |= FILE__WRITE; | ||
1933 | if (av) | ||
1934 | error = avc_has_perm(sid, tsid, | ||
1935 | SECCLASS_FILE, av, NULL); | ||
1936 | } | ||
1937 | |||
1938 | return error; | ||
1939 | } | ||
1940 | |||
1941 | static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) | 1866 | static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) |
1942 | { | 1867 | { |
1943 | const struct cred *cred = current_cred(); | 1868 | const struct cred *cred = current_cred(); |
@@ -2012,7 +1937,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
2012 | { | 1937 | { |
2013 | int rc, cap_sys_admin = 0; | 1938 | int rc, cap_sys_admin = 0; |
2014 | 1939 | ||
2015 | rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN, | 1940 | rc = selinux_capable(current, current_cred(), |
1941 | &init_user_ns, CAP_SYS_ADMIN, | ||
2016 | SECURITY_CAP_NOAUDIT); | 1942 | SECURITY_CAP_NOAUDIT); |
2017 | if (rc == 0) | 1943 | if (rc == 0) |
2018 | cap_sys_admin = 1; | 1944 | cap_sys_admin = 1; |
@@ -2060,7 +1986,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2060 | } else { | 1986 | } else { |
2061 | /* Check for a default transition on this program. */ | 1987 | /* Check for a default transition on this program. */ |
2062 | rc = security_transition_sid(old_tsec->sid, isec->sid, | 1988 | rc = security_transition_sid(old_tsec->sid, isec->sid, |
2063 | SECCLASS_PROCESS, &new_tsec->sid); | 1989 | SECCLASS_PROCESS, NULL, |
1990 | &new_tsec->sid); | ||
2064 | if (rc) | 1991 | if (rc) |
2065 | return rc; | 1992 | return rc; |
2066 | } | 1993 | } |
@@ -2181,7 +2108,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2181 | file = file_priv->file; | 2108 | file = file_priv->file; |
2182 | inode = file->f_path.dentry->d_inode; | 2109 | inode = file->f_path.dentry->d_inode; |
2183 | if (inode_has_perm(cred, inode, | 2110 | if (inode_has_perm(cred, inode, |
2184 | FILE__READ | FILE__WRITE, NULL)) { | 2111 | FILE__READ | FILE__WRITE, NULL, 0)) { |
2185 | drop_tty = 1; | 2112 | drop_tty = 1; |
2186 | } | 2113 | } |
2187 | } | 2114 | } |
@@ -2443,6 +2370,91 @@ out: | |||
2443 | return rc; | 2370 | return rc; |
2444 | } | 2371 | } |
2445 | 2372 | ||
2373 | static int selinux_sb_remount(struct super_block *sb, void *data) | ||
2374 | { | ||
2375 | int rc, i, *flags; | ||
2376 | struct security_mnt_opts opts; | ||
2377 | char *secdata, **mount_options; | ||
2378 | struct superblock_security_struct *sbsec = sb->s_security; | ||
2379 | |||
2380 | if (!(sbsec->flags & SE_SBINITIALIZED)) | ||
2381 | return 0; | ||
2382 | |||
2383 | if (!data) | ||
2384 | return 0; | ||
2385 | |||
2386 | if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) | ||
2387 | return 0; | ||
2388 | |||
2389 | security_init_mnt_opts(&opts); | ||
2390 | secdata = alloc_secdata(); | ||
2391 | if (!secdata) | ||
2392 | return -ENOMEM; | ||
2393 | rc = selinux_sb_copy_data(data, secdata); | ||
2394 | if (rc) | ||
2395 | goto out_free_secdata; | ||
2396 | |||
2397 | rc = selinux_parse_opts_str(secdata, &opts); | ||
2398 | if (rc) | ||
2399 | goto out_free_secdata; | ||
2400 | |||
2401 | mount_options = opts.mnt_opts; | ||
2402 | flags = opts.mnt_opts_flags; | ||
2403 | |||
2404 | for (i = 0; i < opts.num_mnt_opts; i++) { | ||
2405 | u32 sid; | ||
2406 | size_t len; | ||
2407 | |||
2408 | if (flags[i] == SE_SBLABELSUPP) | ||
2409 | continue; | ||
2410 | len = strlen(mount_options[i]); | ||
2411 | rc = security_context_to_sid(mount_options[i], len, &sid); | ||
2412 | if (rc) { | ||
2413 | printk(KERN_WARNING "SELinux: security_context_to_sid" | ||
2414 | "(%s) failed for (dev %s, type %s) errno=%d\n", | ||
2415 | mount_options[i], sb->s_id, sb->s_type->name, rc); | ||
2416 | goto out_free_opts; | ||
2417 | } | ||
2418 | rc = -EINVAL; | ||
2419 | switch (flags[i]) { | ||
2420 | case FSCONTEXT_MNT: | ||
2421 | if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) | ||
2422 | goto out_bad_option; | ||
2423 | break; | ||
2424 | case CONTEXT_MNT: | ||
2425 | if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) | ||
2426 | goto out_bad_option; | ||
2427 | break; | ||
2428 | case ROOTCONTEXT_MNT: { | ||
2429 | struct inode_security_struct *root_isec; | ||
2430 | root_isec = sb->s_root->d_inode->i_security; | ||
2431 | |||
2432 | if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) | ||
2433 | goto out_bad_option; | ||
2434 | break; | ||
2435 | } | ||
2436 | case DEFCONTEXT_MNT: | ||
2437 | if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) | ||
2438 | goto out_bad_option; | ||
2439 | break; | ||
2440 | default: | ||
2441 | goto out_free_opts; | ||
2442 | } | ||
2443 | } | ||
2444 | |||
2445 | rc = 0; | ||
2446 | out_free_opts: | ||
2447 | security_free_mnt_opts(&opts); | ||
2448 | out_free_secdata: | ||
2449 | free_secdata(secdata); | ||
2450 | return rc; | ||
2451 | out_bad_option: | ||
2452 | printk(KERN_WARNING "SELinux: unable to change security options " | ||
2453 | "during remount (dev %s, type=%s)\n", sb->s_id, | ||
2454 | sb->s_type->name); | ||
2455 | goto out_free_opts; | ||
2456 | } | ||
2457 | |||
2446 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | 2458 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) |
2447 | { | 2459 | { |
2448 | const struct cred *cred = current_cred(); | 2460 | const struct cred *cred = current_cred(); |
@@ -2509,8 +2521,8 @@ static void selinux_inode_free_security(struct inode *inode) | |||
2509 | } | 2521 | } |
2510 | 2522 | ||
2511 | static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | 2523 | static int selinux_inode_init_security(struct inode *inode, struct inode *dir, |
2512 | char **name, void **value, | 2524 | const struct qstr *qstr, char **name, |
2513 | size_t *len) | 2525 | void **value, size_t *len) |
2514 | { | 2526 | { |
2515 | const struct task_security_struct *tsec = current_security(); | 2527 | const struct task_security_struct *tsec = current_security(); |
2516 | struct inode_security_struct *dsec; | 2528 | struct inode_security_struct *dsec; |
@@ -2531,7 +2543,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2531 | else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | 2543 | else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
2532 | rc = security_transition_sid(sid, dsec->sid, | 2544 | rc = security_transition_sid(sid, dsec->sid, |
2533 | inode_mode_to_security_class(inode->i_mode), | 2545 | inode_mode_to_security_class(inode->i_mode), |
2534 | &newsid); | 2546 | qstr, &newsid); |
2535 | if (rc) { | 2547 | if (rc) { |
2536 | printk(KERN_WARNING "%s: " | 2548 | printk(KERN_WARNING "%s: " |
2537 | "security_transition_sid failed, rc=%d (dev=%s " | 2549 | "security_transition_sid failed, rc=%d (dev=%s " |
@@ -2628,7 +2640,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na | |||
2628 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); | 2640 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); |
2629 | } | 2641 | } |
2630 | 2642 | ||
2631 | static int selinux_inode_permission(struct inode *inode, int mask) | 2643 | static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) |
2632 | { | 2644 | { |
2633 | const struct cred *cred = current_cred(); | 2645 | const struct cred *cred = current_cred(); |
2634 | struct common_audit_data ad; | 2646 | struct common_audit_data ad; |
@@ -2650,7 +2662,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
2650 | 2662 | ||
2651 | perms = file_mask_to_av(inode->i_mode, mask); | 2663 | perms = file_mask_to_av(inode->i_mode, mask); |
2652 | 2664 | ||
2653 | return inode_has_perm(cred, inode, perms, &ad); | 2665 | return inode_has_perm(cred, inode, perms, &ad, flags); |
2654 | } | 2666 | } |
2655 | 2667 | ||
2656 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2668 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
@@ -2718,7 +2730,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2718 | if (!(sbsec->flags & SE_SBLABELSUPP)) | 2730 | if (!(sbsec->flags & SE_SBLABELSUPP)) |
2719 | return -EOPNOTSUPP; | 2731 | return -EOPNOTSUPP; |
2720 | 2732 | ||
2721 | if (!is_owner_or_cap(inode)) | 2733 | if (!inode_owner_or_capable(inode)) |
2722 | return -EPERM; | 2734 | return -EPERM; |
2723 | 2735 | ||
2724 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2736 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
@@ -2829,7 +2841,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name | |||
2829 | * and lack of permission just means that we fall back to the | 2841 | * and lack of permission just means that we fall back to the |
2830 | * in-core context value, not a denial. | 2842 | * in-core context value, not a denial. |
2831 | */ | 2843 | */ |
2832 | error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN, | 2844 | error = selinux_capable(current, current_cred(), |
2845 | &init_user_ns, CAP_MAC_ADMIN, | ||
2833 | SECURITY_CAP_NOAUDIT); | 2846 | SECURITY_CAP_NOAUDIT); |
2834 | if (!error) | 2847 | if (!error) |
2835 | error = security_sid_to_context_force(isec->sid, &context, | 2848 | error = security_sid_to_context_force(isec->sid, &context, |
@@ -2932,16 +2945,47 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
2932 | unsigned long arg) | 2945 | unsigned long arg) |
2933 | { | 2946 | { |
2934 | const struct cred *cred = current_cred(); | 2947 | const struct cred *cred = current_cred(); |
2935 | u32 av = 0; | 2948 | int error = 0; |
2936 | 2949 | ||
2937 | if (_IOC_DIR(cmd) & _IOC_WRITE) | 2950 | switch (cmd) { |
2938 | av |= FILE__WRITE; | 2951 | case FIONREAD: |
2939 | if (_IOC_DIR(cmd) & _IOC_READ) | 2952 | /* fall through */ |
2940 | av |= FILE__READ; | 2953 | case FIBMAP: |
2941 | if (!av) | 2954 | /* fall through */ |
2942 | av = FILE__IOCTL; | 2955 | case FIGETBSZ: |
2956 | /* fall through */ | ||
2957 | case EXT2_IOC_GETFLAGS: | ||
2958 | /* fall through */ | ||
2959 | case EXT2_IOC_GETVERSION: | ||
2960 | error = file_has_perm(cred, file, FILE__GETATTR); | ||
2961 | break; | ||
2962 | |||
2963 | case EXT2_IOC_SETFLAGS: | ||
2964 | /* fall through */ | ||
2965 | case EXT2_IOC_SETVERSION: | ||
2966 | error = file_has_perm(cred, file, FILE__SETATTR); | ||
2967 | break; | ||
2968 | |||
2969 | /* sys_ioctl() checks */ | ||
2970 | case FIONBIO: | ||
2971 | /* fall through */ | ||
2972 | case FIOASYNC: | ||
2973 | error = file_has_perm(cred, file, 0); | ||
2974 | break; | ||
2943 | 2975 | ||
2944 | return file_has_perm(cred, file, av); | 2976 | case KDSKBENT: |
2977 | case KDSKBSENT: | ||
2978 | error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG, | ||
2979 | SECURITY_CAP_AUDIT); | ||
2980 | break; | ||
2981 | |||
2982 | /* default case assumes that the command will go | ||
2983 | * to the file's ioctl() function. | ||
2984 | */ | ||
2985 | default: | ||
2986 | error = file_has_perm(cred, file, FILE__IOCTL); | ||
2987 | } | ||
2988 | return error; | ||
2945 | } | 2989 | } |
2946 | 2990 | ||
2947 | static int default_noexec; | 2991 | static int default_noexec; |
@@ -3166,7 +3210,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) | |||
3166 | * new inode label or new policy. | 3210 | * new inode label or new policy. |
3167 | * This check is not redundant - do not remove. | 3211 | * This check is not redundant - do not remove. |
3168 | */ | 3212 | */ |
3169 | return inode_has_perm(cred, inode, open_file_to_av(file), NULL); | 3213 | return inode_has_perm(cred, inode, open_file_to_av(file), NULL, 0); |
3170 | } | 3214 | } |
3171 | 3215 | ||
3172 | /* task security operations */ | 3216 | /* task security operations */ |
@@ -3644,9 +3688,16 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) | |||
3644 | 3688 | ||
3645 | /* socket security operations */ | 3689 | /* socket security operations */ |
3646 | 3690 | ||
3647 | static u32 socket_sockcreate_sid(const struct task_security_struct *tsec) | 3691 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, |
3692 | u16 secclass, u32 *socksid) | ||
3648 | { | 3693 | { |
3649 | return tsec->sockcreate_sid ? : tsec->sid; | 3694 | if (tsec->sockcreate_sid > SECSID_NULL) { |
3695 | *socksid = tsec->sockcreate_sid; | ||
3696 | return 0; | ||
3697 | } | ||
3698 | |||
3699 | return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL, | ||
3700 | socksid); | ||
3650 | } | 3701 | } |
3651 | 3702 | ||
3652 | static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) | 3703 | static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) |
@@ -3670,12 +3721,16 @@ static int selinux_socket_create(int family, int type, | |||
3670 | const struct task_security_struct *tsec = current_security(); | 3721 | const struct task_security_struct *tsec = current_security(); |
3671 | u32 newsid; | 3722 | u32 newsid; |
3672 | u16 secclass; | 3723 | u16 secclass; |
3724 | int rc; | ||
3673 | 3725 | ||
3674 | if (kern) | 3726 | if (kern) |
3675 | return 0; | 3727 | return 0; |
3676 | 3728 | ||
3677 | newsid = socket_sockcreate_sid(tsec); | ||
3678 | secclass = socket_type_to_security_class(family, type, protocol); | 3729 | secclass = socket_type_to_security_class(family, type, protocol); |
3730 | rc = socket_sockcreate_sid(tsec, secclass, &newsid); | ||
3731 | if (rc) | ||
3732 | return rc; | ||
3733 | |||
3679 | return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); | 3734 | return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); |
3680 | } | 3735 | } |
3681 | 3736 | ||
@@ -3687,12 +3742,16 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
3687 | struct sk_security_struct *sksec; | 3742 | struct sk_security_struct *sksec; |
3688 | int err = 0; | 3743 | int err = 0; |
3689 | 3744 | ||
3745 | isec->sclass = socket_type_to_security_class(family, type, protocol); | ||
3746 | |||
3690 | if (kern) | 3747 | if (kern) |
3691 | isec->sid = SECINITSID_KERNEL; | 3748 | isec->sid = SECINITSID_KERNEL; |
3692 | else | 3749 | else { |
3693 | isec->sid = socket_sockcreate_sid(tsec); | 3750 | err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid)); |
3751 | if (err) | ||
3752 | return err; | ||
3753 | } | ||
3694 | 3754 | ||
3695 | isec->sclass = socket_type_to_security_class(family, type, protocol); | ||
3696 | isec->initialized = 1; | 3755 | isec->initialized = 1; |
3697 | 3756 | ||
3698 | if (sock->sk) { | 3757 | if (sock->sk) { |
@@ -4002,7 +4061,6 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4002 | { | 4061 | { |
4003 | int err = 0; | 4062 | int err = 0; |
4004 | struct sk_security_struct *sksec = sk->sk_security; | 4063 | struct sk_security_struct *sksec = sk->sk_security; |
4005 | u32 peer_sid; | ||
4006 | u32 sk_sid = sksec->sid; | 4064 | u32 sk_sid = sksec->sid; |
4007 | struct common_audit_data ad; | 4065 | struct common_audit_data ad; |
4008 | char *addrp; | 4066 | char *addrp; |
@@ -4021,20 +4079,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4021 | return err; | 4079 | return err; |
4022 | } | 4080 | } |
4023 | 4081 | ||
4024 | if (selinux_policycap_netpeer) { | 4082 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); |
4025 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4083 | if (err) |
4026 | if (err) | 4084 | return err; |
4027 | return err; | 4085 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); |
4028 | err = avc_has_perm(sk_sid, peer_sid, | ||
4029 | SECCLASS_PEER, PEER__RECV, &ad); | ||
4030 | if (err) | ||
4031 | selinux_netlbl_err(skb, err, 0); | ||
4032 | } else { | ||
4033 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); | ||
4034 | if (err) | ||
4035 | return err; | ||
4036 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); | ||
4037 | } | ||
4038 | 4086 | ||
4039 | return err; | 4087 | return err; |
4040 | } | 4088 | } |
@@ -4306,7 +4354,7 @@ static void selinux_secmark_refcount_dec(void) | |||
4306 | static void selinux_req_classify_flow(const struct request_sock *req, | 4354 | static void selinux_req_classify_flow(const struct request_sock *req, |
4307 | struct flowi *fl) | 4355 | struct flowi *fl) |
4308 | { | 4356 | { |
4309 | fl->secid = req->secid; | 4357 | fl->flowi_secid = req->secid; |
4310 | } | 4358 | } |
4311 | 4359 | ||
4312 | static int selinux_tun_dev_create(void) | 4360 | static int selinux_tun_dev_create(void) |
@@ -4529,9 +4577,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4529 | SECCLASS_PACKET, PACKET__SEND, &ad)) | 4577 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
4530 | return NF_DROP_ERR(-ECONNREFUSED); | 4578 | return NF_DROP_ERR(-ECONNREFUSED); |
4531 | 4579 | ||
4532 | if (selinux_policycap_netpeer) | 4580 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
4533 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) | 4581 | return NF_DROP_ERR(-ECONNREFUSED); |
4534 | return NF_DROP_ERR(-ECONNREFUSED); | ||
4535 | 4582 | ||
4536 | return NF_ACCEPT; | 4583 | return NF_ACCEPT; |
4537 | } | 4584 | } |
@@ -4574,27 +4621,14 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4574 | * from the sending socket, otherwise use the kernel's sid */ | 4621 | * from the sending socket, otherwise use the kernel's sid */ |
4575 | sk = skb->sk; | 4622 | sk = skb->sk; |
4576 | if (sk == NULL) { | 4623 | if (sk == NULL) { |
4577 | switch (family) { | 4624 | if (skb->skb_iif) { |
4578 | case PF_INET: | 4625 | secmark_perm = PACKET__FORWARD_OUT; |
4579 | if (IPCB(skb)->flags & IPSKB_FORWARDED) | ||
4580 | secmark_perm = PACKET__FORWARD_OUT; | ||
4581 | else | ||
4582 | secmark_perm = PACKET__SEND; | ||
4583 | break; | ||
4584 | case PF_INET6: | ||
4585 | if (IP6CB(skb)->flags & IP6SKB_FORWARDED) | ||
4586 | secmark_perm = PACKET__FORWARD_OUT; | ||
4587 | else | ||
4588 | secmark_perm = PACKET__SEND; | ||
4589 | break; | ||
4590 | default: | ||
4591 | return NF_DROP_ERR(-ECONNREFUSED); | ||
4592 | } | ||
4593 | if (secmark_perm == PACKET__FORWARD_OUT) { | ||
4594 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | 4626 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) |
4595 | return NF_DROP; | 4627 | return NF_DROP; |
4596 | } else | 4628 | } else { |
4629 | secmark_perm = PACKET__SEND; | ||
4597 | peer_sid = SECINITSID_KERNEL; | 4630 | peer_sid = SECINITSID_KERNEL; |
4631 | } | ||
4598 | } else { | 4632 | } else { |
4599 | struct sk_security_struct *sksec = sk->sk_security; | 4633 | struct sk_security_struct *sksec = sk->sk_security; |
4600 | peer_sid = sksec->sid; | 4634 | peer_sid = sksec->sid; |
@@ -4669,6 +4703,7 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability) | |||
4669 | { | 4703 | { |
4670 | int err; | 4704 | int err; |
4671 | struct common_audit_data ad; | 4705 | struct common_audit_data ad; |
4706 | u32 sid; | ||
4672 | 4707 | ||
4673 | err = cap_netlink_recv(skb, capability); | 4708 | err = cap_netlink_recv(skb, capability); |
4674 | if (err) | 4709 | if (err) |
@@ -4677,8 +4712,9 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability) | |||
4677 | COMMON_AUDIT_DATA_INIT(&ad, CAP); | 4712 | COMMON_AUDIT_DATA_INIT(&ad, CAP); |
4678 | ad.u.cap = capability; | 4713 | ad.u.cap = capability; |
4679 | 4714 | ||
4680 | return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, | 4715 | security_task_getsecid(current, &sid); |
4681 | SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad); | 4716 | return avc_has_perm(sid, sid, SECCLASS_CAPABILITY, |
4717 | CAP_TO_MASK(capability), &ad); | ||
4682 | } | 4718 | } |
4683 | 4719 | ||
4684 | static int ipc_alloc_security(struct task_struct *task, | 4720 | static int ipc_alloc_security(struct task_struct *task, |
@@ -4848,7 +4884,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
4848 | * message queue this message will be stored in | 4884 | * message queue this message will be stored in |
4849 | */ | 4885 | */ |
4850 | rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, | 4886 | rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, |
4851 | &msec->sid); | 4887 | NULL, &msec->sid); |
4852 | if (rc) | 4888 | if (rc) |
4853 | return rc; | 4889 | return rc; |
4854 | } | 4890 | } |
@@ -5402,7 +5438,6 @@ static struct security_operations selinux_ops = { | |||
5402 | .ptrace_traceme = selinux_ptrace_traceme, | 5438 | .ptrace_traceme = selinux_ptrace_traceme, |
5403 | .capget = selinux_capget, | 5439 | .capget = selinux_capget, |
5404 | .capset = selinux_capset, | 5440 | .capset = selinux_capset, |
5405 | .sysctl = selinux_sysctl, | ||
5406 | .capable = selinux_capable, | 5441 | .capable = selinux_capable, |
5407 | .quotactl = selinux_quotactl, | 5442 | .quotactl = selinux_quotactl, |
5408 | .quota_on = selinux_quota_on, | 5443 | .quota_on = selinux_quota_on, |
@@ -5420,6 +5455,7 @@ static struct security_operations selinux_ops = { | |||
5420 | .sb_alloc_security = selinux_sb_alloc_security, | 5455 | .sb_alloc_security = selinux_sb_alloc_security, |
5421 | .sb_free_security = selinux_sb_free_security, | 5456 | .sb_free_security = selinux_sb_free_security, |
5422 | .sb_copy_data = selinux_sb_copy_data, | 5457 | .sb_copy_data = selinux_sb_copy_data, |
5458 | .sb_remount = selinux_sb_remount, | ||
5423 | .sb_kern_mount = selinux_sb_kern_mount, | 5459 | .sb_kern_mount = selinux_sb_kern_mount, |
5424 | .sb_show_options = selinux_sb_show_options, | 5460 | .sb_show_options = selinux_sb_show_options, |
5425 | .sb_statfs = selinux_sb_statfs, | 5461 | .sb_statfs = selinux_sb_statfs, |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 5615081b73ec..e77b2ac2908b 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -54,11 +54,11 @@ struct avc_cache_stats { | |||
54 | 54 | ||
55 | void __init avc_init(void); | 55 | void __init avc_init(void); |
56 | 56 | ||
57 | void avc_audit(u32 ssid, u32 tsid, | 57 | int avc_audit(u32 ssid, u32 tsid, |
58 | u16 tclass, u32 requested, | 58 | u16 tclass, u32 requested, |
59 | struct av_decision *avd, | 59 | struct av_decision *avd, |
60 | int result, | 60 | int result, |
61 | struct common_audit_data *a); | 61 | struct common_audit_data *a, unsigned flags); |
62 | 62 | ||
63 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 63 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
64 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 64 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
@@ -66,9 +66,17 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
66 | unsigned flags, | 66 | unsigned flags, |
67 | struct av_decision *avd); | 67 | struct av_decision *avd); |
68 | 68 | ||
69 | int avc_has_perm(u32 ssid, u32 tsid, | 69 | int avc_has_perm_flags(u32 ssid, u32 tsid, |
70 | u16 tclass, u32 requested, | 70 | u16 tclass, u32 requested, |
71 | struct common_audit_data *auditdata); | 71 | struct common_audit_data *auditdata, |
72 | unsigned); | ||
73 | |||
74 | static inline int avc_has_perm(u32 ssid, u32 tsid, | ||
75 | u16 tclass, u32 requested, | ||
76 | struct common_audit_data *auditdata) | ||
77 | { | ||
78 | return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0); | ||
79 | } | ||
72 | 80 | ||
73 | u32 avc_policy_seqno(void); | 81 | u32 avc_policy_seqno(void); |
74 | 82 | ||
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 7ed3663332ec..b8c53723e09b 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h | |||
@@ -12,6 +12,10 @@ | |||
12 | #define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \ | 12 | #define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \ |
13 | "write", "associate", "unix_read", "unix_write" | 13 | "write", "associate", "unix_read", "unix_write" |
14 | 14 | ||
15 | /* | ||
16 | * Note: The name for any socket class should be suffixed by "socket", | ||
17 | * and doesn't contain more than one substr of "socket". | ||
18 | */ | ||
15 | struct security_class_mapping secclass_map[] = { | 19 | struct security_class_mapping secclass_map[] = { |
16 | { "security", | 20 | { "security", |
17 | { "compute_av", "compute_create", "compute_member", | 21 | { "compute_av", "compute_create", "compute_member", |
@@ -132,8 +136,7 @@ struct security_class_mapping secclass_map[] = { | |||
132 | { "appletalk_socket", | 136 | { "appletalk_socket", |
133 | { COMMON_SOCK_PERMS, NULL } }, | 137 | { COMMON_SOCK_PERMS, NULL } }, |
134 | { "packet", | 138 | { "packet", |
135 | { "send", "recv", "relabelto", "flow_in", "flow_out", | 139 | { "send", "recv", "relabelto", "forward_in", "forward_out", NULL } }, |
136 | "forward_in", "forward_out", NULL } }, | ||
137 | { "key", | 140 | { "key", |
138 | { "view", "read", "write", "search", "link", "setattr", "create", | 141 | { "view", "read", "write", "search", "link", "setattr", "create", |
139 | NULL } }, | 142 | NULL } }, |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 671273eb1115..348eb00cb668 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -8,6 +8,7 @@ | |||
8 | #ifndef _SELINUX_SECURITY_H_ | 8 | #ifndef _SELINUX_SECURITY_H_ |
9 | #define _SELINUX_SECURITY_H_ | 9 | #define _SELINUX_SECURITY_H_ |
10 | 10 | ||
11 | #include <linux/dcache.h> | ||
11 | #include <linux/magic.h> | 12 | #include <linux/magic.h> |
12 | #include <linux/types.h> | 13 | #include <linux/types.h> |
13 | #include "flask.h" | 14 | #include "flask.h" |
@@ -28,13 +29,14 @@ | |||
28 | #define POLICYDB_VERSION_POLCAP 22 | 29 | #define POLICYDB_VERSION_POLCAP 22 |
29 | #define POLICYDB_VERSION_PERMISSIVE 23 | 30 | #define POLICYDB_VERSION_PERMISSIVE 23 |
30 | #define POLICYDB_VERSION_BOUNDARY 24 | 31 | #define POLICYDB_VERSION_BOUNDARY 24 |
32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 | ||
31 | 33 | ||
32 | /* Range of policy versions we understand*/ | 34 | /* Range of policy versions we understand*/ |
33 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 35 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
34 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 36 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
35 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 37 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
36 | #else | 38 | #else |
37 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY | 39 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_FILENAME_TRANS |
38 | #endif | 40 | #endif |
39 | 41 | ||
40 | /* Mask for just the mount related flags */ | 42 | /* Mask for just the mount related flags */ |
@@ -106,8 +108,8 @@ void security_compute_av(u32 ssid, u32 tsid, | |||
106 | void security_compute_av_user(u32 ssid, u32 tsid, | 108 | void security_compute_av_user(u32 ssid, u32 tsid, |
107 | u16 tclass, struct av_decision *avd); | 109 | u16 tclass, struct av_decision *avd); |
108 | 110 | ||
109 | int security_transition_sid(u32 ssid, u32 tsid, | 111 | int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, |
110 | u16 tclass, u32 *out_sid); | 112 | const struct qstr *qstr, u32 *out_sid); |
111 | 113 | ||
112 | int security_transition_sid_user(u32 ssid, u32 tsid, | 114 | int security_transition_sid_user(u32 ssid, u32 tsid, |
113 | u16 tclass, u32 *out_sid); | 115 | u16 tclass, u32 *out_sid); |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 13128f9a3e5a..b43813c9e049 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
@@ -19,7 +19,7 @@ void selinux_xfrm_state_free(struct xfrm_state *x); | |||
19 | int selinux_xfrm_state_delete(struct xfrm_state *x); | 19 | int selinux_xfrm_state_delete(struct xfrm_state *x); |
20 | int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); | 20 | int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); |
21 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, | 21 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, |
22 | struct xfrm_policy *xp, struct flowi *fl); | 22 | struct xfrm_policy *xp, const struct flowi *fl); |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Extract the security blob from the sock (it's actually on the socket) | 25 | * Extract the security blob from the sock (it's actually on the socket) |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 1c2fc46544bf..c3bf3ed07b06 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
@@ -151,7 +151,7 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec) | |||
151 | * | 151 | * |
152 | * Description: | 152 | * Description: |
153 | * Called when the NetLabel state of a sk_security_struct needs to be reset. | 153 | * Called when the NetLabel state of a sk_security_struct needs to be reset. |
154 | * The caller is responsibile for all the NetLabel sk_security_struct locking. | 154 | * The caller is responsible for all the NetLabel sk_security_struct locking. |
155 | * | 155 | * |
156 | */ | 156 | */ |
157 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec) | 157 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec) |
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index dff0c75345c1..63ce2f9e441d 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h | |||
@@ -14,7 +14,7 @@ | |||
14 | * | 14 | * |
15 | * Copyright (C) 2003 Tresys Technology, LLC | 15 | * Copyright (C) 2003 Tresys Technology, LLC |
16 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License as published by | 17 | * it under the terms of the GNU General Public License as published by |
18 | * the Free Software Foundation, version 2. | 18 | * the Free Software Foundation, version 2. |
19 | * | 19 | * |
20 | * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> | 20 | * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> |
@@ -27,16 +27,16 @@ struct avtab_key { | |||
27 | u16 source_type; /* source type */ | 27 | u16 source_type; /* source type */ |
28 | u16 target_type; /* target type */ | 28 | u16 target_type; /* target type */ |
29 | u16 target_class; /* target object class */ | 29 | u16 target_class; /* target object class */ |
30 | #define AVTAB_ALLOWED 1 | 30 | #define AVTAB_ALLOWED 0x0001 |
31 | #define AVTAB_AUDITALLOW 2 | 31 | #define AVTAB_AUDITALLOW 0x0002 |
32 | #define AVTAB_AUDITDENY 4 | 32 | #define AVTAB_AUDITDENY 0x0004 |
33 | #define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) | 33 | #define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY) |
34 | #define AVTAB_TRANSITION 16 | 34 | #define AVTAB_TRANSITION 0x0010 |
35 | #define AVTAB_MEMBER 32 | 35 | #define AVTAB_MEMBER 0x0020 |
36 | #define AVTAB_CHANGE 64 | 36 | #define AVTAB_CHANGE 0x0040 |
37 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) | 37 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) |
38 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ | 38 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ |
39 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ | 39 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ |
40 | u16 specified; /* what field is specified */ | 40 | u16 specified; /* what field is specified */ |
41 | }; | 41 | }; |
42 | 42 | ||
@@ -86,7 +86,6 @@ void avtab_cache_destroy(void); | |||
86 | 86 | ||
87 | #define MAX_AVTAB_HASH_BITS 11 | 87 | #define MAX_AVTAB_HASH_BITS 11 |
88 | #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) | 88 | #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) |
89 | #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) | ||
90 | 89 | ||
91 | #endif /* _SS_AVTAB_H_ */ | 90 | #endif /* _SS_AVTAB_H_ */ |
92 | 91 | ||
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 1f4e93c2ae86..922f8afa89dd 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
@@ -36,7 +36,6 @@ struct ebitmap { | |||
36 | }; | 36 | }; |
37 | 37 | ||
38 | #define ebitmap_length(e) ((e)->highbit) | 38 | #define ebitmap_length(e) ((e)->highbit) |
39 | #define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0) | ||
40 | 39 | ||
41 | static inline unsigned int ebitmap_start_positive(struct ebitmap *e, | 40 | static inline unsigned int ebitmap_start_positive(struct ebitmap *e, |
42 | struct ebitmap_node **n) | 41 | struct ebitmap_node **n) |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 1ef8e4e89880..e96174216bc9 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -512,7 +512,8 @@ int mls_compute_sid(struct context *scontext, | |||
512 | struct context *tcontext, | 512 | struct context *tcontext, |
513 | u16 tclass, | 513 | u16 tclass, |
514 | u32 specified, | 514 | u32 specified, |
515 | struct context *newcontext) | 515 | struct context *newcontext, |
516 | bool sock) | ||
516 | { | 517 | { |
517 | struct range_trans rtr; | 518 | struct range_trans rtr; |
518 | struct mls_range *r; | 519 | struct mls_range *r; |
@@ -531,7 +532,7 @@ int mls_compute_sid(struct context *scontext, | |||
531 | return mls_range_set(newcontext, r); | 532 | return mls_range_set(newcontext, r); |
532 | /* Fallthrough */ | 533 | /* Fallthrough */ |
533 | case AVTAB_CHANGE: | 534 | case AVTAB_CHANGE: |
534 | if (tclass == policydb.process_class) | 535 | if ((tclass == policydb.process_class) || (sock == true)) |
535 | /* Use the process MLS attributes. */ | 536 | /* Use the process MLS attributes. */ |
536 | return mls_context_cpy(newcontext, scontext); | 537 | return mls_context_cpy(newcontext, scontext); |
537 | else | 538 | else |
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index cd9152632e54..037bf9d82d41 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h | |||
@@ -49,7 +49,8 @@ int mls_compute_sid(struct context *scontext, | |||
49 | struct context *tcontext, | 49 | struct context *tcontext, |
50 | u16 tclass, | 50 | u16 tclass, |
51 | u32 specified, | 51 | u32 specified, |
52 | struct context *newcontext); | 52 | struct context *newcontext, |
53 | bool sock); | ||
53 | 54 | ||
54 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, | 55 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, |
55 | struct context *usercon); | 56 | struct context *usercon); |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 57363562f0f8..e6e7ce0d3d55 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -123,6 +123,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
123 | .sym_num = SYM_NUM, | 123 | .sym_num = SYM_NUM, |
124 | .ocon_num = OCON_NUM, | 124 | .ocon_num = OCON_NUM, |
125 | }, | 125 | }, |
126 | { | ||
127 | .version = POLICYDB_VERSION_FILENAME_TRANS, | ||
128 | .sym_num = SYM_NUM, | ||
129 | .ocon_num = OCON_NUM, | ||
130 | }, | ||
126 | }; | 131 | }; |
127 | 132 | ||
128 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 133 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
@@ -497,7 +502,7 @@ static int policydb_index(struct policydb *p) | |||
497 | goto out; | 502 | goto out; |
498 | 503 | ||
499 | rc = flex_array_prealloc(p->type_val_to_struct_array, 0, | 504 | rc = flex_array_prealloc(p->type_val_to_struct_array, 0, |
500 | p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO); | 505 | p->p_types.nprim, GFP_KERNEL | __GFP_ZERO); |
501 | if (rc) | 506 | if (rc) |
502 | goto out; | 507 | goto out; |
503 | 508 | ||
@@ -514,7 +519,7 @@ static int policydb_index(struct policydb *p) | |||
514 | goto out; | 519 | goto out; |
515 | 520 | ||
516 | rc = flex_array_prealloc(p->sym_val_to_name[i], | 521 | rc = flex_array_prealloc(p->sym_val_to_name[i], |
517 | 0, p->symtab[i].nprim - 1, | 522 | 0, p->symtab[i].nprim, |
518 | GFP_KERNEL | __GFP_ZERO); | 523 | GFP_KERNEL | __GFP_ZERO); |
519 | if (rc) | 524 | if (rc) |
520 | goto out; | 525 | goto out; |
@@ -704,6 +709,7 @@ void policydb_destroy(struct policydb *p) | |||
704 | int i; | 709 | int i; |
705 | struct role_allow *ra, *lra = NULL; | 710 | struct role_allow *ra, *lra = NULL; |
706 | struct role_trans *tr, *ltr = NULL; | 711 | struct role_trans *tr, *ltr = NULL; |
712 | struct filename_trans *ft, *nft; | ||
707 | 713 | ||
708 | for (i = 0; i < SYM_NUM; i++) { | 714 | for (i = 0; i < SYM_NUM; i++) { |
709 | cond_resched(); | 715 | cond_resched(); |
@@ -781,6 +787,15 @@ void policydb_destroy(struct policydb *p) | |||
781 | } | 787 | } |
782 | flex_array_free(p->type_attr_map_array); | 788 | flex_array_free(p->type_attr_map_array); |
783 | } | 789 | } |
790 | |||
791 | ft = p->filename_trans; | ||
792 | while (ft) { | ||
793 | nft = ft->next; | ||
794 | kfree(ft->name); | ||
795 | kfree(ft); | ||
796 | ft = nft; | ||
797 | } | ||
798 | |||
784 | ebitmap_destroy(&p->policycaps); | 799 | ebitmap_destroy(&p->policycaps); |
785 | ebitmap_destroy(&p->permissive_map); | 800 | ebitmap_destroy(&p->permissive_map); |
786 | 801 | ||
@@ -1788,6 +1803,76 @@ out: | |||
1788 | return rc; | 1803 | return rc; |
1789 | } | 1804 | } |
1790 | 1805 | ||
1806 | static int filename_trans_read(struct policydb *p, void *fp) | ||
1807 | { | ||
1808 | struct filename_trans *ft, *last; | ||
1809 | u32 nel, len; | ||
1810 | char *name; | ||
1811 | __le32 buf[4]; | ||
1812 | int rc, i; | ||
1813 | |||
1814 | if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) | ||
1815 | return 0; | ||
1816 | |||
1817 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1818 | if (rc) | ||
1819 | goto out; | ||
1820 | nel = le32_to_cpu(buf[0]); | ||
1821 | |||
1822 | printk(KERN_ERR "%s: nel=%d\n", __func__, nel); | ||
1823 | |||
1824 | last = p->filename_trans; | ||
1825 | while (last && last->next) | ||
1826 | last = last->next; | ||
1827 | |||
1828 | for (i = 0; i < nel; i++) { | ||
1829 | rc = -ENOMEM; | ||
1830 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); | ||
1831 | if (!ft) | ||
1832 | goto out; | ||
1833 | |||
1834 | /* add it to the tail of the list */ | ||
1835 | if (!last) | ||
1836 | p->filename_trans = ft; | ||
1837 | else | ||
1838 | last->next = ft; | ||
1839 | last = ft; | ||
1840 | |||
1841 | /* length of the path component string */ | ||
1842 | rc = next_entry(buf, fp, sizeof(u32)); | ||
1843 | if (rc) | ||
1844 | goto out; | ||
1845 | len = le32_to_cpu(buf[0]); | ||
1846 | |||
1847 | rc = -ENOMEM; | ||
1848 | name = kmalloc(len + 1, GFP_KERNEL); | ||
1849 | if (!name) | ||
1850 | goto out; | ||
1851 | |||
1852 | ft->name = name; | ||
1853 | |||
1854 | /* path component string */ | ||
1855 | rc = next_entry(name, fp, len); | ||
1856 | if (rc) | ||
1857 | goto out; | ||
1858 | name[len] = 0; | ||
1859 | |||
1860 | printk(KERN_ERR "%s: ft=%p ft->name=%p ft->name=%s\n", __func__, ft, ft->name, ft->name); | ||
1861 | |||
1862 | rc = next_entry(buf, fp, sizeof(u32) * 4); | ||
1863 | if (rc) | ||
1864 | goto out; | ||
1865 | |||
1866 | ft->stype = le32_to_cpu(buf[0]); | ||
1867 | ft->ttype = le32_to_cpu(buf[1]); | ||
1868 | ft->tclass = le32_to_cpu(buf[2]); | ||
1869 | ft->otype = le32_to_cpu(buf[3]); | ||
1870 | } | ||
1871 | rc = 0; | ||
1872 | out: | ||
1873 | return rc; | ||
1874 | } | ||
1875 | |||
1791 | static int genfs_read(struct policydb *p, void *fp) | 1876 | static int genfs_read(struct policydb *p, void *fp) |
1792 | { | 1877 | { |
1793 | int i, j, rc; | 1878 | int i, j, rc; |
@@ -2251,6 +2336,10 @@ int policydb_read(struct policydb *p, void *fp) | |||
2251 | lra = ra; | 2336 | lra = ra; |
2252 | } | 2337 | } |
2253 | 2338 | ||
2339 | rc = filename_trans_read(p, fp); | ||
2340 | if (rc) | ||
2341 | goto bad; | ||
2342 | |||
2254 | rc = policydb_index(p); | 2343 | rc = policydb_index(p); |
2255 | if (rc) | 2344 | if (rc) |
2256 | goto bad; | 2345 | goto bad; |
@@ -2286,7 +2375,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
2286 | goto bad; | 2375 | goto bad; |
2287 | 2376 | ||
2288 | /* preallocate so we don't have to worry about the put ever failing */ | 2377 | /* preallocate so we don't have to worry about the put ever failing */ |
2289 | rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1, | 2378 | rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim, |
2290 | GFP_KERNEL | __GFP_ZERO); | 2379 | GFP_KERNEL | __GFP_ZERO); |
2291 | if (rc) | 2380 | if (rc) |
2292 | goto bad; | 2381 | goto bad; |
@@ -3025,6 +3114,43 @@ static int range_write(struct policydb *p, void *fp) | |||
3025 | return 0; | 3114 | return 0; |
3026 | } | 3115 | } |
3027 | 3116 | ||
3117 | static int filename_trans_write(struct policydb *p, void *fp) | ||
3118 | { | ||
3119 | struct filename_trans *ft; | ||
3120 | u32 len, nel = 0; | ||
3121 | __le32 buf[4]; | ||
3122 | int rc; | ||
3123 | |||
3124 | for (ft = p->filename_trans; ft; ft = ft->next) | ||
3125 | nel++; | ||
3126 | |||
3127 | buf[0] = cpu_to_le32(nel); | ||
3128 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3129 | if (rc) | ||
3130 | return rc; | ||
3131 | |||
3132 | for (ft = p->filename_trans; ft; ft = ft->next) { | ||
3133 | len = strlen(ft->name); | ||
3134 | buf[0] = cpu_to_le32(len); | ||
3135 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3136 | if (rc) | ||
3137 | return rc; | ||
3138 | |||
3139 | rc = put_entry(ft->name, sizeof(char), len, fp); | ||
3140 | if (rc) | ||
3141 | return rc; | ||
3142 | |||
3143 | buf[0] = ft->stype; | ||
3144 | buf[1] = ft->ttype; | ||
3145 | buf[2] = ft->tclass; | ||
3146 | buf[3] = ft->otype; | ||
3147 | |||
3148 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
3149 | if (rc) | ||
3150 | return rc; | ||
3151 | } | ||
3152 | return 0; | ||
3153 | } | ||
3028 | /* | 3154 | /* |
3029 | * Write the configuration data in a policy database | 3155 | * Write the configuration data in a policy database |
3030 | * structure to a policy database binary representation | 3156 | * structure to a policy database binary representation |
@@ -3135,6 +3261,10 @@ int policydb_write(struct policydb *p, void *fp) | |||
3135 | if (rc) | 3261 | if (rc) |
3136 | return rc; | 3262 | return rc; |
3137 | 3263 | ||
3264 | rc = filename_trans_write(p, fp); | ||
3265 | if (rc) | ||
3266 | return rc; | ||
3267 | |||
3138 | rc = ocontext_write(p, info, fp); | 3268 | rc = ocontext_write(p, info, fp); |
3139 | if (rc) | 3269 | if (rc) |
3140 | return rc; | 3270 | return rc; |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 4e3ab9d0b315..732ea4a68682 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -77,6 +77,15 @@ struct role_trans { | |||
77 | struct role_trans *next; | 77 | struct role_trans *next; |
78 | }; | 78 | }; |
79 | 79 | ||
80 | struct filename_trans { | ||
81 | struct filename_trans *next; | ||
82 | u32 stype; /* current process */ | ||
83 | u32 ttype; /* parent dir context */ | ||
84 | u16 tclass; /* class of new object */ | ||
85 | const char *name; /* last path component */ | ||
86 | u32 otype; /* expected of new object */ | ||
87 | }; | ||
88 | |||
80 | struct role_allow { | 89 | struct role_allow { |
81 | u32 role; /* current role */ | 90 | u32 role; /* current role */ |
82 | u32 new_role; /* new role */ | 91 | u32 new_role; /* new role */ |
@@ -217,6 +226,9 @@ struct policydb { | |||
217 | /* role transitions */ | 226 | /* role transitions */ |
218 | struct role_trans *role_tr; | 227 | struct role_trans *role_tr; |
219 | 228 | ||
229 | /* file transitions with the last path component */ | ||
230 | struct filename_trans *filename_trans; | ||
231 | |||
220 | /* bools indexed by (value - 1) */ | 232 | /* bools indexed by (value - 1) */ |
221 | struct cond_bool_datum **bool_val_to_struct; | 233 | struct cond_bool_datum **bool_val_to_struct; |
222 | /* type enforcement conditional access vectors and transitions */ | 234 | /* type enforcement conditional access vectors and transitions */ |
@@ -302,7 +314,7 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes) | |||
302 | return 0; | 314 | return 0; |
303 | } | 315 | } |
304 | 316 | ||
305 | static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp) | 317 | static inline int put_entry(const void *buf, size_t bytes, int num, struct policy_file *fp) |
306 | { | 318 | { |
307 | size_t len = bytes * num; | 319 | size_t len = bytes * num; |
308 | 320 | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index a03cfaf0ee07..6ef4af47dac4 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -201,6 +201,21 @@ static u16 unmap_class(u16 tclass) | |||
201 | return tclass; | 201 | return tclass; |
202 | } | 202 | } |
203 | 203 | ||
204 | /* | ||
205 | * Get kernel value for class from its policy value | ||
206 | */ | ||
207 | static u16 map_class(u16 pol_value) | ||
208 | { | ||
209 | u16 i; | ||
210 | |||
211 | for (i = 1; i < current_mapping_size; i++) { | ||
212 | if (current_mapping[i].value == pol_value) | ||
213 | return i; | ||
214 | } | ||
215 | |||
216 | return SECCLASS_NULL; | ||
217 | } | ||
218 | |||
204 | static void map_decision(u16 tclass, struct av_decision *avd, | 219 | static void map_decision(u16 tclass, struct av_decision *avd, |
205 | int allow_unknown) | 220 | int allow_unknown) |
206 | { | 221 | { |
@@ -1343,10 +1358,27 @@ out: | |||
1343 | return -EACCES; | 1358 | return -EACCES; |
1344 | } | 1359 | } |
1345 | 1360 | ||
1361 | static void filename_compute_type(struct policydb *p, struct context *newcontext, | ||
1362 | u32 scon, u32 tcon, u16 tclass, | ||
1363 | const struct qstr *qstr) | ||
1364 | { | ||
1365 | struct filename_trans *ft; | ||
1366 | for (ft = p->filename_trans; ft; ft = ft->next) { | ||
1367 | if (ft->stype == scon && | ||
1368 | ft->ttype == tcon && | ||
1369 | ft->tclass == tclass && | ||
1370 | !strcmp(ft->name, qstr->name)) { | ||
1371 | newcontext->type = ft->otype; | ||
1372 | return; | ||
1373 | } | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1346 | static int security_compute_sid(u32 ssid, | 1377 | static int security_compute_sid(u32 ssid, |
1347 | u32 tsid, | 1378 | u32 tsid, |
1348 | u16 orig_tclass, | 1379 | u16 orig_tclass, |
1349 | u32 specified, | 1380 | u32 specified, |
1381 | const struct qstr *qstr, | ||
1350 | u32 *out_sid, | 1382 | u32 *out_sid, |
1351 | bool kern) | 1383 | bool kern) |
1352 | { | 1384 | { |
@@ -1357,6 +1389,7 @@ static int security_compute_sid(u32 ssid, | |||
1357 | struct avtab_node *node; | 1389 | struct avtab_node *node; |
1358 | u16 tclass; | 1390 | u16 tclass; |
1359 | int rc = 0; | 1391 | int rc = 0; |
1392 | bool sock; | ||
1360 | 1393 | ||
1361 | if (!ss_initialized) { | 1394 | if (!ss_initialized) { |
1362 | switch (orig_tclass) { | 1395 | switch (orig_tclass) { |
@@ -1374,10 +1407,13 @@ static int security_compute_sid(u32 ssid, | |||
1374 | 1407 | ||
1375 | read_lock(&policy_rwlock); | 1408 | read_lock(&policy_rwlock); |
1376 | 1409 | ||
1377 | if (kern) | 1410 | if (kern) { |
1378 | tclass = unmap_class(orig_tclass); | 1411 | tclass = unmap_class(orig_tclass); |
1379 | else | 1412 | sock = security_is_socket_class(orig_tclass); |
1413 | } else { | ||
1380 | tclass = orig_tclass; | 1414 | tclass = orig_tclass; |
1415 | sock = security_is_socket_class(map_class(tclass)); | ||
1416 | } | ||
1381 | 1417 | ||
1382 | scontext = sidtab_search(&sidtab, ssid); | 1418 | scontext = sidtab_search(&sidtab, ssid); |
1383 | if (!scontext) { | 1419 | if (!scontext) { |
@@ -1408,7 +1444,7 @@ static int security_compute_sid(u32 ssid, | |||
1408 | } | 1444 | } |
1409 | 1445 | ||
1410 | /* Set the role and type to default values. */ | 1446 | /* Set the role and type to default values. */ |
1411 | if (tclass == policydb.process_class) { | 1447 | if ((tclass == policydb.process_class) || (sock == true)) { |
1412 | /* Use the current role and type of process. */ | 1448 | /* Use the current role and type of process. */ |
1413 | newcontext.role = scontext->role; | 1449 | newcontext.role = scontext->role; |
1414 | newcontext.type = scontext->type; | 1450 | newcontext.type = scontext->type; |
@@ -1442,6 +1478,11 @@ static int security_compute_sid(u32 ssid, | |||
1442 | newcontext.type = avdatum->data; | 1478 | newcontext.type = avdatum->data; |
1443 | } | 1479 | } |
1444 | 1480 | ||
1481 | /* if we have a qstr this is a file trans check so check those rules */ | ||
1482 | if (qstr) | ||
1483 | filename_compute_type(&policydb, &newcontext, scontext->type, | ||
1484 | tcontext->type, tclass, qstr); | ||
1485 | |||
1445 | /* Check for class-specific changes. */ | 1486 | /* Check for class-specific changes. */ |
1446 | if (tclass == policydb.process_class) { | 1487 | if (tclass == policydb.process_class) { |
1447 | if (specified & AVTAB_TRANSITION) { | 1488 | if (specified & AVTAB_TRANSITION) { |
@@ -1460,7 +1501,8 @@ static int security_compute_sid(u32 ssid, | |||
1460 | 1501 | ||
1461 | /* Set the MLS attributes. | 1502 | /* Set the MLS attributes. |
1462 | This is done last because it may allocate memory. */ | 1503 | This is done last because it may allocate memory. */ |
1463 | rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext); | 1504 | rc = mls_compute_sid(scontext, tcontext, tclass, specified, |
1505 | &newcontext, sock); | ||
1464 | if (rc) | 1506 | if (rc) |
1465 | goto out_unlock; | 1507 | goto out_unlock; |
1466 | 1508 | ||
@@ -1495,22 +1537,17 @@ out: | |||
1495 | * if insufficient memory is available, or %0 if the new SID was | 1537 | * if insufficient memory is available, or %0 if the new SID was |
1496 | * computed successfully. | 1538 | * computed successfully. |
1497 | */ | 1539 | */ |
1498 | int security_transition_sid(u32 ssid, | 1540 | int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, |
1499 | u32 tsid, | 1541 | const struct qstr *qstr, u32 *out_sid) |
1500 | u16 tclass, | ||
1501 | u32 *out_sid) | ||
1502 | { | 1542 | { |
1503 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, | 1543 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, |
1504 | out_sid, true); | 1544 | qstr, out_sid, true); |
1505 | } | 1545 | } |
1506 | 1546 | ||
1507 | int security_transition_sid_user(u32 ssid, | 1547 | int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) |
1508 | u32 tsid, | ||
1509 | u16 tclass, | ||
1510 | u32 *out_sid) | ||
1511 | { | 1548 | { |
1512 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, | 1549 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, |
1513 | out_sid, false); | 1550 | NULL, out_sid, false); |
1514 | } | 1551 | } |
1515 | 1552 | ||
1516 | /** | 1553 | /** |
@@ -1531,8 +1568,8 @@ int security_member_sid(u32 ssid, | |||
1531 | u16 tclass, | 1568 | u16 tclass, |
1532 | u32 *out_sid) | 1569 | u32 *out_sid) |
1533 | { | 1570 | { |
1534 | return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid, | 1571 | return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL, |
1535 | false); | 1572 | out_sid, false); |
1536 | } | 1573 | } |
1537 | 1574 | ||
1538 | /** | 1575 | /** |
@@ -1553,8 +1590,8 @@ int security_change_sid(u32 ssid, | |||
1553 | u16 tclass, | 1590 | u16 tclass, |
1554 | u32 *out_sid) | 1591 | u32 *out_sid) |
1555 | { | 1592 | { |
1556 | return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid, | 1593 | return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL, |
1557 | false); | 1594 | out_sid, false); |
1558 | } | 1595 | } |
1559 | 1596 | ||
1560 | /* Clone the SID into the new SID table. */ | 1597 | /* Clone the SID into the new SID table. */ |
@@ -2769,7 +2806,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) | |||
2769 | case AUDIT_SUBJ_CLR: | 2806 | case AUDIT_SUBJ_CLR: |
2770 | case AUDIT_OBJ_LEV_LOW: | 2807 | case AUDIT_OBJ_LEV_LOW: |
2771 | case AUDIT_OBJ_LEV_HIGH: | 2808 | case AUDIT_OBJ_LEV_HIGH: |
2772 | /* we do not allow a range, indicated by the presense of '-' */ | 2809 | /* we do not allow a range, indicated by the presence of '-' */ |
2773 | if (strchr(rulestr, '-')) | 2810 | if (strchr(rulestr, '-')) |
2774 | return -EINVAL; | 2811 | return -EINVAL; |
2775 | break; | 2812 | break; |
@@ -3038,7 +3075,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, | |||
3038 | * Description: | 3075 | * Description: |
3039 | * Convert the given NetLabel security attributes in @secattr into a | 3076 | * Convert the given NetLabel security attributes in @secattr into a |
3040 | * SELinux SID. If the @secattr field does not contain a full SELinux | 3077 | * SELinux SID. If the @secattr field does not contain a full SELinux |
3041 | * SID/context then use SECINITSID_NETMSG as the foundation. If possibile the | 3078 | * SID/context then use SECINITSID_NETMSG as the foundation. If possible the |
3042 | * 'cache' field of @secattr is set and the CACHE flag is set; this is to | 3079 | * 'cache' field of @secattr is set and the CACHE flag is set; this is to |
3043 | * allow the @secattr to be used by NetLabel to cache the secattr to SID | 3080 | * allow the @secattr to be used by NetLabel to cache the secattr to SID |
3044 | * conversion for future lookups. Returns zero on success, negative values on | 3081 | * conversion for future lookups. Returns zero on success, negative values on |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index fff78d3b51a2..68178b76a2b3 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -112,7 +112,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) | |||
112 | */ | 112 | */ |
113 | 113 | ||
114 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, | 114 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, |
115 | struct flowi *fl) | 115 | const struct flowi *fl) |
116 | { | 116 | { |
117 | u32 state_sid; | 117 | u32 state_sid; |
118 | int rc; | 118 | int rc; |
@@ -135,10 +135,10 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * | |||
135 | 135 | ||
136 | state_sid = x->security->ctx_sid; | 136 | state_sid = x->security->ctx_sid; |
137 | 137 | ||
138 | if (fl->secid != state_sid) | 138 | if (fl->flowi_secid != state_sid) |
139 | return 0; | 139 | return 0; |
140 | 140 | ||
141 | rc = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, | 141 | rc = avc_has_perm(fl->flowi_secid, state_sid, SECCLASS_ASSOCIATION, |
142 | ASSOCIATION__SENDTO, | 142 | ASSOCIATION__SENDTO, |
143 | NULL)? 0:1; | 143 | NULL)? 0:1; |
144 | 144 | ||
@@ -208,7 +208,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, | |||
208 | if (!uctx) | 208 | if (!uctx) |
209 | goto not_from_user; | 209 | goto not_from_user; |
210 | 210 | ||
211 | if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) | 211 | if (uctx->ctx_alg != XFRM_SC_ALG_SELINUX) |
212 | return -EINVAL; | 212 | return -EINVAL; |
213 | 213 | ||
214 | str_len = uctx->ctx_len; | 214 | str_len = uctx->ctx_len; |