diff options
author | James Morris <jmorris@namei.org> | 2011-03-15 18:41:17 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-03-15 18:41:17 -0400 |
commit | a002951c97ff8da49938c982a4c236bf2fafdc9f (patch) | |
tree | d43e7885ea7376df0a47a0fc8ceca66dc5bfa357 /security/selinux/hooks.c | |
parent | 521cb40b0c44418a4fd36dc633f575813d59a43d (diff) | |
parent | c151694b2c48d956ac8c8c59c6927f89cc29ef70 (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 350 |
1 files changed, 188 insertions, 162 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c8d699270687..d52a92507412 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,7 +73,6 @@ | |||
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> |
@@ -1120,39 +1122,35 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc | |||
1120 | } | 1122 | } |
1121 | 1123 | ||
1122 | #ifdef CONFIG_PROC_FS | 1124 | #ifdef CONFIG_PROC_FS |
1123 | static int selinux_proc_get_sid(struct proc_dir_entry *de, | 1125 | static int selinux_proc_get_sid(struct dentry *dentry, |
1124 | u16 tclass, | 1126 | u16 tclass, |
1125 | u32 *sid) | 1127 | u32 *sid) |
1126 | { | 1128 | { |
1127 | int buflen, rc; | 1129 | int rc; |
1128 | char *buffer, *path, *end; | 1130 | char *buffer, *path; |
1129 | 1131 | ||
1130 | buffer = (char *)__get_free_page(GFP_KERNEL); | 1132 | buffer = (char *)__get_free_page(GFP_KERNEL); |
1131 | if (!buffer) | 1133 | if (!buffer) |
1132 | return -ENOMEM; | 1134 | return -ENOMEM; |
1133 | 1135 | ||
1134 | buflen = PAGE_SIZE; | 1136 | path = dentry_path_raw(dentry, buffer, PAGE_SIZE); |
1135 | end = buffer+buflen; | 1137 | if (IS_ERR(path)) |
1136 | *--end = '\0'; | 1138 | rc = PTR_ERR(path); |
1137 | buflen--; | 1139 | else { |
1138 | path = end-1; | 1140 | /* each process gets a /proc/PID/ entry. Strip off the |
1139 | *path = '/'; | 1141 | * PID part to get a valid selinux labeling. |
1140 | while (de && de != de->parent) { | 1142 | * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ |
1141 | buflen -= de->namelen + 1; | 1143 | while (path[1] >= '0' && path[1] <= '9') { |
1142 | if (buflen < 0) | 1144 | path[1] = '/'; |
1143 | break; | 1145 | path++; |
1144 | end -= de->namelen; | 1146 | } |
1145 | memcpy(end, de->name, de->namelen); | 1147 | rc = security_genfs_sid("proc", path, tclass, sid); |
1146 | *--end = '/'; | ||
1147 | path = end; | ||
1148 | de = de->parent; | ||
1149 | } | 1148 | } |
1150 | rc = security_genfs_sid("proc", path, tclass, sid); | ||
1151 | free_page((unsigned long)buffer); | 1149 | free_page((unsigned long)buffer); |
1152 | return rc; | 1150 | return rc; |
1153 | } | 1151 | } |
1154 | #else | 1152 | #else |
1155 | static int selinux_proc_get_sid(struct proc_dir_entry *de, | 1153 | static int selinux_proc_get_sid(struct dentry *dentry, |
1156 | u16 tclass, | 1154 | u16 tclass, |
1157 | u32 *sid) | 1155 | u32 *sid) |
1158 | { | 1156 | { |
@@ -1300,10 +1298,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1300 | 1298 | ||
1301 | /* Try to obtain a transition SID. */ | 1299 | /* Try to obtain a transition SID. */ |
1302 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1300 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
1303 | rc = security_transition_sid(isec->task_sid, | 1301 | rc = security_transition_sid(isec->task_sid, sbsec->sid, |
1304 | sbsec->sid, | 1302 | isec->sclass, NULL, &sid); |
1305 | isec->sclass, | ||
1306 | &sid); | ||
1307 | if (rc) | 1303 | if (rc) |
1308 | goto out_unlock; | 1304 | goto out_unlock; |
1309 | isec->sid = sid; | 1305 | isec->sid = sid; |
@@ -1316,10 +1312,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1316 | isec->sid = sbsec->sid; | 1312 | isec->sid = sbsec->sid; |
1317 | 1313 | ||
1318 | if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { | 1314 | if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { |
1319 | struct proc_inode *proci = PROC_I(inode); | 1315 | if (opt_dentry) { |
1320 | if (proci->pde) { | ||
1321 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1316 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
1322 | rc = selinux_proc_get_sid(proci->pde, | 1317 | rc = selinux_proc_get_sid(opt_dentry, |
1323 | isec->sclass, | 1318 | isec->sclass, |
1324 | &sid); | 1319 | &sid); |
1325 | if (rc) | 1320 | if (rc) |
@@ -1578,7 +1573,7 @@ static int may_create(struct inode *dir, | |||
1578 | return rc; | 1573 | return rc; |
1579 | 1574 | ||
1580 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | 1575 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
1581 | rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); | 1576 | rc = security_transition_sid(sid, dsec->sid, tclass, NULL, &newsid); |
1582 | if (rc) | 1577 | if (rc) |
1583 | return rc; | 1578 | return rc; |
1584 | } | 1579 | } |
@@ -1862,82 +1857,6 @@ static int selinux_capable(struct task_struct *tsk, const struct cred *cred, | |||
1862 | return task_has_capability(tsk, cred, cap, audit); | 1857 | return task_has_capability(tsk, cred, cap, audit); |
1863 | } | 1858 | } |
1864 | 1859 | ||
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) | 1860 | static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) |
1942 | { | 1861 | { |
1943 | const struct cred *cred = current_cred(); | 1862 | const struct cred *cred = current_cred(); |
@@ -2060,7 +1979,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2060 | } else { | 1979 | } else { |
2061 | /* Check for a default transition on this program. */ | 1980 | /* Check for a default transition on this program. */ |
2062 | rc = security_transition_sid(old_tsec->sid, isec->sid, | 1981 | rc = security_transition_sid(old_tsec->sid, isec->sid, |
2063 | SECCLASS_PROCESS, &new_tsec->sid); | 1982 | SECCLASS_PROCESS, NULL, |
1983 | &new_tsec->sid); | ||
2064 | if (rc) | 1984 | if (rc) |
2065 | return rc; | 1985 | return rc; |
2066 | } | 1986 | } |
@@ -2443,6 +2363,91 @@ out: | |||
2443 | return rc; | 2363 | return rc; |
2444 | } | 2364 | } |
2445 | 2365 | ||
2366 | static int selinux_sb_remount(struct super_block *sb, void *data) | ||
2367 | { | ||
2368 | int rc, i, *flags; | ||
2369 | struct security_mnt_opts opts; | ||
2370 | char *secdata, **mount_options; | ||
2371 | struct superblock_security_struct *sbsec = sb->s_security; | ||
2372 | |||
2373 | if (!(sbsec->flags & SE_SBINITIALIZED)) | ||
2374 | return 0; | ||
2375 | |||
2376 | if (!data) | ||
2377 | return 0; | ||
2378 | |||
2379 | if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) | ||
2380 | return 0; | ||
2381 | |||
2382 | security_init_mnt_opts(&opts); | ||
2383 | secdata = alloc_secdata(); | ||
2384 | if (!secdata) | ||
2385 | return -ENOMEM; | ||
2386 | rc = selinux_sb_copy_data(data, secdata); | ||
2387 | if (rc) | ||
2388 | goto out_free_secdata; | ||
2389 | |||
2390 | rc = selinux_parse_opts_str(secdata, &opts); | ||
2391 | if (rc) | ||
2392 | goto out_free_secdata; | ||
2393 | |||
2394 | mount_options = opts.mnt_opts; | ||
2395 | flags = opts.mnt_opts_flags; | ||
2396 | |||
2397 | for (i = 0; i < opts.num_mnt_opts; i++) { | ||
2398 | u32 sid; | ||
2399 | size_t len; | ||
2400 | |||
2401 | if (flags[i] == SE_SBLABELSUPP) | ||
2402 | continue; | ||
2403 | len = strlen(mount_options[i]); | ||
2404 | rc = security_context_to_sid(mount_options[i], len, &sid); | ||
2405 | if (rc) { | ||
2406 | printk(KERN_WARNING "SELinux: security_context_to_sid" | ||
2407 | "(%s) failed for (dev %s, type %s) errno=%d\n", | ||
2408 | mount_options[i], sb->s_id, sb->s_type->name, rc); | ||
2409 | goto out_free_opts; | ||
2410 | } | ||
2411 | rc = -EINVAL; | ||
2412 | switch (flags[i]) { | ||
2413 | case FSCONTEXT_MNT: | ||
2414 | if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) | ||
2415 | goto out_bad_option; | ||
2416 | break; | ||
2417 | case CONTEXT_MNT: | ||
2418 | if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) | ||
2419 | goto out_bad_option; | ||
2420 | break; | ||
2421 | case ROOTCONTEXT_MNT: { | ||
2422 | struct inode_security_struct *root_isec; | ||
2423 | root_isec = sb->s_root->d_inode->i_security; | ||
2424 | |||
2425 | if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) | ||
2426 | goto out_bad_option; | ||
2427 | break; | ||
2428 | } | ||
2429 | case DEFCONTEXT_MNT: | ||
2430 | if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) | ||
2431 | goto out_bad_option; | ||
2432 | break; | ||
2433 | default: | ||
2434 | goto out_free_opts; | ||
2435 | } | ||
2436 | } | ||
2437 | |||
2438 | rc = 0; | ||
2439 | out_free_opts: | ||
2440 | security_free_mnt_opts(&opts); | ||
2441 | out_free_secdata: | ||
2442 | free_secdata(secdata); | ||
2443 | return rc; | ||
2444 | out_bad_option: | ||
2445 | printk(KERN_WARNING "SELinux: unable to change security options " | ||
2446 | "during remount (dev %s, type=%s)\n", sb->s_id, | ||
2447 | sb->s_type->name); | ||
2448 | goto out_free_opts; | ||
2449 | } | ||
2450 | |||
2446 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | 2451 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) |
2447 | { | 2452 | { |
2448 | const struct cred *cred = current_cred(); | 2453 | const struct cred *cred = current_cred(); |
@@ -2509,8 +2514,8 @@ static void selinux_inode_free_security(struct inode *inode) | |||
2509 | } | 2514 | } |
2510 | 2515 | ||
2511 | static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | 2516 | static int selinux_inode_init_security(struct inode *inode, struct inode *dir, |
2512 | char **name, void **value, | 2517 | const struct qstr *qstr, char **name, |
2513 | size_t *len) | 2518 | void **value, size_t *len) |
2514 | { | 2519 | { |
2515 | const struct task_security_struct *tsec = current_security(); | 2520 | const struct task_security_struct *tsec = current_security(); |
2516 | struct inode_security_struct *dsec; | 2521 | struct inode_security_struct *dsec; |
@@ -2531,7 +2536,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2531 | else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { | 2536 | else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
2532 | rc = security_transition_sid(sid, dsec->sid, | 2537 | rc = security_transition_sid(sid, dsec->sid, |
2533 | inode_mode_to_security_class(inode->i_mode), | 2538 | inode_mode_to_security_class(inode->i_mode), |
2534 | &newsid); | 2539 | qstr, &newsid); |
2535 | if (rc) { | 2540 | if (rc) { |
2536 | printk(KERN_WARNING "%s: " | 2541 | printk(KERN_WARNING "%s: " |
2537 | "security_transition_sid failed, rc=%d (dev=%s " | 2542 | "security_transition_sid failed, rc=%d (dev=%s " |
@@ -2932,16 +2937,47 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
2932 | unsigned long arg) | 2937 | unsigned long arg) |
2933 | { | 2938 | { |
2934 | const struct cred *cred = current_cred(); | 2939 | const struct cred *cred = current_cred(); |
2935 | u32 av = 0; | 2940 | int error = 0; |
2936 | 2941 | ||
2937 | if (_IOC_DIR(cmd) & _IOC_WRITE) | 2942 | switch (cmd) { |
2938 | av |= FILE__WRITE; | 2943 | case FIONREAD: |
2939 | if (_IOC_DIR(cmd) & _IOC_READ) | 2944 | /* fall through */ |
2940 | av |= FILE__READ; | 2945 | case FIBMAP: |
2941 | if (!av) | 2946 | /* fall through */ |
2942 | av = FILE__IOCTL; | 2947 | case FIGETBSZ: |
2948 | /* fall through */ | ||
2949 | case EXT2_IOC_GETFLAGS: | ||
2950 | /* fall through */ | ||
2951 | case EXT2_IOC_GETVERSION: | ||
2952 | error = file_has_perm(cred, file, FILE__GETATTR); | ||
2953 | break; | ||
2954 | |||
2955 | case EXT2_IOC_SETFLAGS: | ||
2956 | /* fall through */ | ||
2957 | case EXT2_IOC_SETVERSION: | ||
2958 | error = file_has_perm(cred, file, FILE__SETATTR); | ||
2959 | break; | ||
2960 | |||
2961 | /* sys_ioctl() checks */ | ||
2962 | case FIONBIO: | ||
2963 | /* fall through */ | ||
2964 | case FIOASYNC: | ||
2965 | error = file_has_perm(cred, file, 0); | ||
2966 | break; | ||
2943 | 2967 | ||
2944 | return file_has_perm(cred, file, av); | 2968 | case KDSKBENT: |
2969 | case KDSKBSENT: | ||
2970 | error = task_has_capability(current, cred, CAP_SYS_TTY_CONFIG, | ||
2971 | SECURITY_CAP_AUDIT); | ||
2972 | break; | ||
2973 | |||
2974 | /* default case assumes that the command will go | ||
2975 | * to the file's ioctl() function. | ||
2976 | */ | ||
2977 | default: | ||
2978 | error = file_has_perm(cred, file, FILE__IOCTL); | ||
2979 | } | ||
2980 | return error; | ||
2945 | } | 2981 | } |
2946 | 2982 | ||
2947 | static int default_noexec; | 2983 | static int default_noexec; |
@@ -3644,9 +3680,16 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) | |||
3644 | 3680 | ||
3645 | /* socket security operations */ | 3681 | /* socket security operations */ |
3646 | 3682 | ||
3647 | static u32 socket_sockcreate_sid(const struct task_security_struct *tsec) | 3683 | static int socket_sockcreate_sid(const struct task_security_struct *tsec, |
3684 | u16 secclass, u32 *socksid) | ||
3648 | { | 3685 | { |
3649 | return tsec->sockcreate_sid ? : tsec->sid; | 3686 | if (tsec->sockcreate_sid > SECSID_NULL) { |
3687 | *socksid = tsec->sockcreate_sid; | ||
3688 | return 0; | ||
3689 | } | ||
3690 | |||
3691 | return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL, | ||
3692 | socksid); | ||
3650 | } | 3693 | } |
3651 | 3694 | ||
3652 | static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) | 3695 | static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) |
@@ -3670,12 +3713,16 @@ static int selinux_socket_create(int family, int type, | |||
3670 | const struct task_security_struct *tsec = current_security(); | 3713 | const struct task_security_struct *tsec = current_security(); |
3671 | u32 newsid; | 3714 | u32 newsid; |
3672 | u16 secclass; | 3715 | u16 secclass; |
3716 | int rc; | ||
3673 | 3717 | ||
3674 | if (kern) | 3718 | if (kern) |
3675 | return 0; | 3719 | return 0; |
3676 | 3720 | ||
3677 | newsid = socket_sockcreate_sid(tsec); | ||
3678 | secclass = socket_type_to_security_class(family, type, protocol); | 3721 | secclass = socket_type_to_security_class(family, type, protocol); |
3722 | rc = socket_sockcreate_sid(tsec, secclass, &newsid); | ||
3723 | if (rc) | ||
3724 | return rc; | ||
3725 | |||
3679 | return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); | 3726 | return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); |
3680 | } | 3727 | } |
3681 | 3728 | ||
@@ -3687,12 +3734,16 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
3687 | struct sk_security_struct *sksec; | 3734 | struct sk_security_struct *sksec; |
3688 | int err = 0; | 3735 | int err = 0; |
3689 | 3736 | ||
3737 | isec->sclass = socket_type_to_security_class(family, type, protocol); | ||
3738 | |||
3690 | if (kern) | 3739 | if (kern) |
3691 | isec->sid = SECINITSID_KERNEL; | 3740 | isec->sid = SECINITSID_KERNEL; |
3692 | else | 3741 | else { |
3693 | isec->sid = socket_sockcreate_sid(tsec); | 3742 | err = socket_sockcreate_sid(tsec, isec->sclass, &(isec->sid)); |
3743 | if (err) | ||
3744 | return err; | ||
3745 | } | ||
3694 | 3746 | ||
3695 | isec->sclass = socket_type_to_security_class(family, type, protocol); | ||
3696 | isec->initialized = 1; | 3747 | isec->initialized = 1; |
3697 | 3748 | ||
3698 | if (sock->sk) { | 3749 | if (sock->sk) { |
@@ -4002,7 +4053,6 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4002 | { | 4053 | { |
4003 | int err = 0; | 4054 | int err = 0; |
4004 | struct sk_security_struct *sksec = sk->sk_security; | 4055 | struct sk_security_struct *sksec = sk->sk_security; |
4005 | u32 peer_sid; | ||
4006 | u32 sk_sid = sksec->sid; | 4056 | u32 sk_sid = sksec->sid; |
4007 | struct common_audit_data ad; | 4057 | struct common_audit_data ad; |
4008 | char *addrp; | 4058 | char *addrp; |
@@ -4021,20 +4071,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4021 | return err; | 4071 | return err; |
4022 | } | 4072 | } |
4023 | 4073 | ||
4024 | if (selinux_policycap_netpeer) { | 4074 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); |
4025 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4075 | if (err) |
4026 | if (err) | 4076 | return err; |
4027 | return err; | 4077 | 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 | 4078 | ||
4039 | return err; | 4079 | return err; |
4040 | } | 4080 | } |
@@ -4529,9 +4569,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4529 | SECCLASS_PACKET, PACKET__SEND, &ad)) | 4569 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
4530 | return NF_DROP_ERR(-ECONNREFUSED); | 4570 | return NF_DROP_ERR(-ECONNREFUSED); |
4531 | 4571 | ||
4532 | if (selinux_policycap_netpeer) | 4572 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
4533 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) | 4573 | return NF_DROP_ERR(-ECONNREFUSED); |
4534 | return NF_DROP_ERR(-ECONNREFUSED); | ||
4535 | 4574 | ||
4536 | return NF_ACCEPT; | 4575 | return NF_ACCEPT; |
4537 | } | 4576 | } |
@@ -4574,27 +4613,14 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4574 | * from the sending socket, otherwise use the kernel's sid */ | 4613 | * from the sending socket, otherwise use the kernel's sid */ |
4575 | sk = skb->sk; | 4614 | sk = skb->sk; |
4576 | if (sk == NULL) { | 4615 | if (sk == NULL) { |
4577 | switch (family) { | 4616 | if (skb->skb_iif) { |
4578 | case PF_INET: | 4617 | 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)) | 4618 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) |
4595 | return NF_DROP; | 4619 | return NF_DROP; |
4596 | } else | 4620 | } else { |
4621 | secmark_perm = PACKET__SEND; | ||
4597 | peer_sid = SECINITSID_KERNEL; | 4622 | peer_sid = SECINITSID_KERNEL; |
4623 | } | ||
4598 | } else { | 4624 | } else { |
4599 | struct sk_security_struct *sksec = sk->sk_security; | 4625 | struct sk_security_struct *sksec = sk->sk_security; |
4600 | peer_sid = sksec->sid; | 4626 | peer_sid = sksec->sid; |
@@ -4848,7 +4874,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
4848 | * message queue this message will be stored in | 4874 | * message queue this message will be stored in |
4849 | */ | 4875 | */ |
4850 | rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, | 4876 | rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, |
4851 | &msec->sid); | 4877 | NULL, &msec->sid); |
4852 | if (rc) | 4878 | if (rc) |
4853 | return rc; | 4879 | return rc; |
4854 | } | 4880 | } |
@@ -5402,7 +5428,6 @@ static struct security_operations selinux_ops = { | |||
5402 | .ptrace_traceme = selinux_ptrace_traceme, | 5428 | .ptrace_traceme = selinux_ptrace_traceme, |
5403 | .capget = selinux_capget, | 5429 | .capget = selinux_capget, |
5404 | .capset = selinux_capset, | 5430 | .capset = selinux_capset, |
5405 | .sysctl = selinux_sysctl, | ||
5406 | .capable = selinux_capable, | 5431 | .capable = selinux_capable, |
5407 | .quotactl = selinux_quotactl, | 5432 | .quotactl = selinux_quotactl, |
5408 | .quota_on = selinux_quota_on, | 5433 | .quota_on = selinux_quota_on, |
@@ -5420,6 +5445,7 @@ static struct security_operations selinux_ops = { | |||
5420 | .sb_alloc_security = selinux_sb_alloc_security, | 5445 | .sb_alloc_security = selinux_sb_alloc_security, |
5421 | .sb_free_security = selinux_sb_free_security, | 5446 | .sb_free_security = selinux_sb_free_security, |
5422 | .sb_copy_data = selinux_sb_copy_data, | 5447 | .sb_copy_data = selinux_sb_copy_data, |
5448 | .sb_remount = selinux_sb_remount, | ||
5423 | .sb_kern_mount = selinux_sb_kern_mount, | 5449 | .sb_kern_mount = selinux_sb_kern_mount, |
5424 | .sb_show_options = selinux_sb_show_options, | 5450 | .sb_show_options = selinux_sb_show_options, |
5425 | .sb_statfs = selinux_sb_statfs, | 5451 | .sb_statfs = selinux_sb_statfs, |