diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/apparmor/include/apparmor.h | 4 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 20 | ||||
-rw-r--r-- | security/apparmor/path.c | 2 | ||||
-rw-r--r-- | security/capability.c | 27 | ||||
-rw-r--r-- | security/commoncap.c | 6 | ||||
-rw-r--r-- | security/inode.c | 2 | ||||
-rw-r--r-- | security/integrity/Kconfig | 4 | ||||
-rw-r--r-- | security/integrity/evm/Kconfig | 2 | ||||
-rw-r--r-- | security/integrity/ima/Kconfig | 1 | ||||
-rw-r--r-- | security/keys/Kconfig | 18 | ||||
-rw-r--r-- | security/keys/proc.c | 8 | ||||
-rw-r--r-- | security/keys/request_key.c | 1 | ||||
-rw-r--r-- | security/security.c | 36 | ||||
-rw-r--r-- | security/selinux/avc.c | 5 | ||||
-rw-r--r-- | security/selinux/hooks.c | 110 | ||||
-rw-r--r-- | security/selinux/include/classmap.h | 2 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 52 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 8 | ||||
-rw-r--r-- | security/smack/Kconfig | 12 | ||||
-rw-r--r-- | security/smack/Makefile | 1 | ||||
-rw-r--r-- | security/smack/smack.h | 11 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 219 | ||||
-rw-r--r-- | security/smack/smack_netfilter.c | 96 | ||||
-rw-r--r-- | security/tomoyo/Kconfig | 1 | ||||
-rw-r--r-- | security/tomoyo/file.c | 4 |
25 files changed, 458 insertions, 194 deletions
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 97130f8..e4ea626 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -112,9 +112,9 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, return aa_dfa_next(dfa, start, 0); } -static inline bool mediated_filesystem(struct inode *inode) +static inline bool mediated_filesystem(struct dentry *dentry) { - return !(inode->i_sb->s_flags & MS_NOUSER); + return !(dentry->d_sb->s_flags & MS_NOUSER); } #endif /* __APPARMOR_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 65ca451..107db88 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -226,7 +226,7 @@ static int common_perm_rm(int op, struct path *dir, struct inode *inode = dentry->d_inode; struct path_cond cond = { }; - if (!inode || !dir->mnt || !mediated_filesystem(inode)) + if (!inode || !dir->mnt || !mediated_filesystem(dentry)) return 0; cond.uid = inode->i_uid; @@ -250,7 +250,7 @@ static int common_perm_create(int op, struct path *dir, struct dentry *dentry, { struct path_cond cond = { current_fsuid(), mode }; - if (!dir->mnt || !mediated_filesystem(dir->dentry->d_inode)) + if (!dir->mnt || !mediated_filesystem(dir->dentry)) return 0; return common_perm_dir_dentry(op, dir, dentry, mask, &cond); @@ -285,7 +285,7 @@ static int apparmor_path_truncate(struct path *path) path->dentry->d_inode->i_mode }; - if (!path->mnt || !mediated_filesystem(path->dentry->d_inode)) + if (!path->mnt || !mediated_filesystem(path->dentry)) return 0; return common_perm(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE, @@ -305,7 +305,7 @@ static int apparmor_path_link(struct dentry *old_dentry, struct path *new_dir, struct aa_profile *profile; int error = 0; - if (!mediated_filesystem(old_dentry->d_inode)) + if (!mediated_filesystem(old_dentry)) return 0; profile = aa_current_profile(); @@ -320,7 +320,7 @@ static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry, struct aa_profile *profile; int error = 0; - if (!mediated_filesystem(old_dentry->d_inode)) + if (!mediated_filesystem(old_dentry)) return 0; profile = aa_current_profile(); @@ -346,7 +346,7 @@ static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry, static int apparmor_path_chmod(struct path *path, umode_t mode) { - if (!mediated_filesystem(path->dentry->d_inode)) + if (!mediated_filesystem(path->dentry)) return 0; return common_perm_mnt_dentry(OP_CHMOD, path->mnt, path->dentry, AA_MAY_CHMOD); @@ -358,7 +358,7 @@ static int apparmor_path_chown(struct path *path, kuid_t uid, kgid_t gid) path->dentry->d_inode->i_mode }; - if (!mediated_filesystem(path->dentry->d_inode)) + if (!mediated_filesystem(path->dentry)) return 0; return common_perm(OP_CHOWN, path, AA_MAY_CHOWN, &cond); @@ -366,7 +366,7 @@ static int apparmor_path_chown(struct path *path, kuid_t uid, kgid_t gid) static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) { - if (!mediated_filesystem(dentry->d_inode)) + if (!mediated_filesystem(dentry)) return 0; return common_perm_mnt_dentry(OP_GETATTR, mnt, dentry, @@ -379,7 +379,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) struct aa_profile *profile; int error = 0; - if (!mediated_filesystem(file_inode(file))) + if (!mediated_filesystem(file->f_path.dentry)) return 0; /* If in exec, permission is handled by bprm hooks. @@ -432,7 +432,7 @@ static int common_file_perm(int op, struct file *file, u32 mask) BUG_ON(!fprofile); if (!file->f_path.mnt || - !mediated_filesystem(file_inode(file))) + !mediated_filesystem(file->f_path.dentry)) return 0; profile = __aa_current_profile(); diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 35b394a..71e0e3a 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -114,7 +114,7 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, * security_path hooks as a deleted dentry except without an inode * allocated. */ - if (d_unlinked(path->dentry) && path->dentry->d_inode && + if (d_unlinked(path->dentry) && d_is_positive(path->dentry) && !(flags & PATH_MEDIATE_DELETED)) { error = -ENOENT; goto out; diff --git a/security/capability.c b/security/capability.c index d68c57a..070dd46 100644 --- a/security/capability.c +++ b/security/capability.c @@ -12,6 +12,29 @@ #include <linux/security.h> +static int cap_binder_set_context_mgr(struct task_struct *mgr) +{ + return 0; +} + +static int cap_binder_transaction(struct task_struct *from, + struct task_struct *to) +{ + return 0; +} + +static int cap_binder_transfer_binder(struct task_struct *from, + struct task_struct *to) +{ + return 0; +} + +static int cap_binder_transfer_file(struct task_struct *from, + struct task_struct *to, struct file *file) +{ + return 0; +} + static int cap_syslog(int type) { return 0; @@ -930,6 +953,10 @@ static void cap_audit_rule_free(void *lsmrule) void __init security_fixup_ops(struct security_operations *ops) { + set_to_cap_if_null(ops, binder_set_context_mgr); + set_to_cap_if_null(ops, binder_transaction); + set_to_cap_if_null(ops, binder_transfer_binder); + set_to_cap_if_null(ops, binder_transfer_file); set_to_cap_if_null(ops, ptrace_access_check); set_to_cap_if_null(ops, ptrace_traceme); set_to_cap_if_null(ops, capget); diff --git a/security/commoncap.c b/security/commoncap.c index 2915d85..f66713b 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -434,7 +434,6 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data */ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap) { - struct dentry *dentry; int rc = 0; struct cpu_vfs_cap_data vcaps; @@ -446,9 +445,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) return 0; - dentry = dget(bprm->file->f_path.dentry); - - rc = get_vfs_caps_from_disk(dentry, &vcaps); + rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); if (rc < 0) { if (rc == -EINVAL) printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n", @@ -464,7 +461,6 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c __func__, rc, bprm->filename); out: - dput(dentry); if (rc) bprm_clear_caps(bprm); diff --git a/security/inode.c b/security/inode.c index 8e7ca62..131a3c4 100644 --- a/security/inode.c +++ b/security/inode.c @@ -203,7 +203,7 @@ void securityfs_remove(struct dentry *dentry) mutex_lock(&parent->d_inode->i_mutex); if (positive(dentry)) { if (dentry->d_inode) { - if (S_ISDIR(dentry->d_inode->i_mode)) + if (d_is_dir(dentry)) simple_rmdir(parent->d_inode, dentry); else simple_unlink(parent->d_inode, dentry); diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index b76235a..73c457b 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -16,7 +16,7 @@ config INTEGRITY if INTEGRITY config INTEGRITY_SIGNATURE - boolean "Digital signature verification using multiple keyrings" + bool "Digital signature verification using multiple keyrings" depends on KEYS default n select SIGNATURE @@ -30,7 +30,7 @@ config INTEGRITY_SIGNATURE usually only added from initramfs. config INTEGRITY_ASYMMETRIC_KEYS - boolean "Enable asymmetric keys support" + bool "Enable asymmetric keys support" depends on INTEGRITY_SIGNATURE default n select ASYMMETRIC_KEY_TYPE diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index df586fa..bf19723 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -1,5 +1,5 @@ config EVM - boolean "EVM support" + bool "EVM support" select KEYS select ENCRYPTED_KEYS select CRYPTO_HMAC diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 57515bc..df30334 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -126,7 +126,6 @@ config IMA_TRUSTED_KEYRING bool "Require all keys on the .ima keyring be signed" depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING depends on INTEGRITY_ASYMMETRIC_KEYS - select KEYS_DEBUG_PROC_KEYS default y help This option requires that all keys added to the .ima diff --git a/security/keys/Kconfig b/security/keys/Kconfig index a4f3f8c..72483b8 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -80,21 +80,3 @@ config ENCRYPTED_KEYS Userspace only ever sees/stores encrypted blobs. If you are unsure as to whether this is required, answer N. - -config KEYS_DEBUG_PROC_KEYS - bool "Enable the /proc/keys file by which keys may be viewed" - depends on KEYS - help - This option turns on support for the /proc/keys file - through which - can be listed all the keys on the system that are viewable by the - reading process. - - The only keys included in the list are those that grant View - permission to the reading process whether or not it possesses them. - Note that LSM security checks are still performed, and may further - filter out keys that the current process is not authorised to view. - - Only key attributes are listed here; key payloads are not included in - the resulting table. - - If you are unsure as to whether this is required, answer N. diff --git a/security/keys/proc.c b/security/keys/proc.c index 972eeb3..f0611a6 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -18,7 +18,6 @@ #include <asm/errno.h> #include "internal.h" -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS static int proc_keys_open(struct inode *inode, struct file *file); static void *proc_keys_start(struct seq_file *p, loff_t *_pos); static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos); @@ -38,7 +37,6 @@ static const struct file_operations proc_keys_fops = { .llseek = seq_lseek, .release = seq_release, }; -#endif static int proc_key_users_open(struct inode *inode, struct file *file); static void *proc_key_users_start(struct seq_file *p, loff_t *_pos); @@ -67,11 +65,9 @@ static int __init key_proc_init(void) { struct proc_dir_entry *p; -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS p = proc_create("keys", 0, NULL, &proc_keys_fops); if (!p) panic("Cannot create /proc/keys\n"); -#endif p = proc_create("key-users", 0, NULL, &proc_key_users_fops); if (!p) @@ -86,8 +82,6 @@ __initcall(key_proc_init); * Implement "/proc/keys" to provide a list of the keys on the system that * grant View permission to the caller. */ -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS - static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n) { struct user_namespace *user_ns = seq_user_ns(p); @@ -275,8 +269,6 @@ static int proc_keys_show(struct seq_file *m, void *v) return 0; } -#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ - static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n) { while (n) { diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 0c7aea4..486ef6f 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -414,6 +414,7 @@ link_check_failed: link_prealloc_failed: mutex_unlock(&user->cons_lock); + key_put(key); kleave(" = %d [prelink]", ret); return ret; diff --git a/security/security.c b/security/security.c index 18b35c6..e81d5bb 100644 --- a/security/security.c +++ b/security/security.c @@ -135,6 +135,29 @@ int __init register_security(struct security_operations *ops) /* Security operations */ +int security_binder_set_context_mgr(struct task_struct *mgr) +{ + return security_ops->binder_set_context_mgr(mgr); +} + +int security_binder_transaction(struct task_struct *from, + struct task_struct *to) +{ + return security_ops->binder_transaction(from, to); +} + +int security_binder_transfer_binder(struct task_struct *from, + struct task_struct *to) +{ + return security_ops->binder_transfer_binder(from, to); +} + +int security_binder_transfer_file(struct task_struct *from, + struct task_struct *to, struct file *file) +{ + return security_ops->binder_transfer_file(from, to, file); +} + int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { #ifdef CONFIG_SECURITY_YAMA_STACKED @@ -726,16 +749,15 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot) return prot | PROT_EXEC; /* * ditto if it's not on noexec mount, except that on !MMU we need - * BDI_CAP_EXEC_MMAP (== VM_MAYEXEC) in this case + * NOMMU_MAP_EXEC (== VM_MAYEXEC) in this case */ if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) { #ifndef CONFIG_MMU - unsigned long caps = 0; - struct address_space *mapping = file->f_mapping; - if (mapping && mapping->backing_dev_info) - caps = mapping->backing_dev_info->capabilities; - if (!(caps & BDI_CAP_EXEC_MAP)) - return prot; + if (file->f_op->mmap_capabilities) { + unsigned caps = file->f_op->mmap_capabilities(file); + if (!(caps & NOMMU_MAP_EXEC)) + return prot; + } #endif return prot | PROT_EXEC; } diff --git a/security/selinux/avc.c b/security/selinux/avc.c index a18f1fa..afcc0ae 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -517,11 +517,6 @@ out: return rc; } -static inline int avc_sidcmp(u32 x, u32 y) -{ - return (x == y || x == SECSID_WILD || y == SECSID_WILD); -} - /** * avc_update_node Update an AVC entry * @event : Updating event diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6da7532..4d1a541 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -401,23 +401,14 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) { struct superblock_security_struct *sbsec = sb->s_security; - if (sbsec->behavior == SECURITY_FS_USE_XATTR || - sbsec->behavior == SECURITY_FS_USE_TRANS || - sbsec->behavior == SECURITY_FS_USE_TASK) - return 1; - - /* Special handling for sysfs. Is genfs but also has setxattr handler*/ - if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) - return 1; - - /* - * Special handling for rootfs. Is genfs but supports - * setting SELinux context on in-core inodes. - */ - if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0) - return 1; - - return 0; + return sbsec->behavior == SECURITY_FS_USE_XATTR || + sbsec->behavior == SECURITY_FS_USE_TRANS || + sbsec->behavior == SECURITY_FS_USE_TASK || + /* Special handling. Genfs but also in-core setxattr handler */ + !strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "rootfs"); } static int sb_finish_set_opts(struct super_block *sb) @@ -456,10 +447,6 @@ static int sb_finish_set_opts(struct super_block *sb) if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", sb->s_id, sb->s_type->name); - else - printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", - sb->s_id, sb->s_type->name, - labeling_behaviors[sbsec->behavior-1]); sbsec->flags |= SE_SBINITIALIZED; if (selinux_is_sblabel_mnt(sb)) @@ -1812,7 +1799,7 @@ static inline int may_rename(struct inode *old_dir, old_dsec = old_dir->i_security; old_isec = old_dentry->d_inode->i_security; - old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); + old_is_dir = d_is_dir(old_dentry); new_dsec = new_dir->i_security; ad.type = LSM_AUDIT_DATA_DENTRY; @@ -1835,14 +1822,14 @@ static inline int may_rename(struct inode *old_dir, ad.u.dentry = new_dentry; av = DIR__ADD_NAME | DIR__SEARCH; - if (new_dentry->d_inode) + if (d_is_positive(new_dentry)) av |= DIR__REMOVE_NAME; rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; - if (new_dentry->d_inode) { + if (d_is_positive(new_dentry)) { new_isec = new_dentry->d_inode->i_security; - new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode); + new_is_dir = d_is_dir(new_dentry); rc = avc_has_perm(sid, new_isec->sid, new_isec->sclass, (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); @@ -1933,6 +1920,74 @@ static inline u32 open_file_to_av(struct file *file) /* Hook functions begin here. */ +static int selinux_binder_set_context_mgr(struct task_struct *mgr) +{ + u32 mysid = current_sid(); + u32 mgrsid = task_sid(mgr); + + return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, + BINDER__SET_CONTEXT_MGR, NULL); +} + +static int selinux_binder_transaction(struct task_struct *from, + struct task_struct *to) +{ + u32 mysid = current_sid(); + u32 fromsid = task_sid(from); + u32 tosid = task_sid(to); + int rc; + + if (mysid != fromsid) { + rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, + BINDER__IMPERSONATE, NULL); + if (rc) + return rc; + } + + return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, + NULL); +} + +static int selinux_binder_transfer_binder(struct task_struct *from, + struct task_struct *to) +{ + u32 fromsid = task_sid(from); + u32 tosid = task_sid(to); + + return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, + NULL); +} + +static int selinux_binder_transfer_file(struct task_struct *from, + struct task_struct *to, + struct file *file) +{ + u32 sid = task_sid(to); + struct file_security_struct *fsec = file->f_security; + struct inode *inode = file->f_path.dentry->d_inode; + struct inode_security_struct *isec = inode->i_security; + struct common_audit_data ad; + int rc; + + ad.type = LSM_AUDIT_DATA_PATH; + ad.u.path = file->f_path; + + if (sid != fsec->sid) { + rc = avc_has_perm(sid, fsec->sid, + SECCLASS_FD, + FD__USE, + &ad); + if (rc) + return rc; + } + + if (unlikely(IS_PRIVATE(inode))) + return 0; + + return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), + &ad); +} + static int selinux_ptrace_access_check(struct task_struct *child, unsigned int mode) { @@ -5810,6 +5865,11 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) static struct security_operations selinux_ops = { .name = "selinux", + .binder_set_context_mgr = selinux_binder_set_context_mgr, + .binder_transaction = selinux_binder_transaction, + .binder_transfer_binder = selinux_binder_transfer_binder, + .binder_transfer_file = selinux_binder_transfer_file, + .ptrace_access_check = selinux_ptrace_access_check, .ptrace_traceme = selinux_ptrace_traceme, .capget = selinux_capget, diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index be491a7..eccd61b 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -151,5 +151,7 @@ struct security_class_mapping secclass_map[] = { { "kernel_service", { "use_as_override", "create_files_as", NULL } }, { "tun_socket", { COMMON_SOCK_PERMS, "attach_queue", NULL } }, + { "binder", { "impersonate", "call", "set_context_mgr", "transfer", + NULL } }, { NULL } }; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 33db1ad..1684bcc 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1195,30 +1195,8 @@ static const struct file_operations sel_commit_bools_ops = { static void sel_remove_entries(struct dentry *de) { - struct list_head *node; - - spin_lock(&de->d_lock); - node = de->d_subdirs.next; - while (node != &de->d_subdirs) { - struct dentry *d = list_entry(node, struct dentry, d_child); - - spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); - list_del_init(node); - - if (d->d_inode) { - dget_dlock(d); - spin_unlock(&de->d_lock); - spin_unlock(&d->d_lock); - d_delete(d); - simple_unlink(de->d_inode, d); - dput(d); - spin_lock(&de->d_lock); - } else - spin_unlock(&d->d_lock); - node = de->d_subdirs.next; - } - - spin_unlock(&de->d_lock); + d_genocide(de); + shrink_dcache_parent(de); } #define BOOL_DIR_NAME "booleans" @@ -1668,37 +1646,13 @@ static int sel_make_class_dir_entries(char *classname, int index, return rc; } -static void sel_remove_classes(void) -{ - struct list_head *class_node; - - list_for_each(class_node, &class_dir->d_subdirs) { - struct dentry *class_subdir = list_entry(class_node, - struct dentry, d_child); - struct list_head *class_subdir_node; - - list_for_each(class_subdir_node, &class_subdir->d_subdirs) { - struct dentry *d = list_entry(class_subdir_node, - struct dentry, d_child); - - if (d->d_inode) - if (d->d_inode->i_mode & S_IFDIR) - sel_remove_entries(d); - } - - sel_remove_entries(class_subdir); - } - - sel_remove_entries(class_dir); -} - static int sel_make_classes(void) { int rc, nclasses, i; char **classes; /* delete any existing entries */ - sel_remove_classes(); + sel_remove_entries(class_dir); rc = security_get_classes(&classes, &nclasses); if (rc) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index bc2a586..74aa224 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -289,12 +289,16 @@ static int policydb_init(struct policydb *p) goto out; p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); - if (!p->filename_trans) + if (!p->filename_trans) { + rc = -ENOMEM; goto out; + } p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); - if (!p->range_tr) + if (!p->range_tr) { + rc = -ENOMEM; goto out; + } ebitmap_init(&p->filename_trans_ttypes); ebitmap_init(&p->policycaps); diff --git a/security/smack/Kconfig b/security/smack/Kconfig index b065f97..271adae 100644 --- a/security/smack/Kconfig +++ b/security/smack/Kconfig @@ -28,3 +28,15 @@ config SECURITY_SMACK_BRINGUP access rule set once the behavior is well understood. This is a superior mechanism to the oft abused "permissive" mode of other systems. + If you are unsure how to answer this question, answer N. + +config SECURITY_SMACK_NETFILTER + bool "Packet marking using secmarks for netfilter" + depends on SECURITY_SMACK + depends on NETWORK_SECMARK + depends on NETFILTER + default n + help + This enables security marking of network packets using + Smack labels. + If you are unsure how to answer this question, answer N. diff --git a/security/smack/Makefile b/security/smack/Makefile index 67a63aa..ee2ebd5 100644 --- a/security/smack/Makefile +++ b/security/smack/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_SECURITY_SMACK) := smack.o smack-y := smack_lsm.o smack_access.o smackfs.o +smack-$(CONFIG_SECURITY_SMACK_NETFILTER) += smack_netfilter.o diff --git a/security/smack/smack.h b/security/smack/smack.h index b828a37..67ccb7b 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -248,6 +248,7 @@ struct smack_known *smk_find_entry(const char *); /* * Shared data. */ +extern int smack_enabled; extern int smack_cipso_direct; extern int smack_cipso_mapped; extern struct smack_known *smack_net_ambient; @@ -298,6 +299,16 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp) return tsp->smk_task; } +static inline struct smack_known *smk_of_task_struct(const struct task_struct *t) +{ + struct smack_known *skp; + + rcu_read_lock(); + skp = smk_of_task(__task_cred(t)->security); + rcu_read_unlock(); + return skp; +} + /* * Present a pointer to the forked smack label entry in an task blob. */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index f1b17a4..c934311 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -43,8 +43,6 @@ #include <linux/binfmts.h> #include "smack.h" -#define task_security(task) (task_cred_xxx((task), security)) - #define TRANS_TRUE "TRUE" #define TRANS_TRUE_SIZE 4 @@ -52,8 +50,11 @@ #define SMK_RECEIVING 1 #define SMK_SENDING 2 +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) LIST_HEAD(smk_ipv6_port_list); +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ static struct kmem_cache *smack_inode_cache; +int smack_enabled; #ifdef CONFIG_SECURITY_SMACK_BRINGUP static void smk_bu_mode(int mode, char *s) @@ -120,7 +121,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp, static int smk_bu_task(struct task_struct *otp, int mode, int rc) { struct task_smack *tsp = current_security(); - struct task_smack *otsp = task_security(otp); + struct smack_known *smk_task = smk_of_task_struct(otp); char acc[SMK_NUM_ACCESS_TYPE + 1]; if (rc <= 0) @@ -128,7 +129,7 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc) smk_bu_mode(mode, acc); pr_info("Smack Bringup: (%s %s %s) %s to %s\n", - tsp->smk_task->smk_known, otsp->smk_task->smk_known, acc, + tsp->smk_task->smk_known, smk_task->smk_known, acc, current->comm, otp->comm); return 0; } @@ -160,7 +161,7 @@ static int smk_bu_file(struct file *file, int mode, int rc) { struct task_smack *tsp = current_security(); struct smack_known *sskp = tsp->smk_task; - struct inode *inode = file->f_inode; + struct inode *inode = file_inode(file); char acc[SMK_NUM_ACCESS_TYPE + 1]; if (rc <= 0) @@ -168,7 +169,7 @@ static int smk_bu_file(struct file *file, int mode, int rc) smk_bu_mode(mode, acc); pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n", - sskp->smk_known, (char *)file->f_security, acc, + sskp->smk_known, smk_of_inode(inode)->smk_known, acc, inode->i_sb->s_id, inode->i_ino, file, current->comm); return 0; @@ -202,6 +203,7 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file, /** * smk_fetch - Fetch the smack label from a file. + * @name: type of the label (attribute) * @ip: a pointer to the inode * @dp: a pointer to the dentry * @@ -254,7 +256,9 @@ struct inode_smack *new_inode_smack(struct smack_known *skp) /** * new_task_smack - allocate a task security blob - * @smack: a pointer to the Smack label to use in the blob + * @task: a pointer to the Smack label for the running task + * @forked: a pointer to the Smack label for the forked task + * @gfp: type of the memory for the allocation * * Returns the new blob or NULL if there's no memory available */ @@ -277,8 +281,9 @@ static struct task_smack *new_task_smack(struct smack_known *task, /** * smk_copy_rules - copy a rule set - * @nhead - new rules header pointer - * @ohead - old rules header pointer + * @nhead: new rules header pointer + * @ohead: old rules header pointer + * @gfp: type of the memory for the allocation * * Returns 0 on success, -ENOMEM on error */ @@ -345,7 +350,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, saip = &ad; } - tsp = task_security(tracer); + rcu_read_lock(); + tsp = __task_cred(tracer)->security; tracer_known = smk_of_task(tsp); if ((mode & PTRACE_MODE_ATTACH) && @@ -365,11 +371,14 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, tracee_known->smk_known, 0, rc, saip); + rcu_read_unlock(); return rc; } /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */ rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip); + + rcu_read_unlock(); return rc; } @@ -396,7 +405,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) if (rc != 0) return rc; - skp = smk_of_task(task_security(ctp)); + skp = smk_of_task_struct(ctp); rc = smk_ptrace_rule_check(current, skp, mode, __func__); return rc; @@ -796,7 +805,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, if (name) *name = XATTR_SMACK_SUFFIX; - if (value) { + if (value && len) { rcu_read_lock(); may = smk_access_entry(skp->smk_known, dsp->smk_known, &skp->smk_rules); @@ -817,10 +826,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, *value = kstrdup(isp->smk_known, GFP_NOFS); if (*value == NULL) return -ENOMEM; - } - if (len) *len = strlen(isp->smk_known); + } return 0; } @@ -847,7 +855,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, rc = smk_curacc(isp, MAY_WRITE, &ad); rc = smk_bu_inode(old_dentry->d_inode, MAY_WRITE, rc); - if (rc == 0 && new_dentry->d_inode != NULL) { + if (rc == 0 && d_is_positive(new_dentry)) { isp = smk_of_inode(new_dentry->d_inode); smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); rc = smk_curacc(isp, MAY_WRITE, &ad); @@ -953,7 +961,7 @@ static int smack_inode_rename(struct inode *old_inode, rc = smk_curacc(isp, MAY_READWRITE, &ad); rc = smk_bu_inode(old_dentry->d_inode, MAY_READWRITE, rc); - if (rc == 0 && new_dentry->d_inode != NULL) { + if (rc == 0 && d_is_positive(new_dentry)) { isp = smk_of_inode(new_dentry->d_inode); smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); rc = smk_curacc(isp, MAY_READWRITE, &ad); @@ -1344,6 +1352,9 @@ static int smack_file_permission(struct file *file, int mask) * The security blob for a file is a pointer to the master * label list, so no allocation is done. * + * f_security is the owner security information. It + * isn't used on file access checks, it's for send_sigio. + * * Returns 0 */ static int smack_file_alloc_security(struct file *file) @@ -1381,17 +1392,18 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, { int rc = 0; struct smk_audit_info ad; + struct inode *inode = file_inode(file); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); if (_IOC_DIR(cmd) & _IOC_WRITE) { - rc = smk_curacc(file->f_security, MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); rc = smk_bu_file(file, MAY_WRITE, rc); } if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) { - rc = smk_curacc(file->f_security, MAY_READ, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad); rc = smk_bu_file(file, MAY_READ, rc); } @@ -1409,10 +1421,11 @@ static int smack_file_lock(struct file *file, unsigned int cmd) { struct smk_audit_info ad; int rc; + struct inode *inode = file_inode(file); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(file->f_security, MAY_LOCK, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); rc = smk_bu_file(file, MAY_LOCK, rc); return rc; } @@ -1434,7 +1447,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, { struct smk_audit_info ad; int rc = 0; - + struct inode *inode = file_inode(file); switch (cmd) { case F_GETLK: @@ -1443,14 +1456,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, case F_SETLKW: smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(file->f_security, MAY_LOCK, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); rc = smk_bu_file(file, MAY_LOCK, rc); break; case F_SETOWN: case F_SETSIG: smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(file->f_security, MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); rc = smk_bu_file(file, MAY_WRITE, rc); break; default: @@ -1568,14 +1581,10 @@ static int smack_mmap_file(struct file *file, * smack_file_set_fowner - set the file security blob value * @file: object in question * - * Returns 0 - * Further research may be required on this one. */ static void smack_file_set_fowner(struct file *file) { - struct smack_known *skp = smk_of_current(); - - file->f_security = skp; + file->f_security = smk_of_current(); } /** @@ -1627,6 +1636,7 @@ static int smack_file_receive(struct file *file) int rc; int may = 0; struct smk_audit_info ad; + struct inode *inode = file_inode(file); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); @@ -1638,7 +1648,7 @@ static int smack_file_receive(struct file *file) if (file->f_mode & FMODE_WRITE) may |= MAY_WRITE; - rc = smk_curacc(file->f_security, may, &ad); + rc = smk_curacc(smk_of_inode(inode), may, &ad); rc = smk_bu_file(file, may, rc); return rc; } @@ -1658,21 +1668,17 @@ static int smack_file_receive(struct file *file) static int smack_file_open(struct file *file, const struct cred *cred) { struct task_smack *tsp = cred->security; - struct inode_smack *isp = file_inode(file)->i_security; + struct inode *inode = file_inode(file); struct smk_audit_info ad; int rc; - if (smack_privileged(CAP_MAC_OVERRIDE)) { - file->f_security = isp->smk_inode; + if (smack_privileged(CAP_MAC_OVERRIDE)) return 0; - } smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad); + rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad); rc = smk_bu_credfile(cred, file, MAY_READ, rc); - if (rc == 0) - file->f_security = isp->smk_inode; return rc; } @@ -1826,7 +1832,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access, const char *caller) { struct smk_audit_info ad; - struct smack_known *skp = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task_struct(p); int rc; smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); @@ -1879,7 +1885,7 @@ static int smack_task_getsid(struct task_struct *p) */ static void smack_task_getsecid(struct task_struct *p, u32 *secid) { - struct smack_known *skp = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task_struct(p); *secid = skp->smk_secid; } @@ -1986,7 +1992,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, { struct smk_audit_info ad; struct smack_known *skp; - struct smack_known *tkp = smk_of_task(task_security(p)); + struct smack_known *tkp = smk_of_task_struct(p); int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); @@ -2040,7 +2046,7 @@ static int smack_task_wait(struct task_struct *p) static void smack_task_to_inode(struct task_struct *p, struct inode *inode) { struct inode_smack *isp = inode->i_security; - struct smack_known *skp = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task_struct(p); isp->smk_inode = skp; } @@ -2212,6 +2218,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) return smack_netlabel(sk, sk_lbl); } +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) /** * smk_ipv6_port_label - Smack port access table management * @sock: socket @@ -2361,6 +2368,7 @@ auditout: rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc); return rc; } +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ /** * smack_inode_setsecurity - set smack xattrs @@ -2421,8 +2429,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, } else return -EOPNOTSUPP; +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) if (sock->sk->sk_family == PF_INET6) smk_ipv6_port_label(sock, NULL); +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ return 0; } @@ -2450,6 +2460,7 @@ static int smack_socket_post_create(struct socket *sock, int family, return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); } +#ifndef CONFIG_SECURITY_SMACK_NETFILTER /** * smack_socket_bind - record port binding information. * @sock: the socket @@ -2463,11 +2474,14 @@ static int smack_socket_post_create(struct socket *sock, int family, static int smack_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { +#if IS_ENABLED(CONFIG_IPV6) if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) smk_ipv6_port_label(sock, address); +#endif return 0; } +#endif /* !CONFIG_SECURITY_SMACK_NETFILTER */ /** * smack_socket_connect - connect access check @@ -2496,8 +2510,10 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, case PF_INET6: if (addrlen < sizeof(struct sockaddr_in6)) return -EINVAL; +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap, SMK_CONNECTING); +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ break; } return rc; @@ -3033,7 +3049,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * of the superblock. */ if (opt_dentry->d_parent == opt_dentry) { - if (sbp->s_magic == CGROUP_SUPER_MAGIC) { + switch (sbp->s_magic) { + case CGROUP_SUPER_MAGIC: /* * The cgroup filesystem is never mounted, * so there's no opportunity to set the mount @@ -3041,8 +3058,19 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ sbsp->smk_root = &smack_known_star; sbsp->smk_default = &smack_known_star; + isp->smk_inode = sbsp->smk_root; + break; + case TMPFS_MAGIC: + /* + * What about shmem/tmpfs anonymous files with dentry + * obtained from d_alloc_pseudo()? + */ + isp->smk_inode = smk_of_current(); + break; + default: + isp->smk_inode = sbsp->smk_root; + break; } - isp->smk_inode = sbsp->smk_root; isp->smk_flags |= SMK_INODE_INSTANT; goto unlockandout; } @@ -3200,7 +3228,7 @@ unlockandout: */ static int smack_getprocattr(struct task_struct *p, char *name, char **value) { - struct smack_known *skp = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task_struct(p); char *cp; int slen; @@ -3297,7 +3325,7 @@ static int smack_unix_stream_connect(struct sock *sock, if (!smack_privileged(CAP_MAC_OVERRIDE)) { skp = ssp->smk_out; - okp = osp->smk_out; + okp = osp->smk_in; #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); smk_ad_setfield_u_net_sk(&ad, other); @@ -3305,7 +3333,9 @@ static int smack_unix_stream_connect(struct sock *sock, rc = smk_access(skp, okp, MAY_WRITE, &ad); rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc); if (rc == 0) { - rc = smk_access(okp, skp, MAY_WRITE, NULL); + okp = osp->smk_out; + skp = ssp->smk_in; + rc = smk_access(okp, skp, MAY_WRITE, &ad); rc = smk_bu_note("UDS connect", okp, skp, MAY_WRITE, rc); } @@ -3366,7 +3396,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ int rc = 0; /* @@ -3380,7 +3412,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, rc = smack_netlabel_send(sock->sk, sip); break; case AF_INET6: +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ break; } return rc; @@ -3471,6 +3505,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, return smack_net_ambient; } +#if IS_ENABLED(CONFIG_IPV6) static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) { u8 nexthdr; @@ -3517,6 +3552,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) } return proto; } +#endif /* CONFIG_IPV6 */ /** * smack_socket_sock_rcv_skb - Smack packet delivery access check @@ -3529,15 +3565,30 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) { struct netlbl_lsm_secattr secattr; struct socket_smack *ssp = sk->sk_security; - struct smack_known *skp; - struct sockaddr_in6 sadd; + struct smack_known *skp = NULL; int rc = 0; struct smk_audit_info ad; #ifdef CONFIG_AUDIT struct lsm_network_audit net; #endif +#if IS_ENABLED(CONFIG_IPV6) + struct sockaddr_in6 sadd; + int proto; +#endif /* CONFIG_IPV6 */ + switch (sk->sk_family) { case PF_INET: +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + /* + * If there is a secmark use it rather than the CIPSO label. + * If there is no secmark fall back to CIPSO. + * The secmark is assumed to reflect policy better. + */ + if (skb && skb->secmark != 0) { + skp = smack_from_secid(skb->secmark); + goto access_check; + } +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ /* * Translate what netlabel gave us. */ @@ -3551,6 +3602,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) netlbl_secattr_destroy(&secattr); +#ifdef CONFIG_SECURITY_SMACK_NETFILTER +access_check: +#endif #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = sk->sk_family; @@ -3569,14 +3623,32 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (rc != 0) netlbl_skbuff_err(skb, rc, 0); break; +#if IS_ENABLED(CONFIG_IPV6) case PF_INET6: - rc = smk_skb_to_addr_ipv6(skb, &sadd); - if (rc == IPPROTO_UDP || rc == IPPROTO_TCP) - rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); + proto = smk_skb_to_addr_ipv6(skb, &sadd); + if (proto != IPPROTO_UDP && proto != IPPROTO_TCP) + break; +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + if (skb && skb->secmark != 0) + skp = smack_from_secid(skb->secmark); else - rc = 0; + skp = smack_net_ambient; +#ifdef CONFIG_AUDIT + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); + ad.a.u.net->family = sk->sk_family; + ad.a.u.net->netif = skb->skb_iif; + ipv6_skb_to_auditdata(skb, &ad.a, NULL); +#endif /* CONFIG_AUDIT */ + rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, + MAY_WRITE, rc); +#else /* CONFIG_SECURITY_SMACK_NETFILTER */ + rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ break; +#endif /* CONFIG_IPV6 */ } + return rc; } @@ -3638,16 +3710,25 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, if (skb != NULL) { if (skb->protocol == htons(ETH_P_IP)) family = PF_INET; +#if IS_ENABLED(CONFIG_IPV6) else if (skb->protocol == htons(ETH_P_IPV6)) family = PF_INET6; +#endif /* CONFIG_IPV6 */ } if (family == PF_UNSPEC && sock != NULL) family = sock->sk->sk_family; - if (family == PF_UNIX) { + switch (family) { + case PF_UNIX: ssp = sock->sk->sk_security; s = ssp->smk_out->smk_secid; - } else if (family == PF_INET || family == PF_INET6) { + break; + case PF_INET: +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + s = skb->secmark; + if (s != 0) + break; +#endif /* * Translate what netlabel gave us. */ @@ -3660,6 +3741,14 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, s = skp->smk_secid; } netlbl_secattr_destroy(&secattr); + break; +#if IS_ENABLED(CONFIG_IPV6) + case PF_INET6: +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + s = skb->secmark; +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ + break; +#endif /* CONFIG_IPV6 */ } *secid = s; if (s == 0) @@ -3715,6 +3804,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct lsm_network_audit net; #endif +#if IS_ENABLED(CONFIG_IPV6) if (family == PF_INET6) { /* * Handle mapped IPv4 packets arriving @@ -3726,6 +3816,19 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, else return 0; } +#endif /* CONFIG_IPV6 */ + +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + /* + * If there is a secmark use it rather than the CIPSO label. + * If there is no secmark fall back to CIPSO. + * The secmark is assumed to reflect policy better. + */ + if (skb && skb->secmark != 0) { + skp = smack_from_secid(skb->secmark); + goto access_check; + } +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr); @@ -3735,6 +3838,10 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, skp = &smack_known_huh; netlbl_secattr_destroy(&secattr); +#ifdef CONFIG_SECURITY_SMACK_NETFILTER +access_check: +#endif + #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = family; @@ -3834,11 +3941,11 @@ static void smack_key_free(struct key *key) key->security = NULL; } -/* +/** * smack_key_permission - Smack access on a key * @key_ref: gets to the object * @cred: the credentials to use - * @perm: unused + * @perm: requested key permissions * * Return 0 if the task has read and write to the object, * an error code otherwise @@ -4184,7 +4291,9 @@ struct security_operations smack_ops = { .unix_may_send = smack_unix_may_send, .socket_post_create = smack_socket_post_create, +#ifndef CONFIG_SECURITY_SMACK_NETFILTER .socket_bind = smack_socket_bind, +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ .socket_connect = smack_socket_connect, .socket_sendmsg = smack_socket_sendmsg, .socket_sock_rcv_skb = smack_socket_sock_rcv_skb, @@ -4265,6 +4374,8 @@ static __init int smack_init(void) if (!security_module_enable(&smack_ops)) return 0; + smack_enabled = 1; + smack_inode_cache = KMEM_CACHE(inode_smack, 0); if (!smack_inode_cache) return -ENOMEM; diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c new file mode 100644 index 0000000..c952632 --- /dev/null +++ b/security/smack/smack_netfilter.c @@ -0,0 +1,96 @@ +/* + * Simplified MAC Kernel (smack) security module + * + * This file contains the Smack netfilter implementation + * + * Author: + * Casey Schaufler <casey@schaufler-ca.com> + * + * Copyright (C) 2014 Casey Schaufler <casey@schaufler-ca.com> + * Copyright (C) 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + */ + +#include <linux/netfilter_ipv4.h> +#include <linux/netfilter_ipv6.h> +#include <linux/netdevice.h> +#include "smack.h" + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct socket_smack *ssp; + struct smack_known *skp; + + if (skb && skb->sk && skb->sk->sk_security) { + ssp = skb->sk->sk_security; + skp = ssp->smk_out; + skb->secmark = skp->smk_secid; + } + + return NF_ACCEPT; +} +#endif /* IPV6 */ + +static unsigned int smack_ipv4_output(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct socket_smack *ssp; + struct smack_known *skp; + + if (skb && skb->sk && skb->sk->sk_security) { + ssp = skb->sk->sk_security; + skp = ssp->smk_out; + skb->secmark = skp->smk_secid; + } + + return NF_ACCEPT; +} + +static struct nf_hook_ops smack_nf_ops[] = { + { + .hook = smack_ipv4_output, + .owner = THIS_MODULE, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP_PRI_SELINUX_FIRST, + }, +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + { + .hook = smack_ipv6_output, + .owner = THIS_MODULE, + .pf = NFPROTO_IPV6, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP6_PRI_SELINUX_FIRST, + }, +#endif /* IPV6 */ +}; + +static int __init smack_nf_ip_init(void) +{ + int err; + + if (smack_enabled == 0) + return 0; + + printk(KERN_DEBUG "Smack: Registering netfilter hooks\n"); + + err = nf_register_hooks(smack_nf_ops, ARRAY_SIZE(smack_nf_ops)); + if (err) + pr_info("Smack: nf_register_hooks: error %d\n", err); + + return 0; +} + +__initcall(smack_nf_ip_init); diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig index 8eb779b9d..604e718 100644 --- a/security/tomoyo/Kconfig +++ b/security/tomoyo/Kconfig @@ -5,6 +5,7 @@ config SECURITY_TOMOYO select SECURITYFS select SECURITY_PATH select SECURITY_NETWORK + select SRCU default n help This selects TOMOYO Linux, pathname-based access control. diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 4003907..c151a18 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -905,11 +905,9 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, !tomoyo_get_realpath(&buf2, path2)) goto out; switch (operation) { - struct dentry *dentry; case TOMOYO_TYPE_RENAME: case TOMOYO_TYPE_LINK: - dentry = path1->dentry; - if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) + if (!d_is_dir(path1->dentry)) break; /* fall through */ case TOMOYO_TYPE_PIVOT_ROOT: |