diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 566 |
1 files changed, 326 insertions, 240 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4796ddd4e721..20219ef5439a 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" |
@@ -987,6 +990,7 @@ static void selinux_write_opts(struct seq_file *m, | |||
987 | continue; | 990 | continue; |
988 | default: | 991 | default: |
989 | BUG(); | 992 | BUG(); |
993 | return; | ||
990 | }; | 994 | }; |
991 | /* we need a comma before each option */ | 995 | /* we need a comma before each option */ |
992 | seq_putc(m, ','); | 996 | seq_putc(m, ','); |
@@ -1120,39 +1124,35 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc | |||
1120 | } | 1124 | } |
1121 | 1125 | ||
1122 | #ifdef CONFIG_PROC_FS | 1126 | #ifdef CONFIG_PROC_FS |
1123 | static int selinux_proc_get_sid(struct proc_dir_entry *de, | 1127 | static int selinux_proc_get_sid(struct dentry *dentry, |
1124 | u16 tclass, | 1128 | u16 tclass, |
1125 | u32 *sid) | 1129 | u32 *sid) |
1126 | { | 1130 | { |
1127 | int buflen, rc; | 1131 | int rc; |
1128 | char *buffer, *path, *end; | 1132 | char *buffer, *path; |
1129 | 1133 | ||
1130 | buffer = (char *)__get_free_page(GFP_KERNEL); | 1134 | buffer = (char *)__get_free_page(GFP_KERNEL); |
1131 | if (!buffer) | 1135 | if (!buffer) |
1132 | return -ENOMEM; | 1136 | return -ENOMEM; |
1133 | 1137 | ||
1134 | buflen = PAGE_SIZE; | 1138 | path = dentry_path_raw(dentry, buffer, PAGE_SIZE); |
1135 | end = buffer+buflen; | 1139 | if (IS_ERR(path)) |
1136 | *--end = '\0'; | 1140 | rc = PTR_ERR(path); |
1137 | buflen--; | 1141 | else { |
1138 | path = end-1; | 1142 | /* each process gets a /proc/PID/ entry. Strip off the |
1139 | *path = '/'; | 1143 | * PID part to get a valid selinux labeling. |
1140 | while (de && de != de->parent) { | 1144 | * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ |
1141 | buflen -= de->namelen + 1; | 1145 | while (path[1] >= '0' && path[1] <= '9') { |
1142 | if (buflen < 0) | 1146 | path[1] = '/'; |
1143 | break; | 1147 | path++; |
1144 | end -= de->namelen; | 1148 | } |
1145 | memcpy(end, de->name, de->namelen); | 1149 | rc = security_genfs_sid("proc", path, tclass, sid); |
1146 | *--end = '/'; | ||
1147 | path = end; | ||
1148 | de = de->parent; | ||
1149 | } | 1150 | } |
1150 | rc = security_genfs_sid("proc", path, tclass, sid); | ||
1151 | free_page((unsigned long)buffer); | 1151 | free_page((unsigned long)buffer); |
1152 | return rc; | 1152 | return rc; |
1153 | } | 1153 | } |
1154 | #else | 1154 | #else |
1155 | static int selinux_proc_get_sid(struct proc_dir_entry *de, | 1155 | static int selinux_proc_get_sid(struct dentry *dentry, |
1156 | u16 tclass, | 1156 | u16 tclass, |
1157 | u32 *sid) | 1157 | u32 *sid) |
1158 | { | 1158 | { |
@@ -1300,10 +1300,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1300 | 1300 | ||
1301 | /* Try to obtain a transition SID. */ | 1301 | /* Try to obtain a transition SID. */ |
1302 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1302 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
1303 | rc = security_transition_sid(isec->task_sid, | 1303 | rc = security_transition_sid(isec->task_sid, sbsec->sid, |
1304 | sbsec->sid, | 1304 | isec->sclass, NULL, &sid); |
1305 | isec->sclass, | ||
1306 | &sid); | ||
1307 | if (rc) | 1305 | if (rc) |
1308 | goto out_unlock; | 1306 | goto out_unlock; |
1309 | isec->sid = sid; | 1307 | isec->sid = sid; |
@@ -1316,10 +1314,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1316 | isec->sid = sbsec->sid; | 1314 | isec->sid = sbsec->sid; |
1317 | 1315 | ||
1318 | if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { | 1316 | if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { |
1319 | struct proc_inode *proci = PROC_I(inode); | 1317 | if (opt_dentry) { |
1320 | if (proci->pde) { | ||
1321 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1318 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
1322 | rc = selinux_proc_get_sid(proci->pde, | 1319 | rc = selinux_proc_get_sid(opt_dentry, |
1323 | isec->sclass, | 1320 | isec->sclass, |
1324 | &sid); | 1321 | &sid); |
1325 | if (rc) | 1322 | if (rc) |
@@ -1447,11 +1444,15 @@ static int task_has_capability(struct task_struct *tsk, | |||
1447 | printk(KERN_ERR | 1444 | printk(KERN_ERR |
1448 | "SELinux: out of range capability %d\n", cap); | 1445 | "SELinux: out of range capability %d\n", cap); |
1449 | BUG(); | 1446 | BUG(); |
1447 | return -EINVAL; | ||
1450 | } | 1448 | } |
1451 | 1449 | ||
1452 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); | 1450 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); |
1453 | if (audit == SECURITY_CAP_AUDIT) | 1451 | if (audit == SECURITY_CAP_AUDIT) { |
1454 | avc_audit(sid, sid, sclass, av, &avd, rc, &ad); | 1452 | int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0); |
1453 | if (rc2) | ||
1454 | return rc2; | ||
1455 | } | ||
1455 | return rc; | 1456 | return rc; |
1456 | } | 1457 | } |
1457 | 1458 | ||
@@ -1471,10 +1472,10 @@ static int task_has_system(struct task_struct *tsk, | |||
1471 | static int inode_has_perm(const struct cred *cred, | 1472 | static int inode_has_perm(const struct cred *cred, |
1472 | struct inode *inode, | 1473 | struct inode *inode, |
1473 | u32 perms, | 1474 | u32 perms, |
1474 | struct common_audit_data *adp) | 1475 | struct common_audit_data *adp, |
1476 | unsigned flags) | ||
1475 | { | 1477 | { |
1476 | struct inode_security_struct *isec; | 1478 | struct inode_security_struct *isec; |
1477 | struct common_audit_data ad; | ||
1478 | u32 sid; | 1479 | u32 sid; |
1479 | 1480 | ||
1480 | validate_creds(cred); | 1481 | validate_creds(cred); |
@@ -1485,30 +1486,49 @@ static int inode_has_perm(const struct cred *cred, | |||
1485 | sid = cred_sid(cred); | 1486 | sid = cred_sid(cred); |
1486 | isec = inode->i_security; | 1487 | isec = inode->i_security; |
1487 | 1488 | ||
1488 | if (!adp) { | 1489 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); |
1489 | adp = &ad; | 1490 | } |
1490 | COMMON_AUDIT_DATA_INIT(&ad, FS); | ||
1491 | ad.u.fs.inode = inode; | ||
1492 | } | ||
1493 | 1491 | ||
1494 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); | 1492 | static int inode_has_perm_noadp(const struct cred *cred, |
1493 | struct inode *inode, | ||
1494 | u32 perms, | ||
1495 | unsigned flags) | ||
1496 | { | ||
1497 | struct common_audit_data ad; | ||
1498 | |||
1499 | COMMON_AUDIT_DATA_INIT(&ad, INODE); | ||
1500 | ad.u.inode = inode; | ||
1501 | return inode_has_perm(cred, inode, perms, &ad, flags); | ||
1495 | } | 1502 | } |
1496 | 1503 | ||
1497 | /* Same as inode_has_perm, but pass explicit audit data containing | 1504 | /* Same as inode_has_perm, but pass explicit audit data containing |
1498 | the dentry to help the auditing code to more easily generate the | 1505 | the dentry to help the auditing code to more easily generate the |
1499 | pathname if needed. */ | 1506 | pathname if needed. */ |
1500 | static inline int dentry_has_perm(const struct cred *cred, | 1507 | static inline int dentry_has_perm(const struct cred *cred, |
1501 | struct vfsmount *mnt, | ||
1502 | struct dentry *dentry, | 1508 | struct dentry *dentry, |
1503 | u32 av) | 1509 | u32 av) |
1504 | { | 1510 | { |
1505 | struct inode *inode = dentry->d_inode; | 1511 | struct inode *inode = dentry->d_inode; |
1506 | struct common_audit_data ad; | 1512 | struct common_audit_data ad; |
1507 | 1513 | ||
1508 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1514 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1509 | ad.u.fs.path.mnt = mnt; | 1515 | ad.u.dentry = dentry; |
1510 | ad.u.fs.path.dentry = dentry; | 1516 | return inode_has_perm(cred, inode, av, &ad, 0); |
1511 | return inode_has_perm(cred, inode, av, &ad); | 1517 | } |
1518 | |||
1519 | /* Same as inode_has_perm, but pass explicit audit data containing | ||
1520 | the path to help the auditing code to more easily generate the | ||
1521 | pathname if needed. */ | ||
1522 | static inline int path_has_perm(const struct cred *cred, | ||
1523 | struct path *path, | ||
1524 | u32 av) | ||
1525 | { | ||
1526 | struct inode *inode = path->dentry->d_inode; | ||
1527 | struct common_audit_data ad; | ||
1528 | |||
1529 | COMMON_AUDIT_DATA_INIT(&ad, PATH); | ||
1530 | ad.u.path = *path; | ||
1531 | return inode_has_perm(cred, inode, av, &ad, 0); | ||
1512 | } | 1532 | } |
1513 | 1533 | ||
1514 | /* Check whether a task can use an open file descriptor to | 1534 | /* Check whether a task can use an open file descriptor to |
@@ -1529,8 +1549,8 @@ static int file_has_perm(const struct cred *cred, | |||
1529 | u32 sid = cred_sid(cred); | 1549 | u32 sid = cred_sid(cred); |
1530 | int rc; | 1550 | int rc; |
1531 | 1551 | ||
1532 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1552 | COMMON_AUDIT_DATA_INIT(&ad, PATH); |
1533 | ad.u.fs.path = file->f_path; | 1553 | ad.u.path = file->f_path; |
1534 | 1554 | ||
1535 | if (sid != fsec->sid) { | 1555 | if (sid != fsec->sid) { |
1536 | rc = avc_has_perm(sid, fsec->sid, | 1556 | rc = avc_has_perm(sid, fsec->sid, |
@@ -1544,7 +1564,7 @@ static int file_has_perm(const struct cred *cred, | |||
1544 | /* av is zero if only checking access to the descriptor. */ | 1564 | /* av is zero if only checking access to the descriptor. */ |
1545 | rc = 0; | 1565 | rc = 0; |
1546 | if (av) | 1566 | if (av) |
1547 | rc = inode_has_perm(cred, inode, av, &ad); | 1567 | rc = inode_has_perm(cred, inode, av, &ad, 0); |
1548 | 1568 | ||
1549 | out: | 1569 | out: |
1550 | return rc; | 1570 | return rc; |
@@ -1568,8 +1588,8 @@ static int may_create(struct inode *dir, | |||
1568 | sid = tsec->sid; | 1588 | sid = tsec->sid; |
1569 | newsid = tsec->create_sid; | 1589 | newsid = tsec->create_sid; |
1570 | 1590 | ||
1571 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1591 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1572 | ad.u.fs.path.dentry = dentry; | 1592 | ad.u.dentry = dentry; |
1573 | 1593 | ||
1574 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, | 1594 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, |
1575 | DIR__ADD_NAME | DIR__SEARCH, | 1595 | DIR__ADD_NAME | DIR__SEARCH, |
@@ -1578,7 +1598,8 @@ static int may_create(struct inode *dir, | |||
1578 | return rc; | 1598 | return rc; |
1579 | 1599 | ||
1580 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | 1600 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
1581 | rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); | 1601 | rc = security_transition_sid(sid, dsec->sid, tclass, |
1602 | &dentry->d_name, &newsid); | ||
1582 | if (rc) | 1603 | if (rc) |
1583 | return rc; | 1604 | return rc; |
1584 | } | 1605 | } |
@@ -1620,8 +1641,8 @@ static int may_link(struct inode *dir, | |||
1620 | dsec = dir->i_security; | 1641 | dsec = dir->i_security; |
1621 | isec = dentry->d_inode->i_security; | 1642 | isec = dentry->d_inode->i_security; |
1622 | 1643 | ||
1623 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1644 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1624 | ad.u.fs.path.dentry = dentry; | 1645 | ad.u.dentry = dentry; |
1625 | 1646 | ||
1626 | av = DIR__SEARCH; | 1647 | av = DIR__SEARCH; |
1627 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); | 1648 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); |
@@ -1666,9 +1687,9 @@ static inline int may_rename(struct inode *old_dir, | |||
1666 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 1687 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
1667 | new_dsec = new_dir->i_security; | 1688 | new_dsec = new_dir->i_security; |
1668 | 1689 | ||
1669 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1690 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1670 | 1691 | ||
1671 | ad.u.fs.path.dentry = old_dentry; | 1692 | ad.u.dentry = old_dentry; |
1672 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, | 1693 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, |
1673 | DIR__REMOVE_NAME | DIR__SEARCH, &ad); | 1694 | DIR__REMOVE_NAME | DIR__SEARCH, &ad); |
1674 | if (rc) | 1695 | if (rc) |
@@ -1684,7 +1705,7 @@ static inline int may_rename(struct inode *old_dir, | |||
1684 | return rc; | 1705 | return rc; |
1685 | } | 1706 | } |
1686 | 1707 | ||
1687 | ad.u.fs.path.dentry = new_dentry; | 1708 | ad.u.dentry = new_dentry; |
1688 | av = DIR__ADD_NAME | DIR__SEARCH; | 1709 | av = DIR__ADD_NAME | DIR__SEARCH; |
1689 | if (new_dentry->d_inode) | 1710 | if (new_dentry->d_inode) |
1690 | av |= DIR__REMOVE_NAME; | 1711 | av |= DIR__REMOVE_NAME; |
@@ -1851,93 +1872,17 @@ static int selinux_capset(struct cred *new, const struct cred *old, | |||
1851 | */ | 1872 | */ |
1852 | 1873 | ||
1853 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, | 1874 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, |
1854 | int cap, int audit) | 1875 | struct user_namespace *ns, int cap, int audit) |
1855 | { | 1876 | { |
1856 | int rc; | 1877 | int rc; |
1857 | 1878 | ||
1858 | rc = cap_capable(tsk, cred, cap, audit); | 1879 | rc = cap_capable(tsk, cred, ns, cap, audit); |
1859 | if (rc) | 1880 | if (rc) |
1860 | return rc; | 1881 | return rc; |
1861 | 1882 | ||
1862 | return task_has_capability(tsk, cred, cap, audit); | 1883 | return task_has_capability(tsk, cred, cap, audit); |
1863 | } | 1884 | } |
1864 | 1885 | ||
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) | 1886 | static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) |
1942 | { | 1887 | { |
1943 | const struct cred *cred = current_cred(); | 1888 | const struct cred *cred = current_cred(); |
@@ -1970,17 +1915,13 @@ static int selinux_quota_on(struct dentry *dentry) | |||
1970 | { | 1915 | { |
1971 | const struct cred *cred = current_cred(); | 1916 | const struct cred *cred = current_cred(); |
1972 | 1917 | ||
1973 | return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); | 1918 | return dentry_has_perm(cred, dentry, FILE__QUOTAON); |
1974 | } | 1919 | } |
1975 | 1920 | ||
1976 | static int selinux_syslog(int type, bool from_file) | 1921 | static int selinux_syslog(int type) |
1977 | { | 1922 | { |
1978 | int rc; | 1923 | int rc; |
1979 | 1924 | ||
1980 | rc = cap_syslog(type, from_file); | ||
1981 | if (rc) | ||
1982 | return rc; | ||
1983 | |||
1984 | switch (type) { | 1925 | switch (type) { |
1985 | case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ | 1926 | case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ |
1986 | case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ | 1927 | case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ |
@@ -2016,7 +1957,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
2016 | { | 1957 | { |
2017 | int rc, cap_sys_admin = 0; | 1958 | int rc, cap_sys_admin = 0; |
2018 | 1959 | ||
2019 | rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN, | 1960 | rc = selinux_capable(current, current_cred(), |
1961 | &init_user_ns, CAP_SYS_ADMIN, | ||
2020 | SECURITY_CAP_NOAUDIT); | 1962 | SECURITY_CAP_NOAUDIT); |
2021 | if (rc == 0) | 1963 | if (rc == 0) |
2022 | cap_sys_admin = 1; | 1964 | cap_sys_admin = 1; |
@@ -2064,13 +2006,14 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2064 | } else { | 2006 | } else { |
2065 | /* Check for a default transition on this program. */ | 2007 | /* Check for a default transition on this program. */ |
2066 | rc = security_transition_sid(old_tsec->sid, isec->sid, | 2008 | rc = security_transition_sid(old_tsec->sid, isec->sid, |
2067 | SECCLASS_PROCESS, &new_tsec->sid); | 2009 | SECCLASS_PROCESS, NULL, |
2010 | &new_tsec->sid); | ||
2068 | if (rc) | 2011 | if (rc) |
2069 | return rc; | 2012 | return rc; |
2070 | } | 2013 | } |
2071 | 2014 | ||
2072 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2015 | COMMON_AUDIT_DATA_INIT(&ad, PATH); |
2073 | ad.u.fs.path = bprm->file->f_path; | 2016 | ad.u.path = bprm->file->f_path; |
2074 | 2017 | ||
2075 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 2018 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) |
2076 | new_tsec->sid = old_tsec->sid; | 2019 | new_tsec->sid = old_tsec->sid; |
@@ -2184,8 +2127,8 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2184 | struct tty_file_private, list); | 2127 | struct tty_file_private, list); |
2185 | file = file_priv->file; | 2128 | file = file_priv->file; |
2186 | inode = file->f_path.dentry->d_inode; | 2129 | inode = file->f_path.dentry->d_inode; |
2187 | if (inode_has_perm(cred, inode, | 2130 | if (inode_has_perm_noadp(cred, inode, |
2188 | FILE__READ | FILE__WRITE, NULL)) { | 2131 | FILE__READ | FILE__WRITE, 0)) { |
2189 | drop_tty = 1; | 2132 | drop_tty = 1; |
2190 | } | 2133 | } |
2191 | } | 2134 | } |
@@ -2198,7 +2141,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2198 | 2141 | ||
2199 | /* Revalidate access to inherited open files. */ | 2142 | /* Revalidate access to inherited open files. */ |
2200 | 2143 | ||
2201 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2144 | COMMON_AUDIT_DATA_INIT(&ad, INODE); |
2202 | 2145 | ||
2203 | spin_lock(&files->file_lock); | 2146 | spin_lock(&files->file_lock); |
2204 | for (;;) { | 2147 | for (;;) { |
@@ -2447,6 +2390,91 @@ out: | |||
2447 | return rc; | 2390 | return rc; |
2448 | } | 2391 | } |
2449 | 2392 | ||
2393 | static int selinux_sb_remount(struct super_block *sb, void *data) | ||
2394 | { | ||
2395 | int rc, i, *flags; | ||
2396 | struct security_mnt_opts opts; | ||
2397 | char *secdata, **mount_options; | ||
2398 | struct superblock_security_struct *sbsec = sb->s_security; | ||
2399 | |||
2400 | if (!(sbsec->flags & SE_SBINITIALIZED)) | ||
2401 | return 0; | ||
2402 | |||
2403 | if (!data) | ||
2404 | return 0; | ||
2405 | |||
2406 | if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) | ||
2407 | return 0; | ||
2408 | |||
2409 | security_init_mnt_opts(&opts); | ||
2410 | secdata = alloc_secdata(); | ||
2411 | if (!secdata) | ||
2412 | return -ENOMEM; | ||
2413 | rc = selinux_sb_copy_data(data, secdata); | ||
2414 | if (rc) | ||
2415 | goto out_free_secdata; | ||
2416 | |||
2417 | rc = selinux_parse_opts_str(secdata, &opts); | ||
2418 | if (rc) | ||
2419 | goto out_free_secdata; | ||
2420 | |||
2421 | mount_options = opts.mnt_opts; | ||
2422 | flags = opts.mnt_opts_flags; | ||
2423 | |||
2424 | for (i = 0; i < opts.num_mnt_opts; i++) { | ||
2425 | u32 sid; | ||
2426 | size_t len; | ||
2427 | |||
2428 | if (flags[i] == SE_SBLABELSUPP) | ||
2429 | continue; | ||
2430 | len = strlen(mount_options[i]); | ||
2431 | rc = security_context_to_sid(mount_options[i], len, &sid); | ||
2432 | if (rc) { | ||
2433 | printk(KERN_WARNING "SELinux: security_context_to_sid" | ||
2434 | "(%s) failed for (dev %s, type %s) errno=%d\n", | ||
2435 | mount_options[i], sb->s_id, sb->s_type->name, rc); | ||
2436 | goto out_free_opts; | ||
2437 | } | ||
2438 | rc = -EINVAL; | ||
2439 | switch (flags[i]) { | ||
2440 | case FSCONTEXT_MNT: | ||
2441 | if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) | ||
2442 | goto out_bad_option; | ||
2443 | break; | ||
2444 | case CONTEXT_MNT: | ||
2445 | if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) | ||
2446 | goto out_bad_option; | ||
2447 | break; | ||
2448 | case ROOTCONTEXT_MNT: { | ||
2449 | struct inode_security_struct *root_isec; | ||
2450 | root_isec = sb->s_root->d_inode->i_security; | ||
2451 | |||
2452 | if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) | ||
2453 | goto out_bad_option; | ||
2454 | break; | ||
2455 | } | ||
2456 | case DEFCONTEXT_MNT: | ||
2457 | if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) | ||
2458 | goto out_bad_option; | ||
2459 | break; | ||
2460 | default: | ||
2461 | goto out_free_opts; | ||
2462 | } | ||
2463 | } | ||
2464 | |||
2465 | rc = 0; | ||
2466 | out_free_opts: | ||
2467 | security_free_mnt_opts(&opts); | ||
2468 | out_free_secdata: | ||
2469 | free_secdata(secdata); | ||
2470 | return rc; | ||
2471 | out_bad_option: | ||
2472 | printk(KERN_WARNING "SELinux: unable to change security options " | ||
2473 | "during remount (dev %s, type=%s)\n", sb->s_id, | ||
2474 | sb->s_type->name); | ||
2475 | goto out_free_opts; | ||
2476 | } | ||
2477 | |||
2450 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | 2478 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) |
2451 | { | 2479 | { |
2452 | const struct cred *cred = current_cred(); | 2480 | const struct cred *cred = current_cred(); |
@@ -2461,8 +2489,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
2461 | if (flags & MS_KERNMOUNT) | 2489 | if (flags & MS_KERNMOUNT) |
2462 | return 0; | 2490 | return 0; |
2463 | 2491 | ||
2464 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2492 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2465 | ad.u.fs.path.dentry = sb->s_root; | 2493 | ad.u.dentry = sb->s_root; |
2466 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); | 2494 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); |
2467 | } | 2495 | } |
2468 | 2496 | ||
@@ -2471,8 +2499,8 @@ static int selinux_sb_statfs(struct dentry *dentry) | |||
2471 | const struct cred *cred = current_cred(); | 2499 | const struct cred *cred = current_cred(); |
2472 | struct common_audit_data ad; | 2500 | struct common_audit_data ad; |
2473 | 2501 | ||
2474 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2502 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2475 | ad.u.fs.path.dentry = dentry->d_sb->s_root; | 2503 | ad.u.dentry = dentry->d_sb->s_root; |
2476 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); | 2504 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
2477 | } | 2505 | } |
2478 | 2506 | ||
@@ -2488,8 +2516,7 @@ static int selinux_mount(char *dev_name, | |||
2488 | return superblock_has_perm(cred, path->mnt->mnt_sb, | 2516 | return superblock_has_perm(cred, path->mnt->mnt_sb, |
2489 | FILESYSTEM__REMOUNT, NULL); | 2517 | FILESYSTEM__REMOUNT, NULL); |
2490 | else | 2518 | else |
2491 | return dentry_has_perm(cred, path->mnt, path->dentry, | 2519 | return path_has_perm(cred, path, FILE__MOUNTON); |
2492 | FILE__MOUNTON); | ||
2493 | } | 2520 | } |
2494 | 2521 | ||
2495 | static int selinux_umount(struct vfsmount *mnt, int flags) | 2522 | static int selinux_umount(struct vfsmount *mnt, int flags) |
@@ -2513,8 +2540,8 @@ static void selinux_inode_free_security(struct inode *inode) | |||
2513 | } | 2540 | } |
2514 | 2541 | ||
2515 | static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | 2542 | static int selinux_inode_init_security(struct inode *inode, struct inode *dir, |
2516 | char **name, void **value, | 2543 | const struct qstr *qstr, char **name, |
2517 | size_t *len) | 2544 | void **value, size_t *len) |
2518 | { | 2545 | { |
2519 | const struct task_security_struct *tsec = current_security(); | 2546 | const struct task_security_struct *tsec = current_security(); |
2520 | struct inode_security_struct *dsec; | 2547 | struct inode_security_struct *dsec; |
@@ -2529,10 +2556,13 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2529 | sid = tsec->sid; | 2556 | sid = tsec->sid; |
2530 | newsid = tsec->create_sid; | 2557 | newsid = tsec->create_sid; |
2531 | 2558 | ||
2532 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | 2559 | if ((sbsec->flags & SE_SBINITIALIZED) && |
2560 | (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) | ||
2561 | newsid = sbsec->mntpoint_sid; | ||
2562 | else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | ||
2533 | rc = security_transition_sid(sid, dsec->sid, | 2563 | rc = security_transition_sid(sid, dsec->sid, |
2534 | inode_mode_to_security_class(inode->i_mode), | 2564 | inode_mode_to_security_class(inode->i_mode), |
2535 | &newsid); | 2565 | qstr, &newsid); |
2536 | if (rc) { | 2566 | if (rc) { |
2537 | printk(KERN_WARNING "%s: " | 2567 | printk(KERN_WARNING "%s: " |
2538 | "security_transition_sid failed, rc=%d (dev=%s " | 2568 | "security_transition_sid failed, rc=%d (dev=%s " |
@@ -2619,17 +2649,17 @@ static int selinux_inode_readlink(struct dentry *dentry) | |||
2619 | { | 2649 | { |
2620 | const struct cred *cred = current_cred(); | 2650 | const struct cred *cred = current_cred(); |
2621 | 2651 | ||
2622 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); | 2652 | return dentry_has_perm(cred, dentry, FILE__READ); |
2623 | } | 2653 | } |
2624 | 2654 | ||
2625 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) | 2655 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) |
2626 | { | 2656 | { |
2627 | const struct cred *cred = current_cred(); | 2657 | const struct cred *cred = current_cred(); |
2628 | 2658 | ||
2629 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); | 2659 | return dentry_has_perm(cred, dentry, FILE__READ); |
2630 | } | 2660 | } |
2631 | 2661 | ||
2632 | static int selinux_inode_permission(struct inode *inode, int mask) | 2662 | static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) |
2633 | { | 2663 | { |
2634 | const struct cred *cred = current_cred(); | 2664 | const struct cred *cred = current_cred(); |
2635 | struct common_audit_data ad; | 2665 | struct common_audit_data ad; |
@@ -2643,15 +2673,15 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
2643 | if (!mask) | 2673 | if (!mask) |
2644 | return 0; | 2674 | return 0; |
2645 | 2675 | ||
2646 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2676 | COMMON_AUDIT_DATA_INIT(&ad, INODE); |
2647 | ad.u.fs.inode = inode; | 2677 | ad.u.inode = inode; |
2648 | 2678 | ||
2649 | if (from_access) | 2679 | if (from_access) |
2650 | ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; | 2680 | ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; |
2651 | 2681 | ||
2652 | perms = file_mask_to_av(inode->i_mode, mask); | 2682 | perms = file_mask_to_av(inode->i_mode, mask); |
2653 | 2683 | ||
2654 | return inode_has_perm(cred, inode, perms, &ad); | 2684 | return inode_has_perm(cred, inode, perms, &ad, flags); |
2655 | } | 2685 | } |
2656 | 2686 | ||
2657 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2687 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
@@ -2669,16 +2699,20 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
2669 | 2699 | ||
2670 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | | 2700 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | |
2671 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) | 2701 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) |
2672 | return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); | 2702 | return dentry_has_perm(cred, dentry, FILE__SETATTR); |
2673 | 2703 | ||
2674 | return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); | 2704 | return dentry_has_perm(cred, dentry, FILE__WRITE); |
2675 | } | 2705 | } |
2676 | 2706 | ||
2677 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 2707 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
2678 | { | 2708 | { |
2679 | const struct cred *cred = current_cred(); | 2709 | const struct cred *cred = current_cred(); |
2710 | struct path path; | ||
2711 | |||
2712 | path.dentry = dentry; | ||
2713 | path.mnt = mnt; | ||
2680 | 2714 | ||
2681 | return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR); | 2715 | return path_has_perm(cred, &path, FILE__GETATTR); |
2682 | } | 2716 | } |
2683 | 2717 | ||
2684 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | 2718 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) |
@@ -2699,7 +2733,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | |||
2699 | 2733 | ||
2700 | /* Not an attribute we recognize, so just check the | 2734 | /* Not an attribute we recognize, so just check the |
2701 | ordinary setattr permission. */ | 2735 | ordinary setattr permission. */ |
2702 | return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); | 2736 | return dentry_has_perm(cred, dentry, FILE__SETATTR); |
2703 | } | 2737 | } |
2704 | 2738 | ||
2705 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | 2739 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, |
@@ -2719,11 +2753,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2719 | if (!(sbsec->flags & SE_SBLABELSUPP)) | 2753 | if (!(sbsec->flags & SE_SBLABELSUPP)) |
2720 | return -EOPNOTSUPP; | 2754 | return -EOPNOTSUPP; |
2721 | 2755 | ||
2722 | if (!is_owner_or_cap(inode)) | 2756 | if (!inode_owner_or_capable(inode)) |
2723 | return -EPERM; | 2757 | return -EPERM; |
2724 | 2758 | ||
2725 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2759 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2726 | ad.u.fs.path.dentry = dentry; | 2760 | ad.u.dentry = dentry; |
2727 | 2761 | ||
2728 | rc = avc_has_perm(sid, isec->sid, isec->sclass, | 2762 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
2729 | FILE__RELABELFROM, &ad); | 2763 | FILE__RELABELFROM, &ad); |
@@ -2786,14 +2820,14 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name) | |||
2786 | { | 2820 | { |
2787 | const struct cred *cred = current_cred(); | 2821 | const struct cred *cred = current_cred(); |
2788 | 2822 | ||
2789 | return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR); | 2823 | return dentry_has_perm(cred, dentry, FILE__GETATTR); |
2790 | } | 2824 | } |
2791 | 2825 | ||
2792 | static int selinux_inode_listxattr(struct dentry *dentry) | 2826 | static int selinux_inode_listxattr(struct dentry *dentry) |
2793 | { | 2827 | { |
2794 | const struct cred *cred = current_cred(); | 2828 | const struct cred *cred = current_cred(); |
2795 | 2829 | ||
2796 | return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR); | 2830 | return dentry_has_perm(cred, dentry, FILE__GETATTR); |
2797 | } | 2831 | } |
2798 | 2832 | ||
2799 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) | 2833 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) |
@@ -2830,7 +2864,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name | |||
2830 | * and lack of permission just means that we fall back to the | 2864 | * and lack of permission just means that we fall back to the |
2831 | * in-core context value, not a denial. | 2865 | * in-core context value, not a denial. |
2832 | */ | 2866 | */ |
2833 | error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN, | 2867 | error = selinux_capable(current, current_cred(), |
2868 | &init_user_ns, CAP_MAC_ADMIN, | ||
2834 | SECURITY_CAP_NOAUDIT); | 2869 | SECURITY_CAP_NOAUDIT); |
2835 | if (!error) | 2870 | if (!error) |
2836 | error = security_sid_to_context_force(isec->sid, &context, | 2871 | error = security_sid_to_context_force(isec->sid, &context, |
@@ -2933,16 +2968,47 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
2933 | unsigned long arg) | 2968 | unsigned long arg) |
2934 | { | 2969 | { |
2935 | const struct cred *cred = current_cred(); | 2970 | const struct cred *cred = current_cred(); |
2936 | u32 av = 0; | 2971 | int error = 0; |
2937 | 2972 | ||
2938 | if (_IOC_DIR(cmd) & _IOC_WRITE) | 2973 | switch (cmd) { |
2939 | av |= FILE__WRITE; | 2974 | case FIONREAD: |
2940 | if (_IOC_DIR(cmd) & _IOC_READ) | 2975 | /* fall through */ |
2941 | av |= FILE__READ; | 2976 | case FIBMAP: |
2942 | if (!av) | 2977 | /* fall through */ |
2943 | av = FILE__IOCTL; | 2978 | case FIGETBSZ: |
2979 | /* fall through */ | ||
2980 | case EXT2_IOC_GETFLAGS: | ||
2981 | /* fall through */ | ||
2982 | case EXT2_IOC_GETVERSION: | ||
2983 | error = file_has_perm(cred, file, FILE__GETATTR); | ||
2984 | break; | ||
2944 | 2985 | ||
2945 | return file_has_perm(cred, file, av); | 2986 | case EXT2_IOC_SETFLAGS: |
2987 | /* fall through */ | ||
2988 | case EXT2_IOC_SETVERSION: | ||
2989 | error = file_has_perm(cred, file, FILE__SETATTR); | ||
2990 | break; | ||
2991 | |||
2992 | /* sys_ioctl() checks */ | ||
2993 | case FIONBIO: | ||
2994 | /* fall through */ | ||
2995 | case FIOASYNC: | ||
2996 | error = file_has_perm(cred, file, 0); | ||
2997 | break; | ||
2998 | |||
2999 | case KDSKBENT: | ||
3000 | case KDSKBSENT: | ||
3001 | error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG, | ||
3002 | SECURITY_CAP_AUDIT); | ||
3003 | break; | ||
3004 | |||
3005 | /* default case assumes that the command will go | ||
3006 | * to the file's ioctl() function. | ||
3007 | */ | ||
3008 | default: | ||
3009 | error = file_has_perm(cred, file, FILE__IOCTL); | ||
3010 | } | ||
3011 | return error; | ||
2946 | } | 3012 | } |
2947 | 3013 | ||
2948 | static int default_noexec; | 3014 | static int default_noexec; |
@@ -3167,7 +3233,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) | |||
3167 | * new inode label or new policy. | 3233 | * new inode label or new policy. |
3168 | * This check is not redundant - do not remove. | 3234 | * This check is not redundant - do not remove. |
3169 | */ | 3235 | */ |
3170 | return inode_has_perm(cred, inode, open_file_to_av(file), NULL); | 3236 | return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0); |
3171 | } | 3237 | } |
3172 | 3238 | ||
3173 | /* task security operations */ | 3239 | /* task security operations */ |
@@ -3199,7 +3265,11 @@ static void selinux_cred_free(struct cred *cred) | |||
3199 | { | 3265 | { |
3200 | struct task_security_struct *tsec = cred->security; | 3266 | struct task_security_struct *tsec = cred->security; |
3201 | 3267 | ||
3202 | BUG_ON((unsigned long) cred->security < PAGE_SIZE); | 3268 | /* |
3269 | * cred->security == NULL if security_cred_alloc_blank() or | ||
3270 | * security_prepare_creds() returned an error. | ||
3271 | */ | ||
3272 | BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE); | ||
3203 | cred->security = (void *) 0x7UL; | 3273 | cred->security = (void *) 0x7UL; |
3204 | kfree(tsec); | 3274 | kfree(tsec); |
3205 | } | 3275 | } |
@@ -3354,11 +3424,11 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, | |||
3354 | return 0; | 3424 | return 0; |
3355 | } | 3425 | } |
3356 | 3426 | ||
3357 | static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) | 3427 | static int selinux_task_setscheduler(struct task_struct *p) |
3358 | { | 3428 | { |
3359 | int rc; | 3429 | int rc; |
3360 | 3430 | ||
3361 | rc = cap_task_setscheduler(p, policy, lp); | 3431 | rc = cap_task_setscheduler(p); |
3362 | if (rc) | 3432 | if (rc) |
3363 | return rc; | 3433 | return rc; |
3364 | 3434 | ||
@@ -3641,9 +3711,16 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) | |||
3641 | 3711 | ||
3642 | /* socket security operations */ | 3712 | /* socket security operations */ |
3643 | 3713 | ||
3644 | static u32 socket_sockcreate_sid(const struct task_security_struct *tsec) | 3714 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, |
3715 | u16 secclass, u32 *socksid) | ||
3645 | { | 3716 | { |
3646 | return tsec->sockcreate_sid ? : tsec->sid; | 3717 | if (tsec->sockcreate_sid > SECSID_NULL) { |
3718 | *socksid = tsec->sockcreate_sid; | ||
3719 | return 0; | ||
3720 | } | ||
3721 | |||
3722 | return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL, | ||
3723 | socksid); | ||
3647 | } | 3724 | } |
3648 | 3725 | ||
3649 | static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) | 3726 | static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) |
@@ -3667,12 +3744,16 @@ static int selinux_socket_create(int family, int type, | |||
3667 | const struct task_security_struct *tsec = current_security(); | 3744 | const struct task_security_struct *tsec = current_security(); |
3668 | u32 newsid; | 3745 | u32 newsid; |
3669 | u16 secclass; | 3746 | u16 secclass; |
3747 | int rc; | ||
3670 | 3748 | ||
3671 | if (kern) | 3749 | if (kern) |
3672 | return 0; | 3750 | return 0; |
3673 | 3751 | ||
3674 | newsid = socket_sockcreate_sid(tsec); | ||
3675 | secclass = socket_type_to_security_class(family, type, protocol); | 3752 | secclass = socket_type_to_security_class(family, type, protocol); |
3753 | rc = socket_sockcreate_sid(tsec, secclass, &newsid); | ||
3754 | if (rc) | ||
3755 | return rc; | ||
3756 | |||
3676 | return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); | 3757 | return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); |
3677 | } | 3758 | } |
3678 | 3759 | ||
@@ -3684,12 +3765,16 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
3684 | struct sk_security_struct *sksec; | 3765 | struct sk_security_struct *sksec; |
3685 | int err = 0; | 3766 | int err = 0; |
3686 | 3767 | ||
3768 | isec->sclass = socket_type_to_security_class(family, type, protocol); | ||
3769 | |||
3687 | if (kern) | 3770 | if (kern) |
3688 | isec->sid = SECINITSID_KERNEL; | 3771 | isec->sid = SECINITSID_KERNEL; |
3689 | else | 3772 | else { |
3690 | isec->sid = socket_sockcreate_sid(tsec); | 3773 | err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid)); |
3774 | if (err) | ||
3775 | return err; | ||
3776 | } | ||
3691 | 3777 | ||
3692 | isec->sclass = socket_type_to_security_class(family, type, protocol); | ||
3693 | isec->initialized = 1; | 3778 | isec->initialized = 1; |
3694 | 3779 | ||
3695 | if (sock->sk) { | 3780 | if (sock->sk) { |
@@ -3925,18 +4010,18 @@ static int selinux_socket_shutdown(struct socket *sock, int how) | |||
3925 | return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN); | 4010 | return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN); |
3926 | } | 4011 | } |
3927 | 4012 | ||
3928 | static int selinux_socket_unix_stream_connect(struct socket *sock, | 4013 | static int selinux_socket_unix_stream_connect(struct sock *sock, |
3929 | struct socket *other, | 4014 | struct sock *other, |
3930 | struct sock *newsk) | 4015 | struct sock *newsk) |
3931 | { | 4016 | { |
3932 | struct sk_security_struct *sksec_sock = sock->sk->sk_security; | 4017 | struct sk_security_struct *sksec_sock = sock->sk_security; |
3933 | struct sk_security_struct *sksec_other = other->sk->sk_security; | 4018 | struct sk_security_struct *sksec_other = other->sk_security; |
3934 | struct sk_security_struct *sksec_new = newsk->sk_security; | 4019 | struct sk_security_struct *sksec_new = newsk->sk_security; |
3935 | struct common_audit_data ad; | 4020 | struct common_audit_data ad; |
3936 | int err; | 4021 | int err; |
3937 | 4022 | ||
3938 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4023 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
3939 | ad.u.net.sk = other->sk; | 4024 | ad.u.net.sk = other; |
3940 | 4025 | ||
3941 | err = avc_has_perm(sksec_sock->sid, sksec_other->sid, | 4026 | err = avc_has_perm(sksec_sock->sid, sksec_other->sid, |
3942 | sksec_other->sclass, | 4027 | sksec_other->sclass, |
@@ -3999,7 +4084,6 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
3999 | { | 4084 | { |
4000 | int err = 0; | 4085 | int err = 0; |
4001 | struct sk_security_struct *sksec = sk->sk_security; | 4086 | struct sk_security_struct *sksec = sk->sk_security; |
4002 | u32 peer_sid; | ||
4003 | u32 sk_sid = sksec->sid; | 4087 | u32 sk_sid = sksec->sid; |
4004 | struct common_audit_data ad; | 4088 | struct common_audit_data ad; |
4005 | char *addrp; | 4089 | char *addrp; |
@@ -4018,20 +4102,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4018 | return err; | 4102 | return err; |
4019 | } | 4103 | } |
4020 | 4104 | ||
4021 | if (selinux_policycap_netpeer) { | 4105 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); |
4022 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4106 | if (err) |
4023 | if (err) | 4107 | return err; |
4024 | return err; | 4108 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); |
4025 | err = avc_has_perm(sk_sid, peer_sid, | ||
4026 | SECCLASS_PEER, PEER__RECV, &ad); | ||
4027 | if (err) | ||
4028 | selinux_netlbl_err(skb, err, 0); | ||
4029 | } else { | ||
4030 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); | ||
4031 | if (err) | ||
4032 | return err; | ||
4033 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); | ||
4034 | } | ||
4035 | 4109 | ||
4036 | return err; | 4110 | return err; |
4037 | } | 4111 | } |
@@ -4279,10 +4353,31 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
4279 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | 4353 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); |
4280 | } | 4354 | } |
4281 | 4355 | ||
4356 | static int selinux_secmark_relabel_packet(u32 sid) | ||
4357 | { | ||
4358 | const struct task_security_struct *__tsec; | ||
4359 | u32 tsid; | ||
4360 | |||
4361 | __tsec = current_security(); | ||
4362 | tsid = __tsec->sid; | ||
4363 | |||
4364 | return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL); | ||
4365 | } | ||
4366 | |||
4367 | static void selinux_secmark_refcount_inc(void) | ||
4368 | { | ||
4369 | atomic_inc(&selinux_secmark_refcount); | ||
4370 | } | ||
4371 | |||
4372 | static void selinux_secmark_refcount_dec(void) | ||
4373 | { | ||
4374 | atomic_dec(&selinux_secmark_refcount); | ||
4375 | } | ||
4376 | |||
4282 | static void selinux_req_classify_flow(const struct request_sock *req, | 4377 | static void selinux_req_classify_flow(const struct request_sock *req, |
4283 | struct flowi *fl) | 4378 | struct flowi *fl) |
4284 | { | 4379 | { |
4285 | fl->secid = req->secid; | 4380 | fl->flowi_secid = req->secid; |
4286 | } | 4381 | } |
4287 | 4382 | ||
4288 | static int selinux_tun_dev_create(void) | 4383 | static int selinux_tun_dev_create(void) |
@@ -4503,11 +4598,10 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4503 | if (selinux_secmark_enabled()) | 4598 | if (selinux_secmark_enabled()) |
4504 | if (avc_has_perm(sksec->sid, skb->secmark, | 4599 | if (avc_has_perm(sksec->sid, skb->secmark, |
4505 | SECCLASS_PACKET, PACKET__SEND, &ad)) | 4600 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
4506 | return NF_DROP; | 4601 | return NF_DROP_ERR(-ECONNREFUSED); |
4507 | 4602 | ||
4508 | if (selinux_policycap_netpeer) | 4603 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
4509 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) | 4604 | return NF_DROP_ERR(-ECONNREFUSED); |
4510 | return NF_DROP; | ||
4511 | 4605 | ||
4512 | return NF_ACCEPT; | 4606 | return NF_ACCEPT; |
4513 | } | 4607 | } |
@@ -4550,27 +4644,14 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4550 | * from the sending socket, otherwise use the kernel's sid */ | 4644 | * from the sending socket, otherwise use the kernel's sid */ |
4551 | sk = skb->sk; | 4645 | sk = skb->sk; |
4552 | if (sk == NULL) { | 4646 | if (sk == NULL) { |
4553 | switch (family) { | 4647 | if (skb->skb_iif) { |
4554 | case PF_INET: | 4648 | secmark_perm = PACKET__FORWARD_OUT; |
4555 | if (IPCB(skb)->flags & IPSKB_FORWARDED) | ||
4556 | secmark_perm = PACKET__FORWARD_OUT; | ||
4557 | else | ||
4558 | secmark_perm = PACKET__SEND; | ||
4559 | break; | ||
4560 | case PF_INET6: | ||
4561 | if (IP6CB(skb)->flags & IP6SKB_FORWARDED) | ||
4562 | secmark_perm = PACKET__FORWARD_OUT; | ||
4563 | else | ||
4564 | secmark_perm = PACKET__SEND; | ||
4565 | break; | ||
4566 | default: | ||
4567 | return NF_DROP; | ||
4568 | } | ||
4569 | if (secmark_perm == PACKET__FORWARD_OUT) { | ||
4570 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | 4649 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) |
4571 | return NF_DROP; | 4650 | return NF_DROP; |
4572 | } else | 4651 | } else { |
4652 | secmark_perm = PACKET__SEND; | ||
4573 | peer_sid = SECINITSID_KERNEL; | 4653 | peer_sid = SECINITSID_KERNEL; |
4654 | } | ||
4574 | } else { | 4655 | } else { |
4575 | struct sk_security_struct *sksec = sk->sk_security; | 4656 | struct sk_security_struct *sksec = sk->sk_security; |
4576 | peer_sid = sksec->sid; | 4657 | peer_sid = sksec->sid; |
@@ -4586,7 +4667,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4586 | if (secmark_active) | 4667 | if (secmark_active) |
4587 | if (avc_has_perm(peer_sid, skb->secmark, | 4668 | if (avc_has_perm(peer_sid, skb->secmark, |
4588 | SECCLASS_PACKET, secmark_perm, &ad)) | 4669 | SECCLASS_PACKET, secmark_perm, &ad)) |
4589 | return NF_DROP; | 4670 | return NF_DROP_ERR(-ECONNREFUSED); |
4590 | 4671 | ||
4591 | if (peerlbl_active) { | 4672 | if (peerlbl_active) { |
4592 | u32 if_sid; | 4673 | u32 if_sid; |
@@ -4596,13 +4677,13 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4596 | return NF_DROP; | 4677 | return NF_DROP; |
4597 | if (avc_has_perm(peer_sid, if_sid, | 4678 | if (avc_has_perm(peer_sid, if_sid, |
4598 | SECCLASS_NETIF, NETIF__EGRESS, &ad)) | 4679 | SECCLASS_NETIF, NETIF__EGRESS, &ad)) |
4599 | return NF_DROP; | 4680 | return NF_DROP_ERR(-ECONNREFUSED); |
4600 | 4681 | ||
4601 | if (sel_netnode_sid(addrp, family, &node_sid)) | 4682 | if (sel_netnode_sid(addrp, family, &node_sid)) |
4602 | return NF_DROP; | 4683 | return NF_DROP; |
4603 | if (avc_has_perm(peer_sid, node_sid, | 4684 | if (avc_has_perm(peer_sid, node_sid, |
4604 | SECCLASS_NODE, NODE__SENDTO, &ad)) | 4685 | SECCLASS_NODE, NODE__SENDTO, &ad)) |
4605 | return NF_DROP; | 4686 | return NF_DROP_ERR(-ECONNREFUSED); |
4606 | } | 4687 | } |
4607 | 4688 | ||
4608 | return NF_ACCEPT; | 4689 | return NF_ACCEPT; |
@@ -4645,6 +4726,7 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability) | |||
4645 | { | 4726 | { |
4646 | int err; | 4727 | int err; |
4647 | struct common_audit_data ad; | 4728 | struct common_audit_data ad; |
4729 | u32 sid; | ||
4648 | 4730 | ||
4649 | err = cap_netlink_recv(skb, capability); | 4731 | err = cap_netlink_recv(skb, capability); |
4650 | if (err) | 4732 | if (err) |
@@ -4653,8 +4735,9 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability) | |||
4653 | COMMON_AUDIT_DATA_INIT(&ad, CAP); | 4735 | COMMON_AUDIT_DATA_INIT(&ad, CAP); |
4654 | ad.u.cap = capability; | 4736 | ad.u.cap = capability; |
4655 | 4737 | ||
4656 | return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, | 4738 | security_task_getsecid(current, &sid); |
4657 | SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad); | 4739 | return avc_has_perm(sid, sid, SECCLASS_CAPABILITY, |
4740 | CAP_TO_MASK(capability), &ad); | ||
4658 | } | 4741 | } |
4659 | 4742 | ||
4660 | static int ipc_alloc_security(struct task_struct *task, | 4743 | static int ipc_alloc_security(struct task_struct *task, |
@@ -4824,7 +4907,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
4824 | * message queue this message will be stored in | 4907 | * message queue this message will be stored in |
4825 | */ | 4908 | */ |
4826 | rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, | 4909 | rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, |
4827 | &msec->sid); | 4910 | NULL, &msec->sid); |
4828 | if (rc) | 4911 | if (rc) |
4829 | return rc; | 4912 | return rc; |
4830 | } | 4913 | } |
@@ -5378,7 +5461,6 @@ static struct security_operations selinux_ops = { | |||
5378 | .ptrace_traceme = selinux_ptrace_traceme, | 5461 | .ptrace_traceme = selinux_ptrace_traceme, |
5379 | .capget = selinux_capget, | 5462 | .capget = selinux_capget, |
5380 | .capset = selinux_capset, | 5463 | .capset = selinux_capset, |
5381 | .sysctl = selinux_sysctl, | ||
5382 | .capable = selinux_capable, | 5464 | .capable = selinux_capable, |
5383 | .quotactl = selinux_quotactl, | 5465 | .quotactl = selinux_quotactl, |
5384 | .quota_on = selinux_quota_on, | 5466 | .quota_on = selinux_quota_on, |
@@ -5396,6 +5478,7 @@ static struct security_operations selinux_ops = { | |||
5396 | .sb_alloc_security = selinux_sb_alloc_security, | 5478 | .sb_alloc_security = selinux_sb_alloc_security, |
5397 | .sb_free_security = selinux_sb_free_security, | 5479 | .sb_free_security = selinux_sb_free_security, |
5398 | .sb_copy_data = selinux_sb_copy_data, | 5480 | .sb_copy_data = selinux_sb_copy_data, |
5481 | .sb_remount = selinux_sb_remount, | ||
5399 | .sb_kern_mount = selinux_sb_kern_mount, | 5482 | .sb_kern_mount = selinux_sb_kern_mount, |
5400 | .sb_show_options = selinux_sb_show_options, | 5483 | .sb_show_options = selinux_sb_show_options, |
5401 | .sb_statfs = selinux_sb_statfs, | 5484 | .sb_statfs = selinux_sb_statfs, |
@@ -5533,6 +5616,9 @@ static struct security_operations selinux_ops = { | |||
5533 | .inet_conn_request = selinux_inet_conn_request, | 5616 | .inet_conn_request = selinux_inet_conn_request, |
5534 | .inet_csk_clone = selinux_inet_csk_clone, | 5617 | .inet_csk_clone = selinux_inet_csk_clone, |
5535 | .inet_conn_established = selinux_inet_conn_established, | 5618 | .inet_conn_established = selinux_inet_conn_established, |
5619 | .secmark_relabel_packet = selinux_secmark_relabel_packet, | ||
5620 | .secmark_refcount_inc = selinux_secmark_refcount_inc, | ||
5621 | .secmark_refcount_dec = selinux_secmark_refcount_dec, | ||
5536 | .req_classify_flow = selinux_req_classify_flow, | 5622 | .req_classify_flow = selinux_req_classify_flow, |
5537 | .tun_dev_create = selinux_tun_dev_create, | 5623 | .tun_dev_create = selinux_tun_dev_create, |
5538 | .tun_dev_post_create = selinux_tun_dev_post_create, | 5624 | .tun_dev_post_create = selinux_tun_dev_post_create, |