diff options
Diffstat (limited to 'security')
40 files changed, 1591 insertions, 1111 deletions
diff --git a/security/Kconfig b/security/Kconfig index 5dfc206748c..49b51f96489 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -113,10 +113,12 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR from userspace allocation. Keeping a user from writing to low pages can help reduce the impact of kernel NULL pointer bugs. - For most users with lots of address space a value of 65536 is - reasonable and should cause no problems. Programs which use vm86 - functionality would either need additional permissions from either - the LSM or the capabilities module or have this protection disabled. + For most ia64, ppc64 and x86 users with lots of address space + a value of 65536 is reasonable and should cause no problems. + On arm and other archs it should not be higher than 32768. + Programs which use vm86 functionality would either need additional + permissions from either the LSM or the capabilities module or have + this protection disabled. This value can be changed after boot using the /proc/sys/vm/mmap_min_addr tunable. diff --git a/security/capability.c b/security/capability.c index 9e99f36a8b5..2c6e06d18fa 100644 --- a/security/capability.c +++ b/security/capability.c @@ -40,7 +40,6 @@ static struct security_operations capability_ops = { .inode_need_killpriv = cap_inode_need_killpriv, .inode_killpriv = cap_inode_killpriv, - .task_kill = cap_task_kill, .task_setscheduler = cap_task_setscheduler, .task_setioprio = cap_task_setioprio, .task_setnice = cap_task_setnice, diff --git a/security/commoncap.c b/security/commoncap.c index bb0c095f576..852905789ca 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -267,7 +267,7 @@ static int get_file_caps(struct linux_binprm *bprm) rc = cap_from_disk(&vcaps, bprm, rc); if (rc) printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", - __FUNCTION__, rc, bprm->filename); + __func__, rc, bprm->filename); out: dput(dentry); @@ -302,7 +302,7 @@ int cap_bprm_set_security (struct linux_binprm *bprm) ret = get_file_caps(bprm); if (ret) printk(KERN_NOTICE "%s: get_file_caps returned %d for %s\n", - __FUNCTION__, ret, bprm->filename); + __func__, ret, bprm->filename); /* To support inheritance of root-permissions and suid-root * executables under compatibility mode, we raise all three @@ -540,41 +540,6 @@ int cap_task_setnice (struct task_struct *p, int nice) return cap_safe_nice(p); } -int cap_task_kill(struct task_struct *p, struct siginfo *info, - int sig, u32 secid) -{ - if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) - return 0; - - /* - * Running a setuid root program raises your capabilities. - * Killing your own setuid root processes was previously - * allowed. - * We must preserve legacy signal behavior in this case. - */ - if (p->uid == current->uid) - return 0; - - /* sigcont is permitted within same session */ - if (sig == SIGCONT && (task_session_nr(current) == task_session_nr(p))) - return 0; - - if (secid) - /* - * Signal sent as a particular user. - * Capabilities are ignored. May be wrong, but it's the - * only thing we can do at the moment. - * Used only by usb drivers? - */ - return 0; - if (cap_issubset(p->cap_permitted, current->cap_permitted)) - return 0; - if (capable(CAP_KILL)) - return 0; - - return -EPERM; -} - /* * called from kernel/sys.c for prctl(PR_CABSET_DROP) * done without task_capability_lock() because it introduces @@ -605,11 +570,6 @@ int cap_task_setnice (struct task_struct *p, int nice) { return 0; } -int cap_task_kill(struct task_struct *p, struct siginfo *info, - int sig, u32 secid) -{ - return 0; -} #endif void cap_task_reparent_to_init (struct task_struct *p) diff --git a/security/dummy.c b/security/dummy.c index 78d8f92310a..b0232bbf427 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -196,13 +196,13 @@ static int dummy_sb_statfs (struct dentry *dentry) return 0; } -static int dummy_sb_mount (char *dev_name, struct nameidata *nd, char *type, +static int dummy_sb_mount (char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { return 0; } -static int dummy_sb_check_sb (struct vfsmount *mnt, struct nameidata *nd) +static int dummy_sb_check_sb (struct vfsmount *mnt, struct path *path) { return 0; } @@ -229,17 +229,17 @@ static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags, } -static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd) +static void dummy_sb_post_addmount (struct vfsmount *mnt, struct path *path) { return; } -static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +static int dummy_sb_pivotroot (struct path *old_path, struct path *new_path) { return 0; } -static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) +static void dummy_sb_post_pivotroot (struct path *old_path, struct path *new_path) { return; } @@ -424,6 +424,11 @@ static int dummy_inode_listsecurity(struct inode *inode, char *buffer, size_t bu return 0; } +static void dummy_inode_getsecid(const struct inode *inode, u32 *secid) +{ + *secid = 0; +} + static int dummy_file_permission (struct file *file, int mask) { return 0; @@ -542,7 +547,9 @@ static int dummy_task_getsid (struct task_struct *p) } static void dummy_task_getsecid (struct task_struct *p, u32 *secid) -{ } +{ + *secid = 0; +} static int dummy_task_setgroups (struct group_info *group_info) { @@ -616,6 +623,11 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag) return 0; } +static void dummy_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) +{ + *secid = 0; +} + static int dummy_msg_msg_alloc_security (struct msg_msg *msg) { return 0; @@ -876,22 +888,23 @@ static inline void dummy_req_classify_flow(const struct request_sock *req, #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM -static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx) +static int dummy_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *sec_ctx) { return 0; } -static inline int dummy_xfrm_policy_clone_security(struct xfrm_policy *old, struct xfrm_policy *new) +static inline int dummy_xfrm_policy_clone_security(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { return 0; } -static void dummy_xfrm_policy_free_security(struct xfrm_policy *xp) +static void dummy_xfrm_policy_free_security(struct xfrm_sec_ctx *ctx) { } -static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp) +static int dummy_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx) { return 0; } @@ -911,7 +924,8 @@ static int dummy_xfrm_state_delete_security(struct xfrm_state *x) return 0; } -static int dummy_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) +static int dummy_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, + u32 sk_sid, u8 dir) { return 0; } @@ -981,7 +995,33 @@ static inline int dummy_key_permission(key_ref_t key_ref, } #endif /* CONFIG_KEYS */ -struct security_operations dummy_security_ops; +#ifdef CONFIG_AUDIT +static inline int dummy_audit_rule_init(u32 field, u32 op, char *rulestr, + void **lsmrule) +{ + return 0; +} + +static inline int dummy_audit_rule_known(struct audit_krule *krule) +{ + return 0; +} + +static inline int dummy_audit_rule_match(u32 secid, u32 field, u32 op, + void *lsmrule, + struct audit_context *actx) +{ + return 0; +} + +static inline void dummy_audit_rule_free(void *lsmrule) +{ } + +#endif /* CONFIG_AUDIT */ + +struct security_operations dummy_security_ops = { + .name = "dummy", +}; #define set_to_dummy_if_null(ops, function) \ do { \ @@ -1058,6 +1098,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, inode_getsecurity); set_to_dummy_if_null(ops, inode_setsecurity); set_to_dummy_if_null(ops, inode_listsecurity); + set_to_dummy_if_null(ops, inode_getsecid); set_to_dummy_if_null(ops, file_permission); set_to_dummy_if_null(ops, file_alloc_security); set_to_dummy_if_null(ops, file_free_security); @@ -1094,6 +1135,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, task_reparent_to_init); set_to_dummy_if_null(ops, task_to_inode); set_to_dummy_if_null(ops, ipc_permission); + set_to_dummy_if_null(ops, ipc_getsecid); set_to_dummy_if_null(ops, msg_msg_alloc_security); set_to_dummy_if_null(ops, msg_msg_free_security); set_to_dummy_if_null(ops, msg_queue_alloc_security); @@ -1168,6 +1210,11 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, key_free); set_to_dummy_if_null(ops, key_permission); #endif /* CONFIG_KEYS */ - +#ifdef CONFIG_AUDIT + set_to_dummy_if_null(ops, audit_rule_init); + set_to_dummy_if_null(ops, audit_rule_known); + set_to_dummy_if_null(ops, audit_rule_match); + set_to_dummy_if_null(ops, audit_rule_free); +#endif } diff --git a/security/keys/internal.h b/security/keys/internal.h index d36d6939335..7d894ef7037 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -22,16 +22,16 @@ void no_printk(const char *fmt, ...) #ifdef __KDEBUG #define kenter(FMT, ...) \ - printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__) + printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__) #define kleave(FMT, ...) \ - printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__) + printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__) #define kdebug(FMT, ...) \ printk(KERN_DEBUG "xxx" FMT"yyy\n", ##__VA_ARGS__) #else #define kenter(FMT, ...) \ - no_printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__) + no_printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__) #define kleave(FMT, ...) \ - no_printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__) + no_printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__) #define kdebug(FMT, ...) \ no_printk(KERN_DEBUG FMT"\n", ##__VA_ARGS__) #endif diff --git a/security/root_plug.c b/security/root_plug.c index 870f13095bb..6112d1404c8 100644 --- a/security/root_plug.c +++ b/security/root_plug.c @@ -49,7 +49,7 @@ module_param(debug, bool, 0600); do { \ if (debug) \ printk(KERN_DEBUG "%s: %s: " fmt , \ - MY_NAME , __FUNCTION__ , \ + MY_NAME , __func__ , \ ## arg); \ } while (0) diff --git a/security/security.c b/security/security.c index b1387a6b416..8a285c7b996 100644 --- a/security/security.c +++ b/security/security.c @@ -17,6 +17,8 @@ #include <linux/kernel.h> #include <linux/security.h> +/* Boot-time LSM user choice */ +static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1]; /* things that live in dummy.c */ extern struct security_operations dummy_security_ops; @@ -57,7 +59,7 @@ int __init security_init(void) if (verify(&dummy_security_ops)) { printk(KERN_ERR "%s could not verify " - "dummy_security_ops structure.\n", __FUNCTION__); + "dummy_security_ops structure.\n", __func__); return -EIO; } @@ -67,13 +69,47 @@ int __init security_init(void) return 0; } +/* Save user chosen LSM */ +static int __init choose_lsm(char *str) +{ + strncpy(chosen_lsm, str, SECURITY_NAME_MAX); + return 1; +} +__setup("security=", choose_lsm); + +/** + * security_module_enable - Load given security module on boot ? + * @ops: a pointer to the struct security_operations that is to be checked. + * + * Each LSM must pass this method before registering its own operations + * to avoid security registration races. This method may also be used + * to check if your LSM is currently loaded during kernel initialization. + * + * Return true if: + * -The passed LSM is the one chosen by user at boot time, + * -or user didsn't specify a specific LSM and we're the first to ask + * for registeration permissoin, + * -or the passed LSM is currently loaded. + * Otherwise, return false. + */ +int __init security_module_enable(struct security_operations *ops) +{ + if (!*chosen_lsm) + strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX); + else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX)) + return 0; + + return 1; +} + /** * register_security - registers a security framework with the kernel * @ops: a pointer to the struct security_options that is to be registered * * This function is to allow a security module to register itself with the * kernel security subsystem. Some rudimentary checking is done on the @ops - * value passed to this function. + * value passed to this function. You'll need to check first if your LSM + * is allowed to register its @ops by calling security_module_enable(@ops). * * If there is already a security module registered with the kernel, * an error will be returned. Otherwise 0 is returned on success. @@ -82,7 +118,7 @@ int register_security(struct security_operations *ops) { if (verify(ops)) { printk(KERN_DEBUG "%s could not verify " - "security_operations structure.\n", __FUNCTION__); + "security_operations structure.\n", __func__); return -EINVAL; } @@ -110,13 +146,13 @@ int mod_reg_security(const char *name, struct security_operations *ops) { if (verify(ops)) { printk(KERN_INFO "%s could not verify " - "security operations.\n", __FUNCTION__); + "security operations.\n", __func__); return -EINVAL; } if (ops == security_ops) { printk(KERN_INFO "%s security operations " - "already registered.\n", __FUNCTION__); + "already registered.\n", __func__); return -EINVAL; } @@ -260,15 +296,15 @@ int security_sb_statfs(struct dentry *dentry) return security_ops->sb_statfs(dentry); } -int security_sb_mount(char *dev_name, struct nameidata *nd, +int security_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { - return security_ops->sb_mount(dev_name, nd, type, flags, data); + return security_ops->sb_mount(dev_name, path, type, flags, data); } -int security_sb_check_sb(struct vfsmount *mnt, struct nameidata *nd) +int security_sb_check_sb(struct vfsmount *mnt, struct path *path) { - return security_ops->sb_check_sb(mnt, nd); + return security_ops->sb_check_sb(mnt, path); } int security_sb_umount(struct vfsmount *mnt, int flags) @@ -291,19 +327,19 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d security_ops->sb_post_remount(mnt, flags, data); } -void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd) +void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint) { - security_ops->sb_post_addmount(mnt, mountpoint_nd); + security_ops->sb_post_addmount(mnt, mountpoint); } -int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd) +int security_sb_pivotroot(struct path *old_path, struct path *new_path) { - return security_ops->sb_pivotroot(old_nd, new_nd); + return security_ops->sb_pivotroot(old_path, new_path); } -void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd) +void security_sb_post_pivotroot(struct path *old_path, struct path *new_path) { - security_ops->sb_post_pivotroot(old_nd, new_nd); + security_ops->sb_post_pivotroot(old_path, new_path); } int security_sb_get_mnt_opts(const struct super_block *sb, @@ -523,6 +559,11 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer return security_ops->inode_listsecurity(inode, buffer, buffer_size); } +void security_inode_getsecid(const struct inode *inode, u32 *secid) +{ + security_ops->inode_getsecid(inode, secid); +} + int security_file_permission(struct file *file, int mask) { return security_ops->file_permission(file, mask); @@ -712,6 +753,11 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag) return security_ops->ipc_permission(ipcp, flag); } +void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) +{ + security_ops->ipc_getsecid(ipcp, secid); +} + int security_msg_msg_alloc(struct msg_msg *msg) { return security_ops->msg_msg_alloc_security(msg); @@ -1014,26 +1060,27 @@ void security_inet_conn_established(struct sock *sk, #ifdef CONFIG_SECURITY_NETWORK_XFRM -int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) +int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx) { - return security_ops->xfrm_policy_alloc_security(xp, sec_ctx); + return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx); } EXPORT_SYMBOL(security_xfrm_policy_alloc); -int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) +int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { - return security_ops->xfrm_policy_clone_security(old, new); + return security_ops->xfrm_policy_clone_security(old_ctx, new_ctxp); } -void security_xfrm_policy_free(struct xfrm_policy *xp) +void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { - security_ops->xfrm_policy_free_security(xp); + security_ops->xfrm_policy_free_security(ctx); } EXPORT_SYMBOL(security_xfrm_policy_free); -int security_xfrm_policy_delete(struct xfrm_policy *xp) +int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { - return security_ops->xfrm_policy_delete_security(xp); + return security_ops->xfrm_policy_delete_security(ctx); } int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) @@ -1065,9 +1112,9 @@ void security_xfrm_state_free(struct xfrm_state *x) security_ops->xfrm_state_free_security(x); } -int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) +int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) { - return security_ops->xfrm_policy_lookup(xp, fl_secid, dir); + return security_ops->xfrm_policy_lookup(ctx, fl_secid, dir); } int security_xfrm_state_pol_flow_match(struct xfrm_state *x, @@ -1110,3 +1157,28 @@ int security_key_permission(key_ref_t key_ref, } #endif /* CONFIG_KEYS */ + +#ifdef CONFIG_AUDIT + +int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule) +{ + return security_ops->audit_rule_init(field, op, rulestr, lsmrule); +} + +int security_audit_rule_known(struct audit_krule *krule) +{ + return security_ops->audit_rule_known(krule); +} + +void security_audit_rule_free(void *lsmrule) +{ + security_ops->audit_rule_free(lsmrule); +} + +int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, + struct audit_context *actx) +{ + return security_ops->audit_rule_match(secid, field, op, lsmrule, actx); +} + +#endif /* CONFIG_AUDIT */ diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 2b517d61867..a436d1cfa88 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE int "NSA SELinux maximum supported policy format version value" depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX - range 15 22 + range 15 23 default 19 help This option sets the value for the maximum policy format version diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 00afd85f1ed..d47fc5e545e 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -11,6 +11,7 @@ selinux-y := avc.o \ nlmsgtab.o \ netif.o \ netnode.o \ + netport.o \ exports.o selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 187964e88af..95a8ef4a507 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -2,16 +2,16 @@ * Implementation of the kernel access vector cache (AVC). * * Authors: Stephen Smalley, <sds@epoch.ncsc.mil> - * James Morris <jmorris@redhat.com> + * James Morris <jmorris@redhat.com> * * Update: KaiGai, Kohei <kaigai@ak.jp.nec.com> - * Replaced the avc_lock spinlock by RCU. + * Replaced the avc_lock spinlock by RCU. * * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * * 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. + * as published by the Free Software Foundation. */ #include <linux/types.h> #include <linux/stddef.h> @@ -44,7 +44,7 @@ static const char *class_to_string[] = { #undef S_ }; -#define TB_(s) static const char * s [] = { +#define TB_(s) static const char *s[] = { #define TE_(s) }; #define S_(s) s, #include "common_perm_to_string.h" @@ -72,7 +72,7 @@ const struct selinux_class_perm selinux_class_perm = { #define AVC_CACHE_RECLAIM 16 #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS -#define avc_cache_stats_incr(field) \ +#define avc_cache_stats_incr(field) \ do { \ per_cpu(avc_cache_stats, get_cpu()).field++; \ put_cpu(); \ @@ -92,7 +92,7 @@ struct avc_entry { struct avc_node { struct avc_entry ae; struct list_head list; - struct rcu_head rhead; + struct rcu_head rhead; }; struct avc_cache { @@ -105,8 +105,8 @@ struct avc_cache { struct avc_callback_node { int (*callback) (u32 event, u32 ssid, u32 tsid, - u16 tclass, u32 perms, - u32 *out_retained); + u16 tclass, u32 perms, + u32 *out_retained); u32 events; u32 ssid; u32 tsid; @@ -202,7 +202,7 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla char *scontext; u32 scontext_len; - rc = security_sid_to_context(ssid, &scontext, &scontext_len); + rc = security_sid_to_context(ssid, &scontext, &scontext_len); if (rc) audit_log_format(ab, "ssid=%d", ssid); else { @@ -306,12 +306,13 @@ static inline int avc_reclaim_node(void) int hvalue, try, ecx; unsigned long flags; - for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++ ) { + for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1); if (!spin_trylock_irqsave(&avc_cache.slots_lock[hvalue], flags)) continue; + rcu_read_lock(); list_for_each_entry(node, &avc_cache.slots[hvalue], list) { if (atomic_dec_and_test(&node->ae.used)) { /* Recently Unused */ @@ -319,11 +320,13 @@ static inline int avc_reclaim_node(void) avc_cache_stats_incr(reclaims); ecx++; if (ecx >= AVC_CACHE_RECLAIM) { + rcu_read_unlock(); spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags); goto out; } } } + rcu_read_unlock(); spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags); } out: @@ -426,7 +429,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) spin_lock_irqsave(¬if_lock, flag); if (is_insert) { if (seqno < avc_cache.latest_notif) { - printk(KERN_WARNING "avc: seqno %d < latest_notif %d\n", + printk(KERN_WARNING "SELinux: avc: seqno %d < latest_notif %d\n", seqno, avc_cache.latest_notif); ret = -EAGAIN; } @@ -475,7 +478,7 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_en if (pos->ae.ssid == ssid && pos->ae.tsid == tsid && pos->ae.tclass == tclass) { - avc_node_replace(node, pos); + avc_node_replace(node, pos); goto found; } } @@ -526,8 +529,8 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, * before calling the auditing code. */ void avc_audit(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct av_decision *avd, int result, struct avc_audit_data *a) + u16 tclass, u32 requested, + struct av_decision *avd, int result, struct avc_audit_data *a) { struct task_struct *tsk = current; struct inode *inode = NULL; @@ -541,7 +544,7 @@ void avc_audit(u32 ssid, u32 tsid, return; } else if (result) { audited = denied = requested; - } else { + } else { audited = requested; if (!(audited & avd->auditallow)) return; @@ -551,7 +554,7 @@ void avc_audit(u32 ssid, u32 tsid, if (!ab) return; /* audit_panic has been called */ audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); - avc_dump_av(ab, tclass,audited); + avc_dump_av(ab, tclass, audited); audit_log_format(ab, " for "); if (a && a->tsk) tsk = a->tsk; @@ -647,7 +650,7 @@ void avc_audit(u32 ssid, u32 tsid, break; } } - + switch (a->u.net.family) { case AF_INET: avc_print_ipv4_addr(ab, a->u.net.v4info.saddr, @@ -702,10 +705,10 @@ void avc_audit(u32 ssid, u32 tsid, * -%ENOMEM if insufficient memory exists to add the callback. */ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, - u16 tclass, u32 perms, - u32 *out_retained), - u32 events, u32 ssid, u32 tsid, - u16 tclass, u32 perms) + u16 tclass, u32 perms, + u32 *out_retained), + u32 events, u32 ssid, u32 tsid, + u16 tclass, u32 perms) { struct avc_callback_node *c; int rc = 0; @@ -759,10 +762,10 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass) hvalue = avc_hash(ssid, tsid, tclass); spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag); - list_for_each_entry(pos, &avc_cache.slots[hvalue], list){ - if ( ssid==pos->ae.ssid && - tsid==pos->ae.tsid && - tclass==pos->ae.tclass ){ + list_for_each_entry(pos, &avc_cache.slots[hvalue], list) { + if (ssid == pos->ae.ssid && + tsid == pos->ae.tsid && + tclass == pos->ae.tclass){ orig = pos; break; } @@ -821,15 +824,21 @@ int avc_ss_reset(u32 seqno) for (i = 0; i < AVC_CACHE_SLOTS; i++) { spin_lock_irqsave(&avc_cache.slots_lock[i], flag); + /* + * With preemptable RCU, the outer spinlock does not + * prevent RCU grace periods from ending. + */ + rcu_read_lock(); list_for_each_entry(node, &avc_cache.slots[i], list) avc_node_delete(node); + rcu_read_unlock(); spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag); } for (c = avc_callbacks; c; c = c->next) { if (c->events & AVC_CALLBACK_RESET) { tmprc = c->callback(AVC_CALLBACK_RESET, - 0, 0, 0, 0, NULL); + 0, 0, 0, 0, NULL); /* save the first error encountered for the return value and continue processing the callbacks */ if (!rc) @@ -871,16 +880,18 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, int rc = 0; u32 denied; + BUG_ON(!requested); + rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass, requested); if (!node) { rcu_read_unlock(); - rc = security_compute_av(ssid,tsid,tclass,requested,&entry.avd); + rc = security_compute_av(ssid, tsid, tclass, requested, &entry.avd); if (rc) goto out; rcu_read_lock(); - node = avc_insert(ssid,tsid,tclass,&entry); + node = avc_insert(ssid, tsid, tclass, &entry); } p_ae = node ? &node->ae : &entry; @@ -890,13 +901,14 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, denied = requested & ~(p_ae->avd.allowed); - if (!requested || denied) { - if (selinux_enforcing || (flags & AVC_STRICT)) + if (denied) { + if (flags & AVC_STRICT) rc = -EACCES; + else if (!selinux_enforcing || security_permissive_sid(ssid)) + avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, + tsid, tclass); else - if (node) - avc_update_node(AVC_CALLBACK_GRANT,requested, - ssid,tsid,tclass); + rc = -EACCES; } rcu_read_unlock(); @@ -921,7 +933,7 @@ out: * another -errno upon other errors. */ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, - u32 requested, struct avc_audit_data *auditdata) + u32 requested, struct avc_audit_data *auditdata) { struct av_decision avd; int rc; diff --git a/security/selinux/exports.c b/security/selinux/exports.c index 87d2bb3ea35..64af2d3409e 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c @@ -25,48 +25,6 @@ /* SECMARK reference count */ extern atomic_t selinux_secmark_refcount; -int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen) -{ - if (selinux_enabled) - return security_sid_to_context(sid, ctx, ctxlen); - else { - *ctx = NULL; - *ctxlen = 0; - } - - return 0; -} - -void selinux_get_inode_sid(const struct inode *inode, u32 *sid) -{ - if (selinux_enabled) { - struct inode_security_struct *isec = inode->i_security; - *sid = isec->sid; - return; - } - *sid = 0; -} - -void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid) -{ - if (selinux_enabled) { - struct ipc_security_struct *isec = ipcp->security; - *sid = isec->sid; - return; - } - *sid = 0; -} - -void selinux_get_task_sid(struct task_struct *tsk, u32 *sid) -{ - if (selinux_enabled) { - struct task_security_struct *tsec = tsk->security; - *sid = tsec->sid; - return; - } - *sid = 0; -} - int selinux_string_to_sid(char *str, u32 *sid) { if (selinux_enabled) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 41a049f50f5..308e2cf17d7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4,22 +4,22 @@ * This file contains the SELinux hook function implementations. * * Authors: Stephen Smalley, <sds@epoch.ncsc.mil> - * Chris Vance, <cvance@nai.com> - * Wayne Salamon, <wsalamon@nai.com> - * James Morris <jmorris@redhat.com> + * Chris Vance, <cvance@nai.com> + * Wayne Salamon, <wsalamon@nai.com> + * James Morris <jmorris@redhat.com> * * Copyright (C) 2001,2002 Networks Associates Technology, Inc. * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. - * <dgoeddel@trustedcs.com> + * <dgoeddel@trustedcs.com> * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. - * Paul Moore <paul.moore@hp.com> + * Paul Moore <paul.moore@hp.com> * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. - * Yuichi Nakamura <ynakam@hitachisoft.jp> + * Yuichi Nakamura <ynakam@hitachisoft.jp> * * 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. + * as published by the Free Software Foundation. */ #include <linux/init.h> @@ -80,8 +80,10 @@ #include "objsec.h" #include "netif.h" #include "netnode.h" +#include "netport.h" #include "xfrm.h" #include "netlabel.h" +#include "audit.h" #define XATTR_SELINUX_SUFFIX "selinux" #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX @@ -97,11 +99,11 @@ extern struct security_operations *security_ops; atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); #ifdef CONFIG_SECURITY_SELINUX_DEVELOP -int selinux_enforcing = 0; +int selinux_enforcing; static int __init enforcing_setup(char *str) { - selinux_enforcing = simple_strtol(str,NULL,0); + selinux_enforcing = simple_strtol(str, NULL, 0); return 1; } __setup("enforcing=", enforcing_setup); @@ -121,13 +123,13 @@ int selinux_enabled = 1; #endif /* Original (dummy) security module. */ -static struct security_operations *original_ops = NULL; +static struct security_operations *original_ops; /* Minimal support for a secondary security module, just to allow the use of the dummy or capability modules. The owlsm module can alternatively be used as a secondary module as long as CONFIG_OWLSM_FD is not enabled. */ -static struct security_operations *secondary_ops = NULL; +static struct security_operations *secondary_ops; /* Lists of inode and superblock security structures initialized before the policy was loaded. */ @@ -161,8 +163,7 @@ static int task_alloc_security(struct task_struct *task) if (!tsec) return -ENOMEM; - tsec->task = task; - tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED; + tsec->osid = tsec->sid = SECINITSID_UNLABELED; task->security = tsec; return 0; @@ -180,7 +181,7 @@ static int inode_alloc_security(struct inode *inode) struct task_security_struct *tsec = current->security; struct inode_security_struct *isec; - isec = kmem_cache_zalloc(sel_inode_cache, GFP_KERNEL); + isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS); if (!isec) return -ENOMEM; @@ -218,7 +219,6 @@ static int file_alloc_security(struct file *file) if (!fsec) return -ENOMEM; - fsec->file = file; fsec->sid = tsec->sid; fsec->fown_sid = tsec->sid; file->f_security = fsec; @@ -275,12 +275,11 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) if (!ssec) return -ENOMEM; - ssec->sk = sk; ssec->peer_sid = SECINITSID_UNLABELED; ssec->sid = SECINITSID_UNLABELED; sk->sk_security = ssec; - selinux_netlbl_sk_security_init(ssec, family); + selinux_netlbl_sk_security_reset(ssec, family); return 0; } @@ -324,10 +323,10 @@ enum { }; static match_table_t tokens = { - {Opt_context, "context=%s"}, - {Opt_fscontext, "fscontext=%s"}, - {Opt_defcontext, "defcontext=%s"}, - {Opt_rootcontext, "rootcontext=%s"}, + {Opt_context, CONTEXT_STR "%s"}, + {Opt_fscontext, FSCONTEXT_STR "%s"}, + {Opt_defcontext, DEFCONTEXT_STR "%s"}, + {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, {Opt_error, NULL}, }; @@ -576,8 +575,8 @@ static int selinux_set_mnt_opts(struct super_block *sb, goto out; } rc = -EINVAL; - printk(KERN_WARNING "Unable to set superblock options before " - "the security server is initialized\n"); + printk(KERN_WARNING "SELinux: Unable to set superblock options " + "before the security server is initialized\n"); goto out; } @@ -671,7 +670,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); if (rc) { printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", - __FUNCTION__, sb->s_type->name, rc); + __func__, sb->s_type->name, rc); goto out; } @@ -756,17 +755,26 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, int set_context = (oldsbsec->flags & CONTEXT_MNT); int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT); - /* we can't error, we can't save the info, this shouldn't get called - * this early in the boot process. */ - BUG_ON(!ss_initialized); - - /* this might go away sometime down the line if there is a new user - * of clone, but for now, nfs better not get here... */ - BUG_ON(newsbsec->initialized); + /* + * if the parent was able to be mounted it clearly had no special lsm + * mount options. thus we can safely put this sb on the list and deal + * with it later + */ + if (!ss_initialized) { + spin_lock(&sb_security_lock); + if (list_empty(&newsbsec->list)) + list_add(&newsbsec->list, &superblock_security_head); + spin_unlock(&sb_security_lock); + return; + } /* how can we clone if the old one wasn't set up?? */ BUG_ON(!oldsbsec->initialized); + /* if fs is reusing a sb, just let its options stand... */ + if (newsbsec->initialized) + return; + mutex_lock(&newsbsec->lock); newsbsec->flags = oldsbsec->flags; @@ -1055,7 +1063,7 @@ static int selinux_proc_get_sid(struct proc_dir_entry *de, int buflen, rc; char *buffer, *path, *end; - buffer = (char*)__get_free_page(GFP_KERNEL); + buffer = (char *)__get_free_page(GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -1136,14 +1144,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent dentry = d_find_alias(inode); } if (!dentry) { - printk(KERN_WARNING "%s: no dentry for dev=%s " - "ino=%ld\n", __FUNCTION__, inode->i_sb->s_id, + printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s " + "ino=%ld\n", __func__, inode->i_sb->s_id, inode->i_ino); goto out_unlock; } len = INITCONTEXTLEN; - context = kmalloc(len, GFP_KERNEL); + context = kmalloc(len, GFP_NOFS); if (!context) { rc = -ENOMEM; dput(dentry); @@ -1161,7 +1169,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent } kfree(context); len = rc; - context = kmalloc(len, GFP_KERNEL); + context = kmalloc(len, GFP_NOFS); if (!context) { rc = -ENOMEM; dput(dentry); @@ -1174,8 +1182,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent dput(dentry); if (rc < 0) { if (rc != -ENODATA) { - printk(KERN_WARNING "%s: getxattr returned " - "%d for dev=%s ino=%ld\n", __FUNCTION__, + printk(KERN_WARNING "SELinux: %s: getxattr returned " + "%d for dev=%s ino=%ld\n", __func__, -rc, inode->i_sb->s_id, inode->i_ino); kfree(context); goto out_unlock; @@ -1185,11 +1193,12 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent rc = 0; } else { rc = security_context_to_sid_default(context, rc, &sid, - sbsec->def_sid); + sbsec->def_sid, + GFP_NOFS); if (rc) { - printk(KERN_WARNING "%s: context_to_sid(%s) " + printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) " "returned %d for dev=%s ino=%ld\n", - __FUNCTION__, context, -rc, + __func__, context, -rc, inode->i_sb->s_id, inode->i_ino); kfree(context); /* Leave with the unlabeled SID */ @@ -1305,7 +1314,7 @@ static int task_has_capability(struct task_struct *tsk, tsec = tsk->security; - AVC_AUDIT_DATA_INIT(&ad,CAP); + AVC_AUDIT_DATA_INIT(&ad, CAP); ad.tsk = tsk; ad.u.cap = cap; @@ -1348,7 +1357,7 @@ static int inode_has_perm(struct task_struct *tsk, struct inode_security_struct *isec; struct avc_audit_data ad; - if (unlikely (IS_PRIVATE (inode))) + if (unlikely(IS_PRIVATE(inode))) return 0; tsec = tsk->security; @@ -1373,7 +1382,7 @@ static inline int dentry_has_perm(struct task_struct *tsk, { struct inode *inode = dentry->d_inode; struct avc_audit_data ad; - AVC_AUDIT_DATA_INIT(&ad,FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.mnt = mnt; ad.u.fs.path.dentry = dentry; return inode_has_perm(tsk, inode, av, &ad); @@ -1470,9 +1479,9 @@ static int may_create_key(u32 ksid, return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); } -#define MAY_LINK 0 -#define MAY_UNLINK 1 -#define MAY_RMDIR 2 +#define MAY_LINK 0 +#define MAY_UNLINK 1 +#define MAY_RMDIR 2 /* Check whether a task can link, unlink, or rmdir a file/directory. */ static int may_link(struct inode *dir, @@ -1510,7 +1519,8 @@ static int may_link(struct inode *dir, av = DIR__RMDIR; break; default: - printk(KERN_WARNING "may_link: unrecognized kind %d\n", kind); + printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n", + __func__, kind); return 0; } @@ -1617,6 +1627,35 @@ static inline u32 file_mask_to_av(int mode, int mask) return av; } +/* + * Convert a file mask to an access vector and include the correct open + * open permission. + */ +static inline u32 open_file_mask_to_av(int mode, int mask) +{ + u32 av = file_mask_to_av(mode, mask); + + if (selinux_policycap_openperm) { + /* + * lnk files and socks do not really have an 'open' + */ + if (S_ISREG(mode)) + av |= FILE__OPEN; + else if (S_ISCHR(mode)) + av |= CHR_FILE__OPEN; + else if (S_ISBLK(mode)) + av |= BLK_FILE__OPEN; + else if (S_ISFIFO(mode)) + av |= FIFO_FILE__OPEN; + else if (S_ISDIR(mode)) + av |= DIR__OPEN; + else + printk(KERN_ERR "SELinux: WARNING: inside %s with " + "unknown mode:%x\n", __func__, mode); + } + return av; +} + /* Convert a Linux file to an access vector. */ static inline u32 file_to_av(struct file *file) { @@ -1630,6 +1669,12 @@ static inline u32 file_to_av(struct file *file) else av |= FILE__WRITE; } + if (!av) { + /* + * Special file opened with flags 3 for ioctl-only use. + */ + av = FILE__IOCTL; + } return av; } @@ -1638,23 +1683,17 @@ static inline u32 file_to_av(struct file *file) static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) { - struct task_security_struct *psec = parent->security; - struct task_security_struct *csec = child->security; int rc; - rc = secondary_ops->ptrace(parent,child); + rc = secondary_ops->ptrace(parent, child); if (rc) return rc; - rc = task_has_perm(parent, child, PROCESS__PTRACE); - /* Save the SID of the tracing process for later use in apply_creds. */ - if (!(child->ptrace & PT_PTRACED) && !rc) - csec->ptrace_sid = psec->sid; - return rc; + return task_has_perm(parent, child, PROCESS__PTRACE); } static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, - kernel_cap_t *inheritable, kernel_cap_t *permitted) + kernel_cap_t *inheritable, kernel_cap_t *permitted) { int error; @@ -1666,7 +1705,7 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, } static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective, - kernel_cap_t *inheritable, kernel_cap_t *permitted) + kernel_cap_t *inheritable, kernel_cap_t *permitted) { int error; @@ -1678,7 +1717,7 @@ static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effect } static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective, - kernel_cap_t *inheritable, kernel_cap_t *permitted) + kernel_cap_t *inheritable, kernel_cap_t *permitted) { secondary_ops->capset_set(target, effective, inheritable, permitted); } @@ -1691,7 +1730,7 @@ static int selinux_capable(struct task_struct *tsk, int cap) if (rc) return rc; - return task_has_capability(tsk,cap); + return task_has_capability(tsk, cap); } static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) @@ -1700,7 +1739,7 @@ static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) char *buffer, *path, *end; rc = -ENOMEM; - buffer = (char*)__get_free_page(GFP_KERNEL); + buffer = (char *)__get_free_page(GFP_KERNEL); if (!buffer) goto out; @@ -1758,7 +1797,7 @@ static int selinux_sysctl(ctl_table *table, int op) /* The op values are "defined" in sysctl.c, thereby creating * a bad coupling between this module and sysctl.c */ - if(op == 001) { + if (op == 001) { error = avc_has_perm(tsec->sid, tsid, SECCLASS_DIR, DIR__SEARCH, NULL); } else { @@ -1770,7 +1809,7 @@ static int selinux_sysctl(ctl_table *table, int op) if (av) error = avc_has_perm(tsec->sid, tsid, SECCLASS_FILE, av, NULL); - } + } return error; } @@ -1783,25 +1822,23 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) return 0; switch (cmds) { - case Q_SYNC: - case Q_QUOTAON: - case Q_QUOTAOFF: - case Q_SETINFO: - case Q_SETQUOTA: - rc = superblock_has_perm(current, - sb, - FILESYSTEM__QUOTAMOD, NULL); - break; - case Q_GETFMT: - case Q_GETINFO: - case Q_GETQUOTA: - rc = superblock_has_perm(current, - sb, - FILESYSTEM__QUOTAGET, NULL); - break; - default: - rc = 0; /* let the kernel handle invalid cmds */ - break; + case Q_SYNC: + case Q_QUOTAON: + case Q_QUOTAOFF: + case Q_SETINFO: + case Q_SETQUOTA: + rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD, + NULL); + break; + case Q_GETFMT: + case Q_GETINFO: + case Q_GETQUOTA: + rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET, + NULL); + break; + default: + rc = 0; /* let the kernel handle invalid cmds */ + break; } return rc; } @@ -1820,23 +1857,23 @@ static int selinux_syslog(int type) return rc; switch (type) { - case 3: /* Read last kernel messages */ - case 10: /* Return size of the log buffer */ - rc = task_has_system(current, SYSTEM__SYSLOG_READ); - break; - case 6: /* Disable logging to console */ - case 7: /* Enable logging to console */ - case 8: /* Set level of messages printed to console */ - rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); - break; - case 0: /* Close log */ - case 1: /* Open log */ - case 2: /* Read from log */ - case 4: /* Read/clear last kernel messages */ - case 5: /* Clear ring buffer */ - default: - rc = task_has_system(current, SYSTEM__SYSLOG_MOD); - break; + case 3: /* Read last kernel messages */ + case 10: /* Return size of the log buffer */ + rc = task_has_system(current, SYSTEM__SYSLOG_READ); + break; + case 6: /* Disable logging to console */ + case 7: /* Enable logging to console */ + case 8: /* Set level of messages printed to console */ + rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); + break; + case 0: /* Close log */ + case 1: /* Open log */ + case 2: /* Read from log */ + case 4: /* Read/clear last kernel messages */ + case 5: /* Clear ring buffer */ + default: + rc = task_has_system(current, SYSTEM__SYSLOG_MOD); + break; } return rc; } @@ -1872,6 +1909,22 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) return __vm_enough_memory(mm, pages, cap_sys_admin); } +/** + * task_tracer_task - return the task that is tracing the given task + * @task: task to consider + * + * Returns NULL if noone is tracing @task, or the &struct task_struct + * pointer to its tracer. + * + * Must be called under rcu_read_lock(). + */ +static struct task_struct *task_tracer_task(struct task_struct *task) +{ + if (task->ptrace & PT_PTRACED) + return rcu_dereference(task->parent); + return NULL; +} + /* binprm security operations */ static int selinux_bprm_alloc_security(struct linux_binprm *bprm) @@ -1882,7 +1935,6 @@ static int selinux_bprm_alloc_security(struct linux_binprm *bprm) if (!bsec) return -ENOMEM; - bsec->bprm = bprm; bsec->sid = SECINITSID_UNLABELED; bsec->set = 0; @@ -1927,7 +1979,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) } else { /* Check for a default transition on this program. */ rc = security_transition_sid(tsec->sid, isec->sid, - SECCLASS_PROCESS, &newsid); + SECCLASS_PROCESS, &newsid); if (rc) return rc; } @@ -1938,7 +1990,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) newsid = tsec->sid; - if (tsec->sid == newsid) { + if (tsec->sid == newsid) { rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); if (rc) @@ -1966,13 +2018,13 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) return 0; } -static int selinux_bprm_check_security (struct linux_binprm *bprm) +static int selinux_bprm_check_security(struct linux_binprm *bprm) { return secondary_ops->bprm_check_security(bprm); } -static int selinux_bprm_secureexec (struct linux_binprm *bprm) +static int selinux_bprm_secureexec(struct linux_binprm *bprm) { struct task_security_struct *tsec = current->security; int atsecure = 0; @@ -1999,7 +2051,7 @@ extern struct vfsmount *selinuxfs_mount; extern struct dentry *selinux_null; /* Derived from fs/exec.c:flush_old_files. */ -static inline void flush_unauthorized_files(struct files_struct * files) +static inline void flush_unauthorized_files(struct files_struct *files) { struct avc_audit_data ad; struct file *file, *devnull = NULL; @@ -2034,7 +2086,7 @@ static inline void flush_unauthorized_files(struct files_struct * files) /* Revalidate access to inherited open files. */ - AVC_AUDIT_DATA_INIT(&ad,FS); + AVC_AUDIT_DATA_INIT(&ad, FS); spin_lock(&files->file_lock); for (;;) { @@ -2050,7 +2102,7 @@ static inline void flush_unauthorized_files(struct files_struct * files) if (!set) continue; spin_unlock(&files->file_lock); - for ( ; set ; i++,set >>= 1) { + for ( ; set ; i++, set >>= 1) { if (set & 1) { file = fget(i); if (!file) @@ -2119,12 +2171,25 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and kill. */ if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { - rc = avc_has_perm(tsec->ptrace_sid, sid, - SECCLASS_PROCESS, PROCESS__PTRACE, - NULL); - if (rc) { - bsec->unsafe = 1; - return; + struct task_struct *tracer; + struct task_security_struct *sec; + u32 ptsid = 0; + + rcu_read_lock(); + tracer = task_tracer_task(current); + if (likely(tracer != NULL)) { + sec = tracer->security; + ptsid = sec->sid; + } + rcu_read_unlock(); + + if (ptsid != 0) { + rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, + PROCESS__PTRACE, NULL); + if (rc) { + bsec->unsafe = 1; + return; + } } } tsec->sid = sid; @@ -2194,7 +2259,7 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) for (i = 0; i < RLIM_NLIMITS; i++) { rlim = current->signal->rlim + i; initrlim = init_task.signal->rlim+i; - rlim->rlim_cur = min(rlim->rlim_max,initrlim->rlim_cur); + rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); } if (current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) { /* @@ -2232,10 +2297,10 @@ static inline int match_prefix(char *prefix, int plen, char *option, int olen) static inline int selinux_option(char *option, int len) { - return (match_prefix("context=", sizeof("context=")-1, option, len) || - match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || - match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) || - match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len)); + return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || + match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || + match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || + match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len)); } static inline void take_option(char **to, char *from, int *first, int len) @@ -2249,16 +2314,15 @@ static inline void take_option(char **to, char *from, int *first, int len) *to += len; } -static inline void take_selinux_option(char **to, char *from, int *first, - int len) +static inline void take_selinux_option(char **to, char *from, int *first, + int len) { int current_size = 0; if (!*first) { **to = '|'; *to += 1; - } - else + } else *first = 0; while (current_size < len) { @@ -2322,7 +2386,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data) if (rc) return rc; - AVC_AUDIT_DATA_INIT(&ad,FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = sb->s_root; return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad); } @@ -2331,29 +2395,29 @@ static int selinux_sb_statfs(struct dentry *dentry) { struct avc_audit_data ad; - AVC_AUDIT_DATA_INIT(&ad,FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry->d_sb->s_root; return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } -static int selinux_mount(char * dev_name, - struct nameidata *nd, - char * type, - unsigned long flags, - void * data) +static int selinux_mount(char *dev_name, + struct path *path, + char *type, + unsigned long flags, + void *data) { int rc; - rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data); + rc = secondary_ops->sb_mount(dev_name, path, type, flags, data); if (rc) return rc; if (flags & MS_REMOUNT) - return superblock_has_perm(current, nd->path.mnt->mnt_sb, - FILESYSTEM__REMOUNT, NULL); + return superblock_has_perm(current, path->mnt->mnt_sb, + FILESYSTEM__REMOUNT, NULL); else - return dentry_has_perm(current, nd->path.mnt, nd->path.dentry, - FILE__MOUNTON); + return dentry_has_perm(current, path->mnt, path->dentry, + FILE__MOUNTON); } static int selinux_umount(struct vfsmount *mnt, int flags) @@ -2364,8 +2428,8 @@ static int selinux_umount(struct vfsmount *mnt, int flags) if (rc) return rc; - return superblock_has_perm(current,mnt->mnt_sb, - FILESYSTEM__UNMOUNT,NULL); + return superblock_has_perm(current, mnt->mnt_sb, + FILESYSTEM__UNMOUNT, NULL); } /* inode security operations */ @@ -2405,7 +2469,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, printk(KERN_WARNING "%s: " "security_transition_sid failed, rc=%d (dev=%s " "ino=%ld)\n", - __FUNCTION__, + __func__, -rc, inode->i_sb->s_id, inode->i_ino); return rc; } @@ -2423,7 +2487,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, return -EOPNOTSUPP; if (name) { - namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL); + namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS); if (!namep) return -ENOMEM; *name = namep; @@ -2451,7 +2515,7 @@ static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, stru { int rc; - rc = secondary_ops->inode_link(old_dentry,dir,new_dentry); + rc = secondary_ops->inode_link(old_dentry, dir, new_dentry); if (rc) return rc; return may_link(dir, old_dentry, MAY_LINK); @@ -2494,7 +2558,7 @@ static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mod } static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry, - struct inode *new_inode, struct dentry *new_dentry) + struct inode *new_inode, struct dentry *new_dentry) { return may_rename(old_inode, old_dentry, new_inode, new_dentry); } @@ -2508,7 +2572,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na { int rc; - rc = secondary_ops->inode_follow_link(dentry,nameidata); + rc = secondary_ops->inode_follow_link(dentry, nameidata); if (rc) return rc; return dentry_has_perm(current, NULL, dentry, FILE__READ); @@ -2529,7 +2593,7 @@ static int selinux_inode_permission(struct inode *inode, int mask, } return inode_has_perm(current, inode, - file_mask_to_av(inode->i_mode, mask), NULL); + open_file_mask_to_av(inode->i_mode, mask), NULL); } static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) @@ -2594,7 +2658,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value if (!is_owner_or_cap(inode)) return -EPERM; - AVC_AUDIT_DATA_INIT(&ad,FS); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.path.dentry = dentry; rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, @@ -2612,7 +2676,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value return rc; rc = security_validate_transition(isec->sid, newsid, tsec->sid, - isec->sclass); + isec->sclass); if (rc) return rc; @@ -2624,7 +2688,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value } static void selinux_inode_post_setxattr(struct dentry *dentry, char *name, - void *value, size_t size, int flags) + void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; struct inode_security_struct *isec = inode->i_security; @@ -2639,7 +2703,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name, rc = security_context_to_sid(value, size, &newsid); if (rc) { printk(KERN_WARNING "%s: unable to obtain SID for context " - "%s, rc=%d\n", __FUNCTION__, (char*)value, -rc); + "%s, rc=%d\n", __func__, (char *)value, -rc); return; } @@ -2647,17 +2711,17 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name, return; } -static int selinux_inode_getxattr (struct dentry *dentry, char *name) +static int selinux_inode_getxattr(struct dentry *dentry, char *name) { return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); } -static int selinux_inode_listxattr (struct dentry *dentry) +static int selinux_inode_listxattr(struct dentry *dentry) { return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); } -static int selinux_inode_removexattr (struct dentry *dentry, char *name) +static int selinux_inode_removexattr(struct dentry *dentry, char *name) { if (strcmp(name, XATTR_NAME_SELINUX)) return selinux_inode_setotherxattr(dentry, name); @@ -2698,7 +2762,7 @@ out_nofree: } static int selinux_inode_setsecurity(struct inode *inode, const char *name, - const void *value, size_t size, int flags) + const void *value, size_t size, int flags) { struct inode_security_struct *isec = inode->i_security; u32 newsid; @@ -2710,7 +2774,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, if (!value || !size) return -EACCES; - rc = security_context_to_sid((void*)value, size, &newsid); + rc = security_context_to_sid((void *)value, size, &newsid); if (rc) return rc; @@ -2736,6 +2800,12 @@ static int selinux_inode_killpriv(struct dentry *dentry) return secondary_ops->inode_killpriv(dentry); } +static void selinux_inode_getsecid(const struct inode *inode, u32 *secid) +{ + struct inode_security_struct *isec = inode->i_security; + *secid = isec->sid; +} + /* file security operations */ static int selinux_revalidate_file_permission(struct file *file, int mask) @@ -2795,42 +2865,41 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, int error = 0; switch (cmd) { - case FIONREAD: - /* fall through */ - case FIBMAP: - /* fall through */ - case FIGETBSZ: - /* fall through */ - case EXT2_IOC_GETFLAGS: - /* fall through */ - case EXT2_IOC_GETVERSION: - error = file_has_perm(current, file, FILE__GETATTR); - break; - - case EXT2_IOC_SETFLAGS: - /* fall through */ - case EXT2_IOC_SETVERSION: - error = file_has_perm(current, file, FILE__SETATTR); - break; + case FIONREAD: + /* fall through */ + case FIBMAP: + /* fall through */ + case FIGETBSZ: + /* fall through */ + case EXT2_IOC_GETFLAGS: + /* fall through */ + case EXT2_IOC_GETVERSION: + error = file_has_perm(current, file, FILE__GETATTR); + break; - /* sys_ioctl() checks */ - case FIONBIO: - /* fall through */ - case FIOASYNC: - error = file_has_perm(current, file, 0); - break; + case EXT2_IOC_SETFLAGS: + /* fall through */ + case EXT2_IOC_SETVERSION: + error = file_has_perm(current, file, FILE__SETATTR); + break; - case KDSKBENT: - case KDSKBSENT: - error = task_has_capability(current,CAP_SYS_TTY_CONFIG); - break; + /* sys_ioctl() checks */ + case FIONBIO: + /* fall through */ + case FIOASYNC: + error = file_has_perm(current, file, 0); + break; - /* default case assumes that the command will go - * to the file's ioctl() function. - */ - default: - error = file_has_perm(current, file, FILE__IOCTL); + case KDSKBENT: + case KDSKBSENT: + error = task_has_capability(current, CAP_SYS_TTY_CONFIG); + break; + /* default case assumes that the command will go + * to the file's ioctl() function. + */ + default: + error = file_has_perm(current, file, FILE__IOCTL); } return error; } @@ -2871,7 +2940,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, unsigned long addr, unsigned long addr_only) { int rc = 0; - u32 sid = ((struct task_security_struct*)(current->security))->sid; + u32 sid = ((struct task_security_struct *)(current->security))->sid; if (addr < mmap_min_addr) rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, @@ -2940,39 +3009,39 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd, int err = 0; switch (cmd) { - case F_SETFL: - if (!file->f_path.dentry || !file->f_path.dentry->d_inode) { - err = -EINVAL; - break; - } + case F_SETFL: + if (!file->f_path.dentry || !file->f_path.dentry->d_inode) { + err = -EINVAL; + break; + } - if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) { - err = file_has_perm(current, file,FILE__WRITE); - break; - } - /* fall through */ - case F_SETOWN: - case F_SETSIG: - case F_GETFL: - case F_GETOWN: - case F_GETSIG: - /* Just check FD__USE permission */ - err = file_has_perm(current, file, 0); + if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) { + err = file_has_perm(current, file, FILE__WRITE); break; - case F_GETLK: - case F_SETLK: - case F_SETLKW: + } + /* fall through */ + case F_SETOWN: + case F_SETSIG: + case F_GETFL: + case F_GETOWN: + case F_GETSIG: + /* Just check FD__USE permission */ + err = file_has_perm(current, file, 0); + break; + case F_GETLK: + case F_SETLK: + case F_SETLKW: #if BITS_PER_LONG == 32 - case F_GETLK64: - case F_SETLK64: - case F_SETLKW64: + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: #endif - if (!file->f_path.dentry || !file->f_path.dentry->d_inode) { - err = -EINVAL; - break; - } - err = file_has_perm(current, file, FILE__LOCK); + if (!file->f_path.dentry || !file->f_path.dentry->d_inode) { + err = -EINVAL; break; + } + err = file_has_perm(current, file, FILE__LOCK); + break; } return err; @@ -2993,13 +3062,13 @@ static int selinux_file_set_fowner(struct file *file) static int selinux_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int signum) { - struct file *file; + struct file *file; u32 perm; struct task_security_struct *tsec; struct file_security_struct *fsec; /* struct fown_struct is never outside the context of a struct file */ - file = container_of(fown, struct file, f_owner); + file = container_of(fown, struct file, f_owner); tsec = tsk->security; fsec = file->f_security; @@ -3080,11 +3149,6 @@ static int selinux_task_alloc_security(struct task_struct *tsk) tsec2->keycreate_sid = tsec1->keycreate_sid; tsec2->sockcreate_sid = tsec1->sockcreate_sid; - /* Retain ptracer SID across fork, if any. - This will be reset by the ptrace hook upon any - subsequent ptrace_attach operations. */ - tsec2->ptrace_sid = tsec1->ptrace_sid; - return 0; } @@ -3106,7 +3170,7 @@ static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { - return secondary_ops->task_post_setuid(id0,id1,id2,flags); + return secondary_ops->task_post_setuid(id0, id1, id2, flags); } static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) @@ -3132,7 +3196,8 @@ static int selinux_task_getsid(struct task_struct *p) static void selinux_task_getsecid(struct task_struct *p, u32 *secid) { - selinux_get_task_sid(p, secid); + struct task_security_struct *tsec = p->security; + *secid = tsec->sid; } static int selinux_task_setgroups(struct group_info *group_info) @@ -3149,7 +3214,7 @@ static int selinux_task_setnice(struct task_struct *p, int nice) if (rc) return rc; - return task_has_perm(current,p, PROCESS__SETSCHED); + return task_has_perm(current, p, PROCESS__SETSCHED); } static int selinux_task_setioprio(struct task_struct *p, int ioprio) @@ -3253,7 +3318,7 @@ static int selinux_task_wait(struct task_struct *p) static void selinux_task_reparent_to_init(struct task_struct *p) { - struct task_security_struct *tsec; + struct task_security_struct *tsec; secondary_ops->task_reparent_to_init(p); @@ -3298,11 +3363,11 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, *proto = ih->protocol; switch (ih->protocol) { - case IPPROTO_TCP: { - struct tcphdr _tcph, *th; + case IPPROTO_TCP: { + struct tcphdr _tcph, *th; - if (ntohs(ih->frag_off) & IP_OFFSET) - break; + if (ntohs(ih->frag_off) & IP_OFFSET) + break; offset += ihlen; th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); @@ -3312,23 +3377,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, ad->u.net.sport = th->source; ad->u.net.dport = th->dest; break; - } - - case IPPROTO_UDP: { - struct udphdr _udph, *uh; - - if (ntohs(ih->frag_off) & IP_OFFSET) - break; - + } + + case IPPROTO_UDP: { + struct udphdr _udph, *uh; + + if (ntohs(ih->frag_off) & IP_OFFSET) + break; + offset += ihlen; - uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); + uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); if (uh == NULL) - break; + break; - ad->u.net.sport = uh->source; - ad->u.net.dport = uh->dest; - break; - } + ad->u.net.sport = uh->source; + ad->u.net.dport = uh->dest; + break; + } case IPPROTO_DCCP: { struct dccp_hdr _dccph, *dh; @@ -3344,11 +3409,11 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, ad->u.net.sport = dh->dccph_sport; ad->u.net.dport = dh->dccph_dport; break; - } + } - default: - break; - } + default: + break; + } out: return ret; } @@ -3383,7 +3448,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, switch (nexthdr) { case IPPROTO_TCP: { - struct tcphdr _tcph, *th; + struct tcphdr _tcph, *th; th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); if (th == NULL) @@ -3416,7 +3481,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, ad->u.net.sport = dh->dccph_sport; ad->u.net.dport = dh->dccph_dport; break; - } + } /* includes fragments */ default: @@ -3514,7 +3579,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, if (isec->sid == SECINITSID_KERNEL) goto out; - AVC_AUDIT_DATA_INIT(&ad,NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = sock->sk; err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad); @@ -3620,13 +3685,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in inet_get_local_port_range(&low, &high); if (snum < max(PROT_SOCK, low) || snum > high) { - err = security_port_sid(sk->sk_family, - sk->sk_type, - sk->sk_protocol, snum, - &sid); + err = sel_netport_sid(sk->sk_protocol, + snum, &sid); if (err) goto out; - AVC_AUDIT_DATA_INIT(&ad,NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sport = htons(snum); ad.u.net.family = family; err = avc_has_perm(isec->sid, sid, @@ -3636,12 +3699,12 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in goto out; } } - - switch(isec->sclass) { + + switch (isec->sclass) { case SECCLASS_TCP_SOCKET: node_perm = TCP_SOCKET__NODE_BIND; break; - + case SECCLASS_UDP_SOCKET: node_perm = UDP_SOCKET__NODE_BIND; break; @@ -3654,12 +3717,12 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in node_perm = RAWIP_SOCKET__NODE_BIND; break; } - + err = sel_netnode_sid(addrp, family, &sid); if (err) goto out; - - AVC_AUDIT_DATA_INIT(&ad,NET); + + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sport = htons(snum); ad.u.net.family = family; @@ -3669,7 +3732,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr); err = avc_has_perm(isec->sid, sid, - isec->sclass, node_perm, &ad); + isec->sclass, node_perm, &ad); if (err) goto out; } @@ -3711,15 +3774,14 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, snum = ntohs(addr6->sin6_port); } - err = security_port_sid(sk->sk_family, sk->sk_type, - sk->sk_protocol, snum, &sid); + err = sel_netport_sid(sk->sk_protocol, snum, &sid); if (err) goto out; perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; - AVC_AUDIT_DATA_INIT(&ad,NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.dport = htons(snum); ad.u.net.family = sk->sk_family; err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); @@ -3757,7 +3819,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) } static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, - int size) + int size) { int rc; @@ -3784,7 +3846,7 @@ static int selinux_socket_getpeername(struct socket *sock) return socket_has_perm(current, sock, SOCKET__GETATTR); } -static int selinux_socket_setsockopt(struct socket *sock,int level,int optname) +static int selinux_socket_setsockopt(struct socket *sock, int level, int optname) { int err; @@ -3823,7 +3885,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, isec = SOCK_INODE(sock)->i_security; other_isec = SOCK_INODE(other)->i_security; - AVC_AUDIT_DATA_INIT(&ad,NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = other->sk; err = avc_has_perm(isec->sid, other_isec->sid, @@ -3835,7 +3897,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, /* connecting socket */ ssec = sock->sk->sk_security; ssec->peer_sid = other_isec->sid; - + /* server child socket */ ssec = newsk->sk_security; ssec->peer_sid = isec->sid; @@ -3855,7 +3917,7 @@ static int selinux_socket_unix_may_send(struct socket *sock, isec = SOCK_INODE(sock)->i_security; other_isec = SOCK_INODE(other)->i_security; - AVC_AUDIT_DATA_INIT(&ad,NET); + AVC_AUDIT_DATA_INIT(&ad, NET); ad.u.net.sk = other->sk; err = avc_has_perm(isec->sid, other_isec->sid, @@ -3933,7 +3995,7 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); if (err) return err; - + err = sel_netnode_sid(addrp, family, &node_sid); if (err) return err; @@ -3943,9 +4005,8 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, if (!recv_perm) return 0; - err = security_port_sid(sk->sk_family, sk->sk_type, - sk->sk_protocol, ntohs(ad->u.net.sport), - &port_sid); + err = sel_netport_sid(sk->sk_protocol, + ntohs(ad->u.net.sport), &port_sid); if (unlikely(err)) { printk(KERN_WARNING "SELinux: failure in" @@ -4085,7 +4146,7 @@ out_len: err = -EFAULT; kfree(scontext); -out: +out: return err; } @@ -4102,7 +4163,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * goto out; if (sock && family == PF_UNIX) - selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); + selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid); else if (skb) selinux_skb_peerlbl_sid(skb, family, &peer_secid); @@ -4132,7 +4193,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) newssec->peer_sid = ssec->peer_sid; newssec->sclass = ssec->sclass; - selinux_netlbl_sk_security_clone(ssec, newssec); + selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); } static void selinux_sk_getsecid(struct sock *sk, u32 *secid) @@ -4146,7 +4207,7 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid) } } -static void selinux_sock_graft(struct sock* sk, struct socket *parent) +static void selinux_sock_graft(struct sock *sk, struct socket *parent) { struct inode_security_struct *isec = SOCK_INODE(parent)->i_security; struct sk_security_struct *sksec = sk->sk_security; @@ -4223,13 +4284,13 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) struct nlmsghdr *nlh; struct socket *sock = sk->sk_socket; struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; - + if (skb->len < NLMSG_SPACE(0)) { err = -EINVAL; goto out; } nlh = nlmsg_hdr(skb); - + err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm); if (err) { if (err == -EINVAL) { @@ -4355,7 +4416,7 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk, return err; err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); return err; - + err = sel_netnode_sid(addrp, family, &node_sid); if (err) return err; @@ -4366,9 +4427,8 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk, if (send_perm != 0) return 0; - err = security_port_sid(sk->sk_family, sk->sk_type, - sk->sk_protocol, ntohs(ad->u.net.dport), - &port_sid); + err = sel_netport_sid(sk->sk_protocol, + ntohs(ad->u.net.dport), &port_sid); if (unlikely(err)) { printk(KERN_WARNING "SELinux: failure in" @@ -4539,7 +4599,7 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability) ad.u.cap = capability; return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, - SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad); + SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad); } static int ipc_alloc_security(struct task_struct *task, @@ -4554,7 +4614,6 @@ static int ipc_alloc_security(struct task_struct *task, return -ENOMEM; isec->sclass = sclass; - isec->ipc_perm = perm; isec->sid = tsec->sid; perm->security = isec; @@ -4576,7 +4635,6 @@ static int msg_msg_alloc_security(struct msg_msg *msg) if (!msec) return -ENOMEM; - msec->msg = msg; msec->sid = SECINITSID_UNLABELED; msg->security = msec; @@ -4633,7 +4691,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) isec = msq->q_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); - ad.u.ipc_id = msq->q_perm.key; + ad.u.ipc_id = msq->q_perm.key; rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ, MSGQ__CREATE, &ad); @@ -4670,7 +4728,7 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd) int err; int perms; - switch(cmd) { + switch (cmd) { case IPC_INFO: case MSG_INFO: /* No specific object, just general system-wide information. */ @@ -4754,7 +4812,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, msec = msg->security; AVC_AUDIT_DATA_INIT(&ad, IPC); - ad.u.ipc_id = msq->q_perm.key; + ad.u.ipc_id = msq->q_perm.key; rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ, MSGQ__READ, &ad); @@ -4780,7 +4838,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) isec = shp->shm_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); - ad.u.ipc_id = shp->shm_perm.key; + ad.u.ipc_id = shp->shm_perm.key; rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM, SHM__CREATE, &ad); @@ -4818,7 +4876,7 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd) int perms; int err; - switch(cmd) { + switch (cmd) { case IPC_INFO: case SHM_INFO: /* No specific object, just general system-wide information. */ @@ -4879,7 +4937,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) isec = sma->sem_perm.security; AVC_AUDIT_DATA_INIT(&ad, IPC); - ad.u.ipc_id = sma->sem_perm.key; + ad.u.ipc_id = sma->sem_perm.key; rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM, SEM__CREATE, &ad); @@ -4917,7 +4975,7 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd) int err; u32 perms; - switch(cmd) { + switch (cmd) { case IPC_INFO: case SEM_INFO: /* No specific object, just general system-wide information. */ @@ -4982,25 +5040,31 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) return ipc_has_perm(ipcp, av); } +static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) +{ + struct ipc_security_struct *isec = ipcp->security; + *secid = isec->sid; +} + /* module stacking operations */ -static int selinux_register_security (const char *name, struct security_operations *ops) +static int selinux_register_security(const char *name, struct security_operations *ops) { if (secondary_ops != original_ops) { printk(KERN_ERR "%s: There is already a secondary security " - "module registered.\n", __FUNCTION__); + "module registered.\n", __func__); return -EINVAL; - } + } secondary_ops = ops; printk(KERN_INFO "%s: Registering secondary module %s\n", - __FUNCTION__, + __func__, name); return 0; } -static void selinux_d_instantiate (struct dentry *dentry, struct inode *inode) +static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode) { if (inode) inode_doinit_with_dentry(inode, dentry); @@ -5050,6 +5114,7 @@ static int selinux_setprocattr(struct task_struct *p, char *name, void *value, size_t size) { struct task_security_struct *tsec; + struct task_struct *tracer; u32 sid = 0; int error; char *str = value; @@ -5127,34 +5192,39 @@ static int selinux_setprocattr(struct task_struct *p, } while_each_thread(g, t); read_unlock(&tasklist_lock); - } + } /* Check permissions for the transition. */ error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, - PROCESS__DYNTRANSITION, NULL); + PROCESS__DYNTRANSITION, NULL); if (error) return error; /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and fail. */ task_lock(p); - if (p->ptrace & PT_PTRACED) { - error = avc_has_perm_noaudit(tsec->ptrace_sid, sid, + rcu_read_lock(); + tracer = task_tracer_task(p); + if (tracer != NULL) { + struct task_security_struct *ptsec = tracer->security; + u32 ptsid = ptsec->sid; + rcu_read_unlock(); + error = avc_has_perm_noaudit(ptsid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, 0, &avd); if (!error) tsec->sid = sid; task_unlock(p); - avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, + avc_audit(ptsid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, &avd, error, NULL); if (error) return error; } else { + rcu_read_unlock(); tsec->sid = sid; task_unlock(p); } - } - else + } else return -EINVAL; return size; @@ -5187,7 +5257,6 @@ static int selinux_key_alloc(struct key *k, struct task_struct *tsk, if (!ksec) return -ENOMEM; - ksec->obj = k; if (tsec->keycreate_sid) ksec->sid = tsec->keycreate_sid; else @@ -5231,6 +5300,8 @@ static int selinux_key_permission(key_ref_t key_ref, #endif static struct security_operations selinux_ops = { + .name = "selinux", + .ptrace = selinux_ptrace, .capget = selinux_capget, .capset_check = selinux_capset_check, @@ -5243,7 +5314,7 @@ static struct security_operations selinux_ops = { .vm_enough_memory = selinux_vm_enough_memory, .netlink_send = selinux_netlink_send, - .netlink_recv = selinux_netlink_recv, + .netlink_recv = selinux_netlink_recv, .bprm_alloc_security = selinux_bprm_alloc_security, .bprm_free_security = selinux_bprm_free_security, @@ -5256,13 +5327,13 @@ static struct security_operations selinux_ops = { .sb_alloc_security = selinux_sb_alloc_security, .sb_free_security = selinux_sb_free_security, .sb_copy_data = selinux_sb_copy_data, - .sb_kern_mount = selinux_sb_kern_mount, + .sb_kern_mount = selinux_sb_kern_mount, .sb_statfs = selinux_sb_statfs, .sb_mount = selinux_mount, .sb_umount = selinux_umount, .sb_get_mnt_opts = selinux_get_mnt_opts, .sb_set_mnt_opts = selinux_set_mnt_opts, - .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, + .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, .sb_parse_opts_str = selinux_parse_opts_str, @@ -5287,11 +5358,12 @@ static struct security_operations selinux_ops = { .inode_getxattr = selinux_inode_getxattr, .inode_listxattr = selinux_inode_listxattr, .inode_removexattr = selinux_inode_removexattr, - .inode_getsecurity = selinux_inode_getsecurity, - .inode_setsecurity = selinux_inode_setsecurity, - .inode_listsecurity = selinux_inode_listsecurity, + .inode_getsecurity = selinux_inode_getsecurity, + .inode_setsecurity = selinux_inode_setsecurity, + .inode_listsecurity = selinux_inode_listsecurity, .inode_need_killpriv = selinux_inode_need_killpriv, .inode_killpriv = selinux_inode_killpriv, + .inode_getsecid = selinux_inode_getsecid, .file_permission = selinux_file_permission, .file_alloc_security = selinux_file_alloc_security, @@ -5305,7 +5377,7 @@ static struct security_operations selinux_ops = { .file_send_sigiotask = selinux_file_send_sigiotask, .file_receive = selinux_file_receive, - .dentry_open = selinux_dentry_open, + .dentry_open = selinux_dentry_open, .task_create = selinux_task_create, .task_alloc_security = selinux_task_alloc_security, @@ -5315,7 +5387,7 @@ static struct security_operations selinux_ops = { .task_setgid = selinux_task_setgid, .task_setpgid = selinux_task_setpgid, .task_getpgid = selinux_task_getpgid, - .task_getsid = selinux_task_getsid, + .task_getsid = selinux_task_getsid, .task_getsecid = selinux_task_getsecid, .task_setgroups = selinux_task_setgroups, .task_setnice = selinux_task_setnice, @@ -5329,9 +5401,10 @@ static struct security_operations selinux_ops = { .task_wait = selinux_task_wait, .task_prctl = selinux_task_prctl, .task_reparent_to_init = selinux_task_reparent_to_init, - .task_to_inode = selinux_task_to_inode, + .task_to_inode = selinux_task_to_inode, .ipc_permission = selinux_ipc_permission, + .ipc_getsecid = selinux_ipc_getsecid, .msg_msg_alloc_security = selinux_msg_msg_alloc_security, .msg_msg_free_security = selinux_msg_msg_free_security, @@ -5349,24 +5422,24 @@ static struct security_operations selinux_ops = { .shm_shmctl = selinux_shm_shmctl, .shm_shmat = selinux_shm_shmat, - .sem_alloc_security = selinux_sem_alloc_security, - .sem_free_security = selinux_sem_free_security, + .sem_alloc_security = selinux_sem_alloc_security, + .sem_free_security = selinux_sem_free_security, .sem_associate = selinux_sem_associate, .sem_semctl = selinux_sem_semctl, .sem_semop = selinux_sem_semop, .register_security = selinux_register_security, - .d_instantiate = selinux_d_instantiate, + .d_instantiate = selinux_d_instantiate, - .getprocattr = selinux_getprocattr, - .setprocattr = selinux_setprocattr, + .getprocattr = selinux_getprocattr, + .setprocattr = selinux_setprocattr, .secid_to_secctx = selinux_secid_to_secctx, .secctx_to_secid = selinux_secctx_to_secid, .release_secctx = selinux_release_secctx, - .unix_stream_connect = selinux_socket_unix_stream_connect, + .unix_stream_connect = selinux_socket_unix_stream_connect, .unix_may_send = selinux_socket_unix_may_send, .socket_create = selinux_socket_create, @@ -5388,7 +5461,7 @@ static struct security_operations selinux_ops = { .sk_alloc_security = selinux_sk_alloc_security, .sk_free_security = selinux_sk_free_security, .sk_clone_security = selinux_sk_clone_security, - .sk_getsecid = selinux_sk_getsecid, + .sk_getsecid = selinux_sk_getsecid, .sock_graft = selinux_sock_graft, .inet_conn_request = selinux_inet_conn_request, .inet_csk_clone = selinux_inet_csk_clone, @@ -5403,15 +5476,22 @@ static struct security_operations selinux_ops = { .xfrm_state_alloc_security = selinux_xfrm_state_alloc, .xfrm_state_free_security = selinux_xfrm_state_free, .xfrm_state_delete_security = selinux_xfrm_state_delete, - .xfrm_policy_lookup = selinux_xfrm_policy_lookup, + .xfrm_policy_lookup = selinux_xfrm_policy_lookup, .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match, .xfrm_decode_session = selinux_xfrm_decode_session, #endif #ifdef CONFIG_KEYS - .key_alloc = selinux_key_alloc, - .key_free = selinux_key_free, - .key_permission = selinux_key_permission, + .key_alloc = selinux_key_alloc, + .key_free = selinux_key_free, + .key_permission = selinux_key_permission, +#endif + +#ifdef CONFIG_AUDIT + .audit_rule_init = selinux_audit_rule_init, + .audit_rule_known = selinux_audit_rule_known, + .audit_rule_match = selinux_audit_rule_match, + .audit_rule_free = selinux_audit_rule_free, #endif }; @@ -5419,6 +5499,11 @@ static __init int selinux_init(void) { struct task_security_struct *tsec; + if (!security_module_enable(&selinux_ops)) { + selinux_enabled = 0; + return 0; + } + if (!selinux_enabled) { printk(KERN_INFO "SELinux: Disabled at boot.\n"); return 0; @@ -5439,15 +5524,14 @@ static __init int selinux_init(void) original_ops = secondary_ops = security_ops; if (!secondary_ops) - panic ("SELinux: No initial security operations\n"); - if (register_security (&selinux_ops)) + panic("SELinux: No initial security operations\n"); + if (register_security(&selinux_ops)) panic("SELinux: Unable to register with kernel.\n"); - if (selinux_enforcing) { + if (selinux_enforcing) printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); - } else { + else printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); - } #ifdef CONFIG_KEYS /* Add security information to initial keyrings */ @@ -5472,8 +5556,8 @@ next_sb: if (!list_empty(&superblock_security_head)) { struct superblock_security_struct *sbsec = list_entry(superblock_security_head.next, - struct superblock_security_struct, - list); + struct superblock_security_struct, + list); struct super_block *sb = sbsec->sb; sb->s_count++; spin_unlock(&sb_security_lock); @@ -5592,10 +5676,11 @@ static void selinux_nf_ip_exit(void) #endif /* CONFIG_NETFILTER */ #ifdef CONFIG_SECURITY_SELINUX_DISABLE +static int selinux_disabled; + int selinux_disable(void) { extern void exit_sel_fs(void); - static int selinux_disabled = 0; if (ss_initialized) { /* Not permitted after initial policy load. */ @@ -5624,5 +5709,3 @@ int selinux_disable(void) return 0; } #endif - - diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h new file mode 100644 index 00000000000..6c8b9ef1557 --- /dev/null +++ b/security/selinux/include/audit.h @@ -0,0 +1,65 @@ +/* + * SELinux support for the Audit LSM hooks + * + * Most of below header was moved from include/linux/selinux.h which + * is released under below copyrights: + * + * Author: James Morris <jmorris@redhat.com> + * + * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com> + * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> + * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com> + * + * 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. + */ + +#ifndef _SELINUX_AUDIT_H +#define _SELINUX_AUDIT_H + +/** + * selinux_audit_rule_init - alloc/init an selinux audit rule structure. + * @field: the field this rule refers to + * @op: the operater the rule uses + * @rulestr: the text "target" of the rule + * @rule: pointer to the new rule structure returned via this + * + * Returns 0 if successful, -errno if not. On success, the rule structure + * will be allocated internally. The caller must free this structure with + * selinux_audit_rule_free() after use. + */ +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule); + +/** + * selinux_audit_rule_free - free an selinux audit rule structure. + * @rule: pointer to the audit rule to be freed + * + * This will free all memory associated with the given rule. + * If @rule is NULL, no operation is performed. + */ +void selinux_audit_rule_free(void *rule); + +/** + * selinux_audit_rule_match - determine if a context ID matches a rule. + * @sid: the context ID to check + * @field: the field this rule refers to + * @op: the operater the rule uses + * @rule: pointer to the audit rule to check against + * @actx: the audit context (can be NULL) associated with the check + * + * Returns 1 if the context id matches the rule, 0 if it does not, and + * -errno on failure. + */ +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, + struct audit_context *actx); + +/** + * selinux_audit_rule_known - check to see if rule contains selinux fields. + * @rule: rule to be checked + * Returns 1 if there are selinux fields specified in the rule, 0 otherwise. + */ +int selinux_audit_rule_known(struct audit_krule *krule); + +#endif /* _SELINUX_AUDIT_H */ + diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index d5696690d3a..1223b4ff9be 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h @@ -14,12 +14,17 @@ S_(SECCLASS_DIR, DIR__REPARENT, "reparent") S_(SECCLASS_DIR, DIR__SEARCH, "search") S_(SECCLASS_DIR, DIR__RMDIR, "rmdir") + S_(SECCLASS_DIR, DIR__OPEN, "open") S_(SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, "execute_no_trans") S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint") S_(SECCLASS_FILE, FILE__EXECMOD, "execmod") + S_(SECCLASS_FILE, FILE__OPEN, "open") S_(SECCLASS_CHR_FILE, CHR_FILE__EXECUTE_NO_TRANS, "execute_no_trans") S_(SECCLASS_CHR_FILE, CHR_FILE__ENTRYPOINT, "entrypoint") S_(SECCLASS_CHR_FILE, CHR_FILE__EXECMOD, "execmod") + S_(SECCLASS_CHR_FILE, CHR_FILE__OPEN, "open") + S_(SECCLASS_BLK_FILE, BLK_FILE__OPEN, "open") + S_(SECCLASS_FIFO_FILE, FIFO_FILE__OPEN, "open") S_(SECCLASS_FD, FD__USE, "use") S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__CONNECTTO, "connectto") S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 75b41311ab8..c4c51165c50 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -79,6 +79,7 @@ #define DIR__REPARENT 0x00080000UL #define DIR__SEARCH 0x00100000UL #define DIR__RMDIR 0x00200000UL +#define DIR__OPEN 0x00400000UL #define FILE__IOCTL 0x00000001UL #define FILE__READ 0x00000002UL #define FILE__WRITE 0x00000004UL @@ -99,6 +100,7 @@ #define FILE__EXECUTE_NO_TRANS 0x00020000UL #define FILE__ENTRYPOINT 0x00040000UL #define FILE__EXECMOD 0x00080000UL +#define FILE__OPEN 0x00100000UL #define LNK_FILE__IOCTL 0x00000001UL #define LNK_FILE__READ 0x00000002UL #define LNK_FILE__WRITE 0x00000004UL @@ -136,6 +138,7 @@ #define CHR_FILE__EXECUTE_NO_TRANS 0x00020000UL #define CHR_FILE__ENTRYPOINT 0x00040000UL #define CHR_FILE__EXECMOD 0x00080000UL +#define CHR_FILE__OPEN 0x00100000UL #define BLK_FILE__IOCTL 0x00000001UL #define BLK_FILE__READ 0x00000002UL #define BLK_FILE__WRITE 0x00000004UL @@ -153,6 +156,7 @@ #define BLK_FILE__SWAPON 0x00004000UL #define BLK_FILE__QUOTAON 0x00008000UL #define BLK_FILE__MOUNTON 0x00010000UL +#define BLK_FILE__OPEN 0x00020000UL #define SOCK_FILE__IOCTL 0x00000001UL #define SOCK_FILE__READ 0x00000002UL #define SOCK_FILE__WRITE 0x00000004UL @@ -187,6 +191,7 @@ #define FIFO_FILE__SWAPON 0x00004000UL #define FIFO_FILE__QUOTAON 0x00008000UL #define FIFO_FILE__MOUNTON 0x00010000UL +#define FIFO_FILE__OPEN 0x00020000UL #define FD__USE 0x00000001UL #define SOCKET__IOCTL 0x00000001UL #define SOCKET__READ 0x00000002UL diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 00a2809c850..9a9e7cd9a37 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -41,10 +41,6 @@ void selinux_netlbl_cache_invalidate(void); void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, int family); -void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, - int family); -void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, - struct sk_security_struct *newssec); int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family, @@ -73,18 +69,6 @@ static inline void selinux_netlbl_sk_security_reset( { return; } -static inline void selinux_netlbl_sk_security_init( - struct sk_security_struct *ssec, - int family) -{ - return; -} -static inline void selinux_netlbl_sk_security_clone( - struct sk_security_struct *ssec, - struct sk_security_struct *newssec) -{ - return; -} static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family, diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h new file mode 100644 index 00000000000..8991752eaf9 --- /dev/null +++ b/security/selinux/include/netport.h @@ -0,0 +1,31 @@ +/* + * Network port table + * + * SELinux must keep a mapping of network ports to labels/SIDs. This + * mapping is maintained as part of the normal policy but a fast cache is + * needed to reduce the lookup overhead. + * + * Author: Paul Moore <paul.moore@hp.com> + * + */ + +/* + * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _SELINUX_NETPORT_H +#define _SELINUX_NETPORT_H + +int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid); + +#endif diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index c6c2bb4ebac..300b61bad7b 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -28,14 +28,12 @@ #include "avc.h" struct task_security_struct { - struct task_struct *task; /* back pointer to task object */ u32 osid; /* SID prior to last execve */ u32 sid; /* current SID */ u32 exec_sid; /* exec SID */ u32 create_sid; /* fscreate SID */ u32 keycreate_sid; /* keycreate SID */ u32 sockcreate_sid; /* fscreate SID */ - u32 ptrace_sid; /* SID of ptrace parent */ }; struct inode_security_struct { @@ -50,7 +48,6 @@ struct inode_security_struct { }; struct file_security_struct { - struct file *file; /* back pointer to file object */ u32 sid; /* SID of open file description */ u32 fown_sid; /* SID of file owner (for SIGIO) */ u32 isid; /* SID of inode at the time of file open */ @@ -73,18 +70,15 @@ struct superblock_security_struct { }; struct msg_security_struct { - struct msg_msg *msg; /* back pointer */ u32 sid; /* SID of message */ }; struct ipc_security_struct { - struct kern_ipc_perm *ipc_perm; /* back pointer */ u16 sclass; /* security class of this object */ u32 sid; /* SID of IPC resource */ }; struct bprm_security_struct { - struct linux_binprm *bprm; /* back pointer to bprm object */ u32 sid; /* SID for transformed process */ unsigned char set; @@ -109,8 +103,13 @@ struct netnode_security_struct { u16 family; /* address family */ }; +struct netport_security_struct { + u32 sid; /* SID for this node */ + u16 port; /* port number */ + u8 protocol; /* transport protocol */ +}; + struct sk_security_struct { - struct sock *sk; /* back pointer to sk object */ u32 sid; /* SID of this object */ u32 peer_sid; /* SID of peer */ u16 sclass; /* sock security class */ @@ -120,12 +119,10 @@ struct sk_security_struct { NLBL_REQUIRE, NLBL_LABELED, } nlbl_state; - spinlock_t nlbl_lock; /* protects nlbl_state */ #endif }; struct key_security_struct { - struct key *obj; /* back pointer */ u32 sid; /* SID of key */ }; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index f7d2f03781f..1904c462a60 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -26,13 +26,14 @@ #define POLICYDB_VERSION_AVTAB 20 #define POLICYDB_VERSION_RANGETRANS 21 #define POLICYDB_VERSION_POLCAP 22 +#define POLICYDB_VERSION_PERMISSIVE 23 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #else -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_POLCAP +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_PERMISSIVE #endif #define CONTEXT_MNT 0x01 @@ -40,6 +41,11 @@ #define ROOTCONTEXT_MNT 0x04 #define DEFCONTEXT_MNT 0x08 +#define CONTEXT_STR "context=" +#define FSCONTEXT_STR "fscontext=" +#define ROOTCONTEXT_STR "rootcontext=" +#define DEFCONTEXT_STR "defcontext=" + struct netlbl_lsm_secattr; extern int selinux_enabled; @@ -48,11 +54,13 @@ extern int selinux_mls_enabled; /* Policy capabilities */ enum { POLICYDB_CAPABILITY_NETPEER, + POLICYDB_CAPABILITY_OPENPERM, __POLICYDB_CAPABILITY_MAX }; #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) extern int selinux_policycap_netpeer; +extern int selinux_policycap_openperm; int security_load_policy(void * data, size_t len); @@ -67,6 +75,8 @@ struct av_decision { u32 seqno; }; +int security_permissive_sid(u32 sid); + int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd); @@ -86,13 +96,13 @@ int security_sid_to_context(u32 sid, char **scontext, int security_context_to_sid(char *scontext, u32 scontext_len, u32 *out_sid); -int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *out_sid, u32 def_sid); +int security_context_to_sid_default(char *scontext, u32 scontext_len, + u32 *out_sid, u32 def_sid, gfp_t gfp_flags); int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel); -int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port, - u32 *out_sid); +int security_port_sid(u8 protocol, u16 port, u32 *out_sid); int security_netif_sid(char *name, u32 *if_sid); diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 36b0510efa7..289e24b39e3 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -7,16 +7,17 @@ #ifndef _SELINUX_XFRM_H_ #define _SELINUX_XFRM_H_ -int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx); -int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); -void selinux_xfrm_policy_free(struct xfrm_policy *xp); -int selinux_xfrm_policy_delete(struct xfrm_policy *xp); +int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *sec_ctx); +int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp); +void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); +int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void selinux_xfrm_state_free(struct xfrm_state *x); int selinux_xfrm_state_delete(struct xfrm_state *x); -int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); +int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 013d3117a86..b4e14bc0bf3 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -8,7 +8,7 @@ * * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. - * Paul Moore <paul.moore@hp.com> + * Paul Moore <paul.moore@hp.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -31,8 +31,7 @@ #define SEL_NETIF_HASH_SIZE 64 #define SEL_NETIF_HASH_MAX 1024 -struct sel_netif -{ +struct sel_netif { struct list_head list; struct netif_security_struct nsec; struct rcu_head rcu_head; @@ -92,10 +91,10 @@ static inline struct sel_netif *sel_netif_find(int ifindex) static int sel_netif_insert(struct sel_netif *netif) { int idx; - + if (sel_netif_total >= SEL_NETIF_HASH_MAX) return -ENOSPC; - + idx = sel_netif_hashfn(netif->nsec.ifindex); list_add_rcu(&netif->list, &sel_netif_hash[idx]); sel_netif_total++; @@ -240,11 +239,13 @@ static void sel_netif_kill(int ifindex) { struct sel_netif *netif; + rcu_read_lock(); spin_lock_bh(&sel_netif_lock); netif = sel_netif_find(ifindex); if (netif) sel_netif_destroy(netif); spin_unlock_bh(&sel_netif_lock); + rcu_read_unlock(); } /** @@ -267,7 +268,7 @@ static void sel_netif_flush(void) } static int sel_netif_avc_callback(u32 event, u32 ssid, u32 tsid, - u16 class, u32 perms, u32 *retained) + u16 class, u32 perms, u32 *retained) { if (event == AVC_CALLBACK_RESET) { sel_netif_flush(); @@ -277,11 +278,11 @@ static int sel_netif_avc_callback(u32 event, u32 ssid, u32 tsid, } static int sel_netif_netdev_notifier_handler(struct notifier_block *this, - unsigned long event, void *ptr) + unsigned long event, void *ptr) { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) @@ -297,7 +298,7 @@ static struct notifier_block sel_netif_netdev_notifier = { static __init int sel_netif_init(void) { int i, err; - + if (!selinux_enabled) return 0; @@ -305,9 +306,9 @@ static __init int sel_netif_init(void) INIT_LIST_HEAD(&sel_netif_hash[i]); register_netdevice_notifier(&sel_netif_netdev_notifier); - + err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET, - SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); + SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); if (err) panic("avc_add_callback() failed, error %d\n", err); diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 0fa2be4149e..89b418392f1 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -34,6 +34,7 @@ #include "objsec.h" #include "security.h" +#include "netlabel.h" /** * selinux_netlbl_sidlookup_cached - Cache a SID lookup @@ -69,9 +70,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, * * Description: * Attempt to label a socket using the NetLabel mechanism using the given - * SID. Returns zero values on success, negative values on failure. The - * caller is responsibile for calling rcu_read_lock() before calling this - * this function and rcu_read_unlock() after this function returns. + * SID. Returns zero values on success, negative values on failure. * */ static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) @@ -86,11 +85,8 @@ static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) if (rc != 0) goto sock_setsid_return; rc = netlbl_sock_setattr(sk, &secattr); - if (rc == 0) { - spin_lock_bh(&sksec->nlbl_lock); + if (rc == 0) sksec->nlbl_state = NLBL_LABELED; - spin_unlock_bh(&sksec->nlbl_lock); - } sock_setsid_return: netlbl_secattr_destroy(&secattr); @@ -122,52 +118,13 @@ void selinux_netlbl_cache_invalidate(void) void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, int family) { - if (family == PF_INET) + if (family == PF_INET) ssec->nlbl_state = NLBL_REQUIRE; else ssec->nlbl_state = NLBL_UNSET; } /** - * selinux_netlbl_sk_security_init - Setup the NetLabel fields - * @ssec: the sk_security_struct - * @family: the socket family - * - * Description: - * Called when a new sk_security_struct is allocated to initialize the NetLabel - * fields. - * - */ -void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, - int family) -{ - /* No locking needed, we are the only one who has access to ssec */ - selinux_netlbl_sk_security_reset(ssec, family); - spin_lock_init(&ssec->nlbl_lock); -} - -/** - * selinux_netlbl_sk_security_clone - Copy the NetLabel fields - * @ssec: the original sk_security_struct - * @newssec: the cloned sk_security_struct - * - * Description: - * Clone the NetLabel specific sk_security_struct fields from @ssec to - * @newssec. - * - */ -void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, - struct sk_security_struct *newssec) -{ - /* We don't need to take newssec->nlbl_lock because we are the only - * thread with access to newssec, but we do need to take the RCU read - * lock as other threads could have access to ssec */ - rcu_read_lock(); - selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family); - rcu_read_unlock(); -} - -/** * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel * @skb: the packet * @family: protocol family @@ -221,12 +178,8 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) struct netlbl_lsm_secattr secattr; u32 nlbl_peer_sid; - rcu_read_lock(); - - if (sksec->nlbl_state != NLBL_REQUIRE) { - rcu_read_unlock(); + if (sksec->nlbl_state != NLBL_REQUIRE) return; - } netlbl_secattr_init(&secattr); if (netlbl_sock_getattr(sk, &secattr) == 0 && @@ -239,8 +192,6 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) * here we will pick up the pieces in later calls to * selinux_netlbl_inode_permission(). */ selinux_netlbl_sock_setsid(sk, sksec->sid); - - rcu_read_unlock(); } /** @@ -254,16 +205,13 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) */ int selinux_netlbl_socket_post_create(struct socket *sock) { - int rc = 0; struct sock *sk = sock->sk; struct sk_security_struct *sksec = sk->sk_security; - rcu_read_lock(); - if (sksec->nlbl_state == NLBL_REQUIRE) - rc = selinux_netlbl_sock_setsid(sk, sksec->sid); - rcu_read_unlock(); + if (sksec->nlbl_state != NLBL_REQUIRE) + return 0; - return rc; + return selinux_netlbl_sock_setsid(sk, sksec->sid); } /** @@ -288,21 +236,21 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask) if (!S_ISSOCK(inode->i_mode) || ((mask & (MAY_WRITE | MAY_APPEND)) == 0)) return 0; + sock = SOCKET_I(inode); sk = sock->sk; sksec = sk->sk_security; - - rcu_read_lock(); - if (sksec->nlbl_state != NLBL_REQUIRE) { - rcu_read_unlock(); + if (sksec->nlbl_state != NLBL_REQUIRE) return 0; - } + local_bh_disable(); bh_lock_sock_nested(sk); - rc = selinux_netlbl_sock_setsid(sk, sksec->sid); + if (likely(sksec->nlbl_state == NLBL_REQUIRE)) + rc = selinux_netlbl_sock_setsid(sk, sksec->sid); + else + rc = 0; bh_unlock_sock(sk); local_bh_enable(); - rcu_read_unlock(); return rc; } @@ -385,7 +333,6 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, struct sk_security_struct *sksec = sk->sk_security; struct netlbl_lsm_secattr secattr; - rcu_read_lock(); if (level == IPPROTO_IP && optname == IP_OPTIONS && sksec->nlbl_state == NLBL_LABELED) { netlbl_secattr_init(&secattr); @@ -396,7 +343,6 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, rc = -EACCES; netlbl_secattr_destroy(&secattr); } - rcu_read_unlock(); return rc; } diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index b59871d74da..1ae556446e6 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c @@ -24,16 +24,16 @@ static struct sock *selnl; static int selnl_msglen(int msgtype) { int ret = 0; - + switch (msgtype) { case SELNL_MSG_SETENFORCE: ret = sizeof(struct selnl_msg_setenforce); break; - + case SELNL_MSG_POLICYLOAD: ret = sizeof(struct selnl_msg_policyload); break; - + default: BUG(); } @@ -45,15 +45,15 @@ static void selnl_add_payload(struct nlmsghdr *nlh, int len, int msgtype, void * switch (msgtype) { case SELNL_MSG_SETENFORCE: { struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh); - + memset(msg, 0, len); msg->val = *((int *)data); break; } - + case SELNL_MSG_POLICYLOAD: { struct selnl_msg_policyload *msg = NLMSG_DATA(nlh); - + memset(msg, 0, len); msg->seqno = *((u32 *)data); break; @@ -70,9 +70,9 @@ static void selnl_notify(int msgtype, void *data) sk_buff_data_t tmp; struct sk_buff *skb; struct nlmsghdr *nlh; - + len = selnl_msglen(msgtype); - + skb = alloc_skb(NLMSG_SPACE(len), GFP_USER); if (!skb) goto oom; @@ -85,11 +85,11 @@ static void selnl_notify(int msgtype, void *data) netlink_broadcast(selnl, skb, 0, SELNLGRP_AVC, GFP_USER); out: return; - + nlmsg_failure: kfree_skb(skb); oom: - printk(KERN_ERR "SELinux: OOM in %s\n", __FUNCTION__); + printk(KERN_ERR "SELinux: OOM in %s\n", __func__); goto out; } @@ -109,7 +109,7 @@ static int __init selnl_init(void) SELNLGRP_MAX, NULL, NULL, THIS_MODULE); if (selnl == NULL) panic("SELinux: Cannot create netlink socket."); - netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV); + netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV); return 0; } diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index f3c526f2cac..2edc4c5e0c6 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c @@ -344,7 +344,7 @@ static __init int sel_netnode_init(void) INIT_LIST_HEAD(&sel_netnode_hash[iter]); ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET, - SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); + SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); if (ret != 0) panic("avc_add_callback() failed, error %d\n", ret); diff --git a/security/selinux/netport.c b/security/selinux/netport.c new file mode 100644 index 00000000000..68ede3c498a --- /dev/null +++ b/security/selinux/netport.c @@ -0,0 +1,286 @@ +/* + * Network port table + * + * SELinux must keep a mapping of network ports to labels/SIDs. This + * mapping is maintained as part of the normal policy but a fast cache is + * needed to reduce the lookup overhead. + * + * Author: Paul Moore <paul.moore@hp.com> + * + * This code is heavily based on the "netif" concept originally developed by + * James Morris <jmorris@redhat.com> + * (see security/selinux/netif.c for more information) + * + */ + +/* + * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/types.h> +#include <linux/rcupdate.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/in.h> +#include <linux/in6.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <asm/bug.h> + +#include "netport.h" +#include "objsec.h" + +#define SEL_NETPORT_HASH_SIZE 256 +#define SEL_NETPORT_HASH_BKT_LIMIT 16 + +struct sel_netport_bkt { + int size; + struct list_head list; +}; + +struct sel_netport { + struct netport_security_struct psec; + + struct list_head list; + struct rcu_head rcu; +}; + +/* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason + * for this is that I suspect most users will not make heavy use of both + * address families at the same time so one table will usually end up wasted, + * if this becomes a problem we can always add a hash table for each address + * family later */ + +static LIST_HEAD(sel_netport_list); +static DEFINE_SPINLOCK(sel_netport_lock); +static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE]; + +/** + * sel_netport_free - Frees a port entry + * @p: the entry's RCU field + * + * Description: + * This function is designed to be used as a callback to the call_rcu() + * function so that memory allocated to a hash table port entry can be + * released safely. + * + */ +static void sel_netport_free(struct rcu_head *p) +{ + struct sel_netport *port = container_of(p, struct sel_netport, rcu); + kfree(port); +} + +/** + * sel_netport_hashfn - Hashing function for the port table + * @pnum: port number + * + * Description: + * This is the hashing function for the port table, it returns the bucket + * number for the given port. + * + */ +static unsigned int sel_netport_hashfn(u16 pnum) +{ + return (pnum & (SEL_NETPORT_HASH_SIZE - 1)); +} + +/** + * sel_netport_find - Search for a port record + * @protocol: protocol + * @port: pnum + * + * Description: + * Search the network port table and return the matching record. If an entry + * can not be found in the table return NULL. + * + */ +static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum) +{ + unsigned int idx; + struct sel_netport *port; + + idx = sel_netport_hashfn(pnum); + list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list) + if (port->psec.port == pnum && + port->psec.protocol == protocol) + return port; + + return NULL; +} + +/** + * sel_netport_insert - Insert a new port into the table + * @port: the new port record + * + * Description: + * Add a new port record to the network address hash table. Returns zero on + * success, negative values on failure. + * + */ +static int sel_netport_insert(struct sel_netport *port) +{ + unsigned int idx; + + /* we need to impose a limit on the growth of the hash table so check + * this bucket to make sure it is within the specified bounds */ + idx = sel_netport_hashfn(port->psec.port); + list_add_rcu(&port->list, &sel_netport_hash[idx].list); + if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { + struct sel_netport *tail; + tail = list_entry(port->list.prev, struct sel_netport, list); + list_del_rcu(port->list.prev); + call_rcu(&tail->rcu, sel_netport_free); + } else + sel_netport_hash[idx].size++; + + return 0; +} + +/** + * sel_netport_sid_slow - Lookup the SID of a network address using the policy + * @protocol: protocol + * @pnum: port + * @sid: port SID + * + * Description: + * This function determines the SID of a network port by quering the security + * policy. The result is added to the network port table to speedup future + * queries. Returns zero on success, negative values on failure. + * + */ +static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) +{ + int ret; + struct sel_netport *port; + struct sel_netport *new = NULL; + + spin_lock_bh(&sel_netport_lock); + port = sel_netport_find(protocol, pnum); + if (port != NULL) { + *sid = port->psec.sid; + ret = 0; + goto out; + } + new = kzalloc(sizeof(*new), GFP_ATOMIC); + if (new == NULL) { + ret = -ENOMEM; + goto out; + } + ret = security_port_sid(protocol, pnum, &new->psec.sid); + if (ret != 0) + goto out; + new->psec.port = pnum; + new->psec.protocol = protocol; + ret = sel_netport_insert(new); + if (ret != 0) + goto out; + *sid = new->psec.sid; + +out: + spin_unlock_bh(&sel_netport_lock); + if (unlikely(ret)) { + printk(KERN_WARNING + "SELinux: failure in sel_netport_sid_slow()," + " unable to determine network port label\n"); + kfree(new); + } + return ret; +} + +/** + * sel_netport_sid - Lookup the SID of a network port + * @protocol: protocol + * @pnum: port + * @sid: port SID + * + * Description: + * This function determines the SID of a network port using the fastest method + * possible. First the port table is queried, but if an entry can't be found + * then the policy is queried and the result is added to the table to speedup + * future queries. Returns zero on success, negative values on failure. + * + */ +int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid) +{ + struct sel_netport *port; + + rcu_read_lock(); + port = sel_netport_find(protocol, pnum); + if (port != NULL) { + *sid = port->psec.sid; + rcu_read_unlock(); + return 0; + } + rcu_read_unlock(); + + return sel_netport_sid_slow(protocol, pnum, sid); +} + +/** + * sel_netport_flush - Flush the entire network port table + * + * Description: + * Remove all entries from the network address table. + * + */ +static void sel_netport_flush(void) +{ + unsigned int idx; + struct sel_netport *port; + + spin_lock_bh(&sel_netport_lock); + for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) { + list_for_each_entry(port, &sel_netport_hash[idx].list, list) { + list_del_rcu(&port->list); + call_rcu(&port->rcu, sel_netport_free); + } + sel_netport_hash[idx].size = 0; + } + spin_unlock_bh(&sel_netport_lock); +} + +static int sel_netport_avc_callback(u32 event, u32 ssid, u32 tsid, + u16 class, u32 perms, u32 *retained) +{ + if (event == AVC_CALLBACK_RESET) { + sel_netport_flush(); + synchronize_net(); + } + return 0; +} + +static __init int sel_netport_init(void) +{ + int iter; + int ret; + + if (!selinux_enabled) + return 0; + + for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) { + INIT_LIST_HEAD(&sel_netport_hash[iter].list); + sel_netport_hash[iter].size = 0; + } + + ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET, + SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); + if (ret != 0) + panic("avc_add_callback() failed, error %d\n", ret); + + return ret; +} + +__initcall(sel_netport_init); diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index eddc7b42010..ff59c0c4804 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -23,8 +23,7 @@ #include "flask.h" #include "av_permissions.h" -struct nlmsg_perm -{ +struct nlmsg_perm { u16 nlmsg_type; u32 perm; }; @@ -159,7 +158,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) if ((nlmsg_type >= AUDIT_FIRST_USER_MSG && nlmsg_type <= AUDIT_LAST_USER_MSG) || (nlmsg_type >= AUDIT_FIRST_USER_MSG2 && - nlmsg_type <= AUDIT_LAST_USER_MSG2)) { + nlmsg_type <= AUDIT_LAST_USER_MSG2)) { *perm = NETLINK_AUDIT_SOCKET__NLMSG_RELAY; } else { err = nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms, diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 0341567665b..ac1ccc13a70 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1,16 +1,16 @@ /* Updated: Karl MacMillan <kmacmillan@tresys.com> * - * Added conditional policy language extensions + * Added conditional policy language extensions * * Updated: Hewlett-Packard <paul.moore@hp.com> * - * Added support for the policy capability bitmap + * Added support for the policy capability bitmap * * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. * Copyright (C) 2003 - 2004 Tresys Technology, LLC * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. */ @@ -28,7 +28,6 @@ #include <linux/percpu.h> #include <linux/audit.h> #include <asm/uaccess.h> -#include <asm/semaphore.h> /* selinuxfs pseudo filesystem for exporting the security policy API. Based on the proc code and the fs/nfsd/nfsctl.c code. */ @@ -42,7 +41,8 @@ /* Policy capability filenames */ static char *policycap_names[] = { - "network_peer_controls" + "network_peer_controls", + "open_perms" }; unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; @@ -57,14 +57,14 @@ int selinux_compat_net = SELINUX_COMPAT_NET_VALUE; static int __init checkreqprot_setup(char *str) { - selinux_checkreqprot = simple_strtoul(str,NULL,0) ? 1 : 0; + selinux_checkreqprot = simple_strtoul(str, NULL, 0) ? 1 : 0; return 1; } __setup("checkreqprot=", checkreqprot_setup); static int __init selinux_compat_net_setup(char *str) { - selinux_compat_net = simple_strtoul(str,NULL,0) ? 1 : 0; + selinux_compat_net = simple_strtoul(str, NULL, 0) ? 1 : 0; return 1; } __setup("selinux_compat_net=", selinux_compat_net_setup); @@ -73,17 +73,17 @@ __setup("selinux_compat_net=", selinux_compat_net_setup); static DEFINE_MUTEX(sel_mutex); /* global data for booleans */ -static struct dentry *bool_dir = NULL; -static int bool_num = 0; +static struct dentry *bool_dir; +static int bool_num; static char **bool_pending_names; -static int *bool_pending_values = NULL; +static int *bool_pending_values; /* global data for classes */ -static struct dentry *class_dir = NULL; +static struct dentry *class_dir; static unsigned long last_class_ino; /* global data for policy capabilities */ -static struct dentry *policycap_dir = NULL; +static struct dentry *policycap_dir; extern void selnl_notify_setenforce(int val); @@ -142,7 +142,7 @@ static ssize_t sel_read_enforce(struct file *filp, char __user *buf, } #ifdef CONFIG_SECURITY_SELINUX_DEVELOP -static ssize_t sel_write_enforce(struct file * file, const char __user * buf, +static ssize_t sel_write_enforce(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -156,7 +156,7 @@ static ssize_t sel_write_enforce(struct file * file, const char __user * buf, /* No partial writes. */ return -EINVAL; } - page = (char*)get_zeroed_page(GFP_KERNEL); + page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; length = -EFAULT; @@ -213,7 +213,7 @@ static const struct file_operations sel_handle_unknown_ops = { }; #ifdef CONFIG_SECURITY_SELINUX_DISABLE -static ssize_t sel_write_disable(struct file * file, const char __user * buf, +static ssize_t sel_write_disable(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -228,7 +228,7 @@ static ssize_t sel_write_disable(struct file * file, const char __user * buf, /* No partial writes. */ return -EINVAL; } - page = (char*)get_zeroed_page(GFP_KERNEL); + page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; length = -EFAULT; @@ -263,7 +263,7 @@ static const struct file_operations sel_disable_ops = { }; static ssize_t sel_read_policyvers(struct file *filp, char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { char tmpbuf[TMPBUFLEN]; ssize_t length; @@ -299,7 +299,7 @@ static const struct file_operations sel_mls_ops = { .read = sel_read_mls, }; -static ssize_t sel_write_load(struct file * file, const char __user * buf, +static ssize_t sel_write_load(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -371,7 +371,7 @@ static const struct file_operations sel_load_ops = { .write = sel_write_load, }; -static ssize_t sel_write_context(struct file * file, char *buf, size_t size) +static ssize_t sel_write_context(struct file *file, char *buf, size_t size) { char *canon; u32 sid, len; @@ -390,8 +390,8 @@ static ssize_t sel_write_context(struct file * file, char *buf, size_t size) return length; if (len > SIMPLE_TRANSACTION_LIMIT) { - printk(KERN_ERR "%s: context size (%u) exceeds payload " - "max\n", __FUNCTION__, len); + printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " + "payload max\n", __func__, len); length = -ERANGE; goto out; } @@ -413,7 +413,7 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf, return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } -static ssize_t sel_write_checkreqprot(struct file * file, const char __user * buf, +static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *page; @@ -430,7 +430,7 @@ static ssize_t sel_write_checkreqprot(struct file * file, const char __user * bu /* No partial writes. */ return -EINVAL; } - page = (char*)get_zeroed_page(GFP_KERNEL); + page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; length = -EFAULT; @@ -462,7 +462,7 @@ static ssize_t sel_read_compat_net(struct file *filp, char __user *buf, return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } -static ssize_t sel_write_compat_net(struct file * file, const char __user * buf, +static ssize_t sel_write_compat_net(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *page; @@ -479,7 +479,7 @@ static ssize_t sel_write_compat_net(struct file * file, const char __user * buf, /* No partial writes. */ return -EINVAL; } - page = (char*)get_zeroed_page(GFP_KERNEL); + page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; length = -EFAULT; @@ -504,11 +504,11 @@ static const struct file_operations sel_compat_net_ops = { /* * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c */ -static ssize_t sel_write_access(struct file * file, char *buf, size_t size); -static ssize_t sel_write_create(struct file * file, char *buf, size_t size); -static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size); -static ssize_t sel_write_user(struct file * file, char *buf, size_t size); -static ssize_t sel_write_member(struct file * file, char *buf, size_t size); +static ssize_t sel_write_access(struct file *file, char *buf, size_t size); +static ssize_t sel_write_create(struct file *file, char *buf, size_t size); +static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size); +static ssize_t sel_write_user(struct file *file, char *buf, size_t size); +static ssize_t sel_write_member(struct file *file, char *buf, size_t size); static ssize_t (*write_op[])(struct file *, char *, size_t) = { [SEL_ACCESS] = sel_write_access, @@ -521,7 +521,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) { - ino_t ino = file->f_path.dentry->d_inode->i_ino; + ino_t ino = file->f_path.dentry->d_inode->i_ino; char *data; ssize_t rv; @@ -532,8 +532,8 @@ static ssize_t selinux_transaction_write(struct file *file, const char __user *b if (IS_ERR(data)) return PTR_ERR(data); - rv = write_op[ino](file, data, size); - if (rv>0) { + rv = write_op[ino](file, data, size); + if (rv > 0) { simple_transaction_set(file, rv); rv = size; } @@ -552,7 +552,7 @@ static const struct file_operations transaction_ops = { * and the length returned. Otherwise return 0 or and -error. */ -static ssize_t sel_write_access(struct file * file, char *buf, size_t size) +static ssize_t sel_write_access(struct file *file, char *buf, size_t size) { char *scon, *tcon; u32 ssid, tsid; @@ -601,7 +601,7 @@ out: return length; } -static ssize_t sel_write_create(struct file * file, char *buf, size_t size) +static ssize_t sel_write_create(struct file *file, char *buf, size_t size) { char *scon, *tcon; u32 ssid, tsid, newsid; @@ -643,8 +643,8 @@ static ssize_t sel_write_create(struct file * file, char *buf, size_t size) goto out2; if (len > SIMPLE_TRANSACTION_LIMIT) { - printk(KERN_ERR "%s: context size (%u) exceeds payload " - "max\n", __FUNCTION__, len); + printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " + "payload max\n", __func__, len); length = -ERANGE; goto out3; } @@ -660,7 +660,7 @@ out: return length; } -static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size) +static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) { char *scon, *tcon; u32 ssid, tsid, newsid; @@ -717,7 +717,7 @@ out: return length; } -static ssize_t sel_write_user(struct file * file, char *buf, size_t size) +static ssize_t sel_write_user(struct file *file, char *buf, size_t size) { char *con, *user, *ptr; u32 sid, *sids; @@ -778,7 +778,7 @@ out: return length; } -static ssize_t sel_write_member(struct file * file, char *buf, size_t size) +static ssize_t sel_write_member(struct file *file, char *buf, size_t size) { char *scon, *tcon; u32 ssid, tsid, newsid; @@ -820,8 +820,8 @@ static ssize_t sel_write_member(struct file * file, char *buf, size_t size) goto out2; if (len > SIMPLE_TRANSACTION_LIMIT) { - printk(KERN_ERR "%s: context size (%u) exceeds payload " - "max\n", __FUNCTION__, len); + printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " + "payload max\n", __func__, len); length = -ERANGE; goto out3; } @@ -872,7 +872,8 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, ret = -EINVAL; goto out; } - if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) { + page = (char *)get_zeroed_page(GFP_KERNEL); + if (!page) { ret = -ENOMEM; goto out; } @@ -923,7 +924,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, length = -EINVAL; goto out; } - page = (char*)get_zeroed_page(GFP_KERNEL); + page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) { length = -ENOMEM; goto out; @@ -951,8 +952,8 @@ out: } static const struct file_operations sel_bool_ops = { - .read = sel_read_bool, - .write = sel_write_bool, + .read = sel_read_bool, + .write = sel_write_bool, }; static ssize_t sel_commit_bools_write(struct file *filep, @@ -977,7 +978,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, /* No partial writes. */ goto out; } - page = (char*)get_zeroed_page(GFP_KERNEL); + page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) { length = -ENOMEM; goto out; @@ -991,9 +992,8 @@ static ssize_t sel_commit_bools_write(struct file *filep, if (sscanf(page, "%d", &new_value) != 1) goto out; - if (new_value && bool_pending_values) { + if (new_value && bool_pending_values) security_set_bools(bool_num, bool_pending_values); - } length = count; @@ -1005,7 +1005,7 @@ out: } static const struct file_operations sel_commit_bools_ops = { - .write = sel_commit_bools_write, + .write = sel_commit_bools_write, }; static void sel_remove_entries(struct dentry *de) @@ -1055,7 +1055,8 @@ static int sel_make_bools(void) sel_remove_entries(dir); - if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) + page = (char *)get_zeroed_page(GFP_KERNEL); + if (!page) return -ENOMEM; ret = security_get_bools(&num, &names, &values); @@ -1082,8 +1083,9 @@ static int sel_make_bools(void) ret = -ENAMETOOLONG; goto err; } - isec = (struct inode_security_struct*)inode->i_security; - if ((ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid))) + isec = (struct inode_security_struct *)inode->i_security; + ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); + if (ret) goto err; isec->sid = sid; isec->initialized = 1; @@ -1111,7 +1113,7 @@ err: #define NULL_FILE_NAME "null" -struct dentry *selinux_null = NULL; +struct dentry *selinux_null; static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf, size_t count, loff_t *ppos) @@ -1123,8 +1125,8 @@ static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf, return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } -static ssize_t sel_write_avc_cache_threshold(struct file * file, - const char __user * buf, +static ssize_t sel_write_avc_cache_threshold(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) { @@ -1143,7 +1145,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file * file, goto out; } - page = (char*)get_zeroed_page(GFP_KERNEL); + page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) { ret = -ENOMEM; goto out; @@ -1301,7 +1303,7 @@ out: return ret; } -static ssize_t sel_read_initcon(struct file * file, char __user *buf, +static ssize_t sel_read_initcon(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct inode *inode; @@ -1375,7 +1377,7 @@ static inline u32 sel_ino_to_perm(unsigned long ino) return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1); } -static ssize_t sel_read_class(struct file * file, char __user *buf, +static ssize_t sel_read_class(struct file *file, char __user *buf, size_t count, loff_t *ppos) { ssize_t rc, len; @@ -1399,7 +1401,7 @@ static const struct file_operations sel_class_ops = { .read = sel_read_class, }; -static ssize_t sel_read_perm(struct file * file, char __user *buf, +static ssize_t sel_read_perm(struct file *file, char __user *buf, size_t count, loff_t *ppos) { ssize_t rc, len; @@ -1412,7 +1414,7 @@ static ssize_t sel_read_perm(struct file * file, char __user *buf, goto out; } - len = snprintf(page, PAGE_SIZE,"%d", sel_ino_to_perm(ino)); + len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_perm(ino)); rc = simple_read_from_buffer(buf, count, ppos, page, len); free_page((unsigned long)page); out: @@ -1640,7 +1642,7 @@ out: return ret; } -static int sel_fill_super(struct super_block * sb, void * data, int silent) +static int sel_fill_super(struct super_block *sb, void *data, int silent) { int ret; struct dentry *dentry; @@ -1696,7 +1698,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) goto err; } inode->i_ino = ++sel_last_ino; - isec = (struct inode_security_struct*)inode->i_security; + isec = (struct inode_security_struct *)inode->i_security; isec->sid = SECINITSID_DEVNULL; isec->sclass = SECCLASS_CHR_FILE; isec->initialized = 1; @@ -1760,7 +1762,8 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) out: return ret; err: - printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); + printk(KERN_ERR "SELinux: %s: failed while creating inodes\n", + __func__); goto out; } diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index cd10e27fc9e..9e6626362bf 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -6,15 +6,15 @@ /* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> * - * Added conditional policy language extensions + * Added conditional policy language extensions * * Copyright (C) 2003 Tresys Technology, LLC * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. * * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> - * Tuned number of hash slots for avtab to reduce memory usage + * Tuned number of hash slots for avtab to reduce memory usage */ #include <linux/kernel.h> @@ -33,10 +33,10 @@ static inline int avtab_hash(struct avtab_key *keyp, u16 mask) static struct avtab_node* avtab_insert_node(struct avtab *h, int hvalue, - struct avtab_node * prev, struct avtab_node * cur, + struct avtab_node *prev, struct avtab_node *cur, struct avtab_key *key, struct avtab_datum *datum) { - struct avtab_node * newnode; + struct avtab_node *newnode; newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); if (newnode == NULL) return NULL; @@ -84,7 +84,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat } newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum); - if(!newnode) + if (!newnode) return -ENOMEM; return 0; @@ -95,7 +95,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat * It also returns a pointer to the node inserted. */ struct avtab_node * -avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_datum * datum) +avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum) { int hvalue; struct avtab_node *prev, *cur, *newnode; @@ -280,8 +280,8 @@ int avtab_alloc(struct avtab *h, u32 nrules) h->nel = 0; h->nslot = nslot; h->mask = mask; - printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. " - "Num of rules:%d\n", h->nslot, nrules); + printk(KERN_DEBUG "SELinux: %d avtab hash slots, %d rules.\n", + h->nslot, nrules); return 0; } @@ -310,8 +310,8 @@ void avtab_hash_eval(struct avtab *h, char *tag) } } - printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, longest " - "chain length %d sum of chain length^2 %Lu\n", + printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " + "longest chain length %d sum of chain length^2 %Lu\n", tag, h->nel, slots_used, h->nslot, max_chain_len, chain2_len_sum); } @@ -326,7 +326,7 @@ static uint16_t spec_order[] = { }; int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, - int (*insertf)(struct avtab *a, struct avtab_key *k, + int (*insertf)(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *p), void *p) { @@ -345,18 +345,18 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, if (vers < POLICYDB_VERSION_AVTAB) { rc = next_entry(buf32, fp, sizeof(u32)); if (rc < 0) { - printk(KERN_ERR "security: avtab: truncated entry\n"); + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return -1; } items2 = le32_to_cpu(buf32[0]); if (items2 > ARRAY_SIZE(buf32)) { - printk(KERN_ERR "security: avtab: entry overflow\n"); + printk(KERN_ERR "SELinux: avtab: entry overflow\n"); return -1; } rc = next_entry(buf32, fp, sizeof(u32)*items2); if (rc < 0) { - printk(KERN_ERR "security: avtab: truncated entry\n"); + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return -1; } items = 0; @@ -364,19 +364,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, val = le32_to_cpu(buf32[items++]); key.source_type = (u16)val; if (key.source_type != val) { - printk("security: avtab: truncated source type\n"); + printk(KERN_ERR "SELinux: avtab: truncated source type\n"); return -1; } val = le32_to_cpu(buf32[items++]); key.target_type = (u16)val; if (key.target_type != val) { - printk("security: avtab: truncated target type\n"); + printk(KERN_ERR "SELinux: avtab: truncated target type\n"); return -1; } val = le32_to_cpu(buf32[items++]); key.target_class = (u16)val; if (key.target_class != val) { - printk("security: avtab: truncated target class\n"); + printk(KERN_ERR "SELinux: avtab: truncated target class\n"); return -1; } @@ -384,12 +384,12 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0; if (!(val & (AVTAB_AV | AVTAB_TYPE))) { - printk("security: avtab: null entry\n"); + printk(KERN_ERR "SELinux: avtab: null entry\n"); return -1; } if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) { - printk("security: avtab: entry has both access vectors and types\n"); + printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); return -1; } @@ -398,12 +398,13 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, key.specified = spec_order[i] | enabled; datum.data = le32_to_cpu(buf32[items++]); rc = insertf(a, &key, &datum, p); - if (rc) return rc; + if (rc) + return rc; } } if (items != items2) { - printk("security: avtab: entry only had %d items, expected %d\n", items2, items); + printk(KERN_ERR "SELinux: avtab: entry only had %d items, expected %d\n", items2, items); return -1; } return 0; @@ -411,7 +412,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, rc = next_entry(buf16, fp, sizeof(u16)*4); if (rc < 0) { - printk("security: avtab: truncated entry\n"); + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return -1; } @@ -424,7 +425,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, if (!policydb_type_isvalid(pol, key.source_type) || !policydb_type_isvalid(pol, key.target_type) || !policydb_class_isvalid(pol, key.target_class)) { - printk(KERN_WARNING "security: avtab: invalid type or class\n"); + printk(KERN_ERR "SELinux: avtab: invalid type or class\n"); return -1; } @@ -434,20 +435,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, set++; } if (!set || set > 1) { - printk(KERN_WARNING - "security: avtab: more than one specifier\n"); + printk(KERN_ERR "SELinux: avtab: more than one specifier\n"); return -1; } rc = next_entry(buf32, fp, sizeof(u32)); if (rc < 0) { - printk("security: avtab: truncated entry\n"); + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return -1; } datum.data = le32_to_cpu(*buf32); if ((key.specified & AVTAB_TYPE) && !policydb_type_isvalid(pol, datum.data)) { - printk(KERN_WARNING "security: avtab: invalid type\n"); + printk(KERN_ERR "SELinux: avtab: invalid type\n"); return -1; } return insertf(a, &key, &datum, p); @@ -468,12 +468,12 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol) rc = next_entry(buf, fp, sizeof(u32)); if (rc < 0) { - printk(KERN_ERR "security: avtab: truncated table\n"); + printk(KERN_ERR "SELinux: avtab: truncated table\n"); goto bad; } nel = le32_to_cpu(buf[0]); if (!nel) { - printk(KERN_ERR "security: avtab: table is empty\n"); + printk(KERN_ERR "SELinux: avtab: table is empty\n"); rc = -EINVAL; goto bad; } @@ -486,9 +486,9 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol) rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL); if (rc) { if (rc == -ENOMEM) - printk(KERN_ERR "security: avtab: out of memory\n"); + printk(KERN_ERR "SELinux: avtab: out of memory\n"); else if (rc == -EEXIST) - printk(KERN_ERR "security: avtab: duplicate entry\n"); + printk(KERN_ERR "SELinux: avtab: duplicate entry\n"); else rc = -EINVAL; goto bad; @@ -513,5 +513,5 @@ void avtab_cache_init(void) void avtab_cache_destroy(void) { - kmem_cache_destroy (avtab_node_cachep); + kmem_cache_destroy(avtab_node_cachep); } diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 50ad85d4b77..fb4efe4f4bc 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -1,9 +1,9 @@ /* Authors: Karl MacMillan <kmacmillan@tresys.com> - * Frank Mayer <mayerf@tresys.com> + * Frank Mayer <mayerf@tresys.com> * * Copyright (C) 2003 - 2004 Tresys Technology, LLC * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. */ @@ -11,7 +11,6 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/spinlock.h> -#include <asm/semaphore.h> #include <linux/slab.h> #include "security.h" @@ -90,29 +89,27 @@ static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr) int evaluate_cond_node(struct policydb *p, struct cond_node *node) { int new_state; - struct cond_av_list* cur; + struct cond_av_list *cur; new_state = cond_evaluate_expr(p, node->expr); if (new_state != node->cur_state) { node->cur_state = new_state; if (new_state == -1) - printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n"); + printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n"); /* turn the rules on or off */ for (cur = node->true_list; cur != NULL; cur = cur->next) { - if (new_state <= 0) { + if (new_state <= 0) cur->node->key.specified &= ~AVTAB_ENABLED; - } else { + else cur->node->key.specified |= AVTAB_ENABLED; - } } for (cur = node->false_list; cur != NULL; cur = cur->next) { /* -1 or 1 */ - if (new_state) { + if (new_state) cur->node->key.specified &= ~AVTAB_ENABLED; - } else { + else cur->node->key.specified |= AVTAB_ENABLED; - } } } return 0; @@ -174,8 +171,8 @@ void cond_policydb_destroy(struct policydb *p) int cond_init_bool_indexes(struct policydb *p) { kfree(p->bool_val_to_struct); - p->bool_val_to_struct = (struct cond_bool_datum**) - kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum*), GFP_KERNEL); + p->bool_val_to_struct = (struct cond_bool_datum **) + kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL); if (!p->bool_val_to_struct) return -1; return 0; @@ -200,7 +197,7 @@ int cond_index_bool(void *key, void *datum, void *datap) return -EINVAL; p->p_bool_val_to_name[booldatum->value - 1] = key; - p->bool_val_to_struct[booldatum->value -1] = booldatum; + p->bool_val_to_struct[booldatum->value - 1] = booldatum; return 0; } @@ -252,8 +249,7 @@ err: return -1; } -struct cond_insertf_data -{ +struct cond_insertf_data { struct policydb *p; struct cond_av_list *other; struct cond_av_list *head; @@ -276,7 +272,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum */ if (k->specified & AVTAB_TYPE) { if (avtab_search(&p->te_avtab, k)) { - printk("security: type rule already exists outside of a conditional."); + printk(KERN_ERR "SELinux: type rule already exists outside of a conditional.\n"); goto err; } /* @@ -291,7 +287,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum node_ptr = avtab_search_node(&p->te_cond_avtab, k); if (node_ptr) { if (avtab_search_node_next(node_ptr, k->specified)) { - printk("security: too many conflicting type rules."); + printk(KERN_ERR "SELinux: too many conflicting type rules.\n"); goto err; } found = 0; @@ -302,13 +298,13 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum } } if (!found) { - printk("security: conflicting type rules.\n"); + printk(KERN_ERR "SELinux: conflicting type rules.\n"); goto err; } } } else { if (avtab_search(&p->te_cond_avtab, k)) { - printk("security: conflicting type rules when adding type rule for true.\n"); + printk(KERN_ERR "SELinux: conflicting type rules when adding type rule for true.\n"); goto err; } } @@ -316,7 +312,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); if (!node_ptr) { - printk("security: could not insert rule."); + printk(KERN_ERR "SELinux: could not insert rule.\n"); goto err; } @@ -353,9 +349,8 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list * return -1; len = le32_to_cpu(buf[0]); - if (len == 0) { + if (len == 0) return 0; - } data.p = p; data.other = other; @@ -376,12 +371,12 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list * static int expr_isvalid(struct policydb *p, struct cond_expr *expr) { if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { - printk("security: conditional expressions uses unknown operator.\n"); + printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n"); return 0; } if (expr->bool > p->p_bools.nprim) { - printk("security: conditional expressions uses unknown bool.\n"); + printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n"); return 0; } return 1; @@ -408,15 +403,14 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) /* expr */ len = le32_to_cpu(buf[0]); - for (i = 0; i < len; i++ ) { + for (i = 0; i < len; i++) { rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc < 0) goto err; expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL); - if (!expr) { + if (!expr) goto err; - } expr->expr_type = le32_to_cpu(buf[0]); expr->bool = le32_to_cpu(buf[1]); @@ -426,11 +420,10 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) goto err; } - if (i == 0) { + if (i == 0) node->expr = expr; - } else { + else last->next = expr; - } last = expr; } @@ -469,11 +462,10 @@ int cond_read_list(struct policydb *p, void *fp) if (cond_read_node(p, node, fp) != 0) goto err; - if (i == 0) { + if (i == 0) p->cond_list = node; - } else { + else last->next = node; - } last = node; } return 0; @@ -490,24 +482,24 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi { struct avtab_node *node; - if(!ctab || !key || !avd) + if (!ctab || !key || !avd) return; - for(node = avtab_search_node(ctab, key); node != NULL; + for (node = avtab_search_node(ctab, key); node != NULL; node = avtab_search_node_next(node, key->specified)) { - if ( (u16) (AVTAB_ALLOWED|AVTAB_ENABLED) == - (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) + if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == + (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) avd->allowed |= node->datum.data; - if ( (u16) (AVTAB_AUDITDENY|AVTAB_ENABLED) == - (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) + if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == + (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) /* Since a '0' in an auditdeny mask represents a * permission we do NOT want to audit (dontaudit), we use * the '&' operand to ensure that all '0's in the mask * are retained (much unlike the allow and auditallow cases). */ avd->auditdeny &= node->datum.data; - if ( (u16) (AVTAB_AUDITALLOW|AVTAB_ENABLED) == - (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) + if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == + (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) avd->auditallow |= node->datum.data; } return; diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 920b5e36a1a..ddc275490af 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -364,7 +364,7 @@ int ebitmap_read(struct ebitmap *e, void *fp) count = le32_to_cpu(buf[2]); if (mapunit != sizeof(u64) * 8) { - printk(KERN_ERR "security: ebitmap: map size %u does not " + printk(KERN_ERR "SELinux: ebitmap: map size %u does not " "match my size %Zd (high bit was %d)\n", mapunit, sizeof(u64) * 8, e->highbit); goto bad; @@ -382,19 +382,19 @@ int ebitmap_read(struct ebitmap *e, void *fp) for (i = 0; i < count; i++) { rc = next_entry(&startbit, fp, sizeof(u32)); if (rc < 0) { - printk(KERN_ERR "security: ebitmap: truncated map\n"); + printk(KERN_ERR "SELinux: ebitmap: truncated map\n"); goto bad; } startbit = le32_to_cpu(startbit); if (startbit & (mapunit - 1)) { - printk(KERN_ERR "security: ebitmap start bit (%d) is " + printk(KERN_ERR "SELinux: ebitmap start bit (%d) is " "not a multiple of the map unit size (%u)\n", startbit, mapunit); goto bad; } if (startbit > e->highbit - mapunit) { - printk(KERN_ERR "security: ebitmap start bit (%d) is " + printk(KERN_ERR "SELinux: ebitmap start bit (%d) is " "beyond the end of the bitmap (%u)\n", startbit, (e->highbit - mapunit)); goto bad; @@ -405,20 +405,19 @@ int ebitmap_read(struct ebitmap *e, void *fp) tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) { printk(KERN_ERR - "security: ebitmap: out of memory\n"); + "SELinux: ebitmap: out of memory\n"); rc = -ENOMEM; goto bad; } /* round down */ tmp->startbit = startbit - (startbit % EBITMAP_SIZE); - if (n) { + if (n) n->next = tmp; - } else { + else e->node = tmp; - } n = tmp; } else if (startbit <= n->startbit) { - printk(KERN_ERR "security: ebitmap: start bit %d" + printk(KERN_ERR "SELinux: ebitmap: start bit %d" " comes after start bit %d\n", startbit, n->startbit); goto bad; @@ -426,7 +425,7 @@ int ebitmap_read(struct ebitmap *e, void *fp) rc = next_entry(&map, fp, sizeof(u64)); if (rc < 0) { - printk(KERN_ERR "security: ebitmap: truncated map\n"); + printk(KERN_ERR "SELinux: ebitmap: truncated map\n"); goto bad; } map = le64_to_cpu(map); diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 77b530c3bbc..2e7788e1321 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -9,8 +9,8 @@ #include "hashtab.h" struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), - int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), - u32 size) + int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), + u32 size) { struct hashtab *p; u32 i; diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index feaf0a5b828..8b1706b7b3c 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -32,7 +32,7 @@ * Return the length in bytes for the MLS fields of the * security context string representation of `context'. */ -int mls_compute_context_len(struct context * context) +int mls_compute_context_len(struct context *context) { int i, l, len, head, prev; char *nm; @@ -86,7 +86,7 @@ int mls_compute_context_len(struct context * context) * Update `*scontext' to point to the end of the MLS fields. */ void mls_sid_to_context(struct context *context, - char **scontext) + char **scontext) { char *scontextp, *nm; int i, l, head, prev; @@ -146,7 +146,7 @@ void mls_sid_to_context(struct context *context, if (l == 0) { if (mls_level_eq(&context->range.level[0], - &context->range.level[1])) + &context->range.level[1])) break; else *scontextp++ = '-'; @@ -305,20 +305,21 @@ int mls_context_to_sid(char oldc, *p++ = 0; /* Separate into range if exists */ - if ((rngptr = strchr(scontextp, '.')) != NULL) { + rngptr = strchr(scontextp, '.'); + if (rngptr != NULL) { /* Remove '.' */ *rngptr++ = 0; } catdatum = hashtab_search(policydb.p_cats.table, - scontextp); + scontextp); if (!catdatum) { rc = -EINVAL; goto out; } rc = ebitmap_set_bit(&context->range.level[l].cat, - catdatum->value - 1, 1); + catdatum->value - 1, 1); if (rc) goto out; @@ -395,7 +396,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) rc = -ENOMEM; } else { rc = mls_context_to_sid(':', &tmpstr, context, - NULL, SECSID_NULL); + NULL, SECSID_NULL); kfree(freestr); } @@ -406,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) * Copies the MLS range `range' into `context'. */ static inline int mls_range_set(struct context *context, - struct mls_range *range) + struct mls_range *range) { int l, rc = 0; @@ -423,7 +424,7 @@ static inline int mls_range_set(struct context *context, } int mls_setup_user_range(struct context *fromcon, struct user_datum *user, - struct context *usercon) + struct context *usercon) { if (selinux_mls_enabled) { struct mls_level *fromcon_sen = &(fromcon->range.level[0]); @@ -449,11 +450,11 @@ int mls_setup_user_range(struct context *fromcon, struct user_datum *user, that of the user's default clearance (but only if the "fromcon" clearance dominates the user's computed sensitivity level) */ - if (mls_level_dom(user_clr, fromcon_clr)) { + if (mls_level_dom(user_clr, fromcon_clr)) *usercon_clr = *fromcon_clr; - } else if (mls_level_dom(fromcon_clr, user_clr)) { + else if (mls_level_dom(fromcon_clr, user_clr)) *usercon_clr = *user_clr; - } else + else return -EINVAL; } @@ -525,7 +526,7 @@ int mls_compute_sid(struct context *scontext, rtr->target_class == tclass) { /* Set the range from the rule */ return mls_range_set(newcontext, - &rtr->target_range); + &rtr->target_range); } } /* Fallthrough */ diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index bd7d6a00342..84f8cc73c7d 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -11,7 +11,7 @@ * * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> * - * Added conditional policy language extensions + * Added conditional policy language extensions * * Updated: Hewlett-Packard <paul.moore@hp.com> * @@ -21,7 +21,7 @@ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004 Tresys Technology, LLC * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. */ @@ -51,7 +51,7 @@ static char *symtab_name[SYM_NUM] = { }; #endif -int selinux_mls_enabled = 0; +int selinux_mls_enabled; static unsigned int symtab_sizes[SYM_NUM] = { 2, @@ -73,44 +73,49 @@ struct policydb_compat_info { /* These need to be updated if SYM_NUM or OCON_NUM changes */ static struct policydb_compat_info policydb_compat[] = { { - .version = POLICYDB_VERSION_BASE, - .sym_num = SYM_NUM - 3, - .ocon_num = OCON_NUM - 1, + .version = POLICYDB_VERSION_BASE, + .sym_num = SYM_NUM - 3, + .ocon_num = OCON_NUM - 1, }, { - .version = POLICYDB_VERSION_BOOL, - .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM - 1, + .version = POLICYDB_VERSION_BOOL, + .sym_num = SYM_NUM - 2, + .ocon_num = OCON_NUM - 1, }, { - .version = POLICYDB_VERSION_IPV6, - .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM, + .version = POLICYDB_VERSION_IPV6, + .sym_num = SYM_NUM - 2, + .ocon_num = OCON_NUM, }, { - .version = POLICYDB_VERSION_NLCLASS, - .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM, + .version = POLICYDB_VERSION_NLCLASS, + .sym_num = SYM_NUM - 2, + .ocon_num = OCON_NUM, }, { - .version = POLICYDB_VERSION_MLS, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .version = POLICYDB_VERSION_MLS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, }, { - .version = POLICYDB_VERSION_AVTAB, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .version = POLICYDB_VERSION_AVTAB, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, }, { - .version = POLICYDB_VERSION_RANGETRANS, - .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .version = POLICYDB_VERSION_RANGETRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, }, { .version = POLICYDB_VERSION_POLCAP, .sym_num = SYM_NUM, .ocon_num = OCON_NUM, + }, + { + .version = POLICYDB_VERSION_PERMISSIVE, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, } }; @@ -147,7 +152,7 @@ static int roles_init(struct policydb *p) rc = -EINVAL; goto out_free_role; } - key = kmalloc(strlen(OBJECT_R)+1,GFP_KERNEL); + key = kmalloc(strlen(OBJECT_R)+1, GFP_KERNEL); if (!key) { rc = -ENOMEM; goto out_free_role; @@ -194,6 +199,7 @@ static int policydb_init(struct policydb *p) goto out_free_symtab; ebitmap_init(&p->policycaps); + ebitmap_init(&p->permissive_map); out: return rc; @@ -384,7 +390,7 @@ static void symtab_hash_eval(struct symtab *s) struct hashtab_info info; hashtab_stat(h, &info); - printk(KERN_DEBUG "%s: %d entries and %d/%d buckets used, " + printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " "longest chain length %d\n", symtab_name[i], h->nel, info.slots_used, h->size, info.max_chain_len); } @@ -401,14 +407,14 @@ static int policydb_index_others(struct policydb *p) { int i, rc = 0; - printk(KERN_DEBUG "security: %d users, %d roles, %d types, %d bools", + printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); if (selinux_mls_enabled) printk(", %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim); printk("\n"); - printk(KERN_DEBUG "security: %d classes, %d rules\n", + printk(KERN_DEBUG "SELinux: %d classes, %d rules\n", p->p_classes.nprim, p->te_avtab.nel); #ifdef DEBUG_HASHES @@ -418,7 +424,7 @@ static int policydb_index_others(struct policydb *p) p->role_val_to_struct = kmalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)), - GFP_KERNEL); + GFP_KERNEL); if (!p->role_val_to_struct) { rc = -ENOMEM; goto out; @@ -426,7 +432,7 @@ static int policydb_index_others(struct policydb *p) p->user_val_to_struct = kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), - GFP_KERNEL); + GFP_KERNEL); if (!p->user_val_to_struct) { rc = -ENOMEM; goto out; @@ -628,7 +634,7 @@ void policydb_destroy(struct policydb *p) while (c) { ctmp = c; c = c->next; - ocontext_destroy(ctmp,i); + ocontext_destroy(ctmp, i); } p->ocontexts[i] = NULL; } @@ -641,7 +647,7 @@ void policydb_destroy(struct policydb *p) while (c) { ctmp = c; c = c->next; - ocontext_destroy(ctmp,OCON_FSUSE); + ocontext_destroy(ctmp, OCON_FSUSE); } gtmp = g; g = g->next; @@ -658,14 +664,14 @@ void policydb_destroy(struct policydb *p) } kfree(ltr); - for (ra = p->role_allow; ra; ra = ra -> next) { + for (ra = p->role_allow; ra; ra = ra->next) { cond_resched(); kfree(lra); lra = ra; } kfree(lra); - for (rt = p->range_tr; rt; rt = rt -> next) { + for (rt = p->range_tr; rt; rt = rt->next) { cond_resched(); if (lrt) { ebitmap_destroy(&lrt->target_range.level[0].cat); @@ -687,6 +693,7 @@ void policydb_destroy(struct policydb *p) kfree(p->type_attr_map); kfree(p->undefined_perms); ebitmap_destroy(&p->policycaps); + ebitmap_destroy(&p->permissive_map); return; } @@ -702,20 +709,20 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s) rc = sidtab_init(s); if (rc) { - printk(KERN_ERR "security: out of memory on SID table init\n"); + printk(KERN_ERR "SELinux: out of memory on SID table init\n"); goto out; } head = p->ocontexts[OCON_ISID]; for (c = head; c; c = c->next) { if (!c->context[0].user) { - printk(KERN_ERR "security: SID %s was never " + printk(KERN_ERR "SELinux: SID %s was never " "defined.\n", c->u.name); rc = -EINVAL; goto out; } if (sidtab_insert(s, c->sid[0], &c->context[0])) { - printk(KERN_ERR "security: unable to load initial " + printk(KERN_ERR "SELinux: unable to load initial " "SID %s.\n", c->u.name); rc = -EINVAL; goto out; @@ -809,13 +816,13 @@ static int mls_read_range_helper(struct mls_range *r, void *fp) items = le32_to_cpu(buf[0]); if (items > ARRAY_SIZE(buf)) { - printk(KERN_ERR "security: mls: range overflow\n"); + printk(KERN_ERR "SELinux: mls: range overflow\n"); rc = -EINVAL; goto out; } rc = next_entry(buf, fp, sizeof(u32) * items); if (rc < 0) { - printk(KERN_ERR "security: mls: truncated range\n"); + printk(KERN_ERR "SELinux: mls: truncated range\n"); goto out; } r->level[0].sens = le32_to_cpu(buf[0]); @@ -826,21 +833,21 @@ static int mls_read_range_helper(struct mls_range *r, void *fp) rc = ebitmap_read(&r->level[0].cat, fp); if (rc) { - printk(KERN_ERR "security: mls: error reading low " + printk(KERN_ERR "SELinux: mls: error reading low " "categories\n"); goto out; } if (items > 1) { rc = ebitmap_read(&r->level[1].cat, fp); if (rc) { - printk(KERN_ERR "security: mls: error reading high " + printk(KERN_ERR "SELinux: mls: error reading high " "categories\n"); goto bad_high; } } else { rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat); if (rc) { - printk(KERN_ERR "security: mls: out of memory\n"); + printk(KERN_ERR "SELinux: mls: out of memory\n"); goto bad_high; } } @@ -866,7 +873,7 @@ static int context_read_and_validate(struct context *c, rc = next_entry(buf, fp, sizeof buf); if (rc < 0) { - printk(KERN_ERR "security: context truncated\n"); + printk(KERN_ERR "SELinux: context truncated\n"); goto out; } c->user = le32_to_cpu(buf[0]); @@ -874,7 +881,7 @@ static int context_read_and_validate(struct context *c, c->type = le32_to_cpu(buf[2]); if (p->policyvers >= POLICYDB_VERSION_MLS) { if (mls_read_range_helper(&c->range, fp)) { - printk(KERN_ERR "security: error reading MLS range of " + printk(KERN_ERR "SELinux: error reading MLS range of " "context\n"); rc = -EINVAL; goto out; @@ -882,7 +889,7 @@ static int context_read_and_validate(struct context *c, } if (!policydb_context_isvalid(p, c)) { - printk(KERN_ERR "security: invalid security context\n"); + printk(KERN_ERR "SELinux: invalid security context\n"); context_destroy(c); rc = -EINVAL; } @@ -917,7 +924,7 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) len = le32_to_cpu(buf[0]); perdatum->value = le32_to_cpu(buf[1]); - key = kmalloc(len + 1,GFP_KERNEL); + key = kmalloc(len + 1, GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; @@ -964,7 +971,7 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) comdatum->permissions.nprim = le32_to_cpu(buf[2]); nel = le32_to_cpu(buf[3]); - key = kmalloc(len + 1,GFP_KERNEL); + key = kmalloc(len + 1, GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; @@ -991,7 +998,7 @@ bad: } static int read_cons_helper(struct constraint_node **nodep, int ncons, - int allowxtarget, void *fp) + int allowxtarget, void *fp) { struct constraint_node *c, *lc; struct constraint_expr *e, *le; @@ -1005,11 +1012,10 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, if (!c) return -ENOMEM; - if (lc) { + if (lc) lc->next = c; - } else { + else *nodep = c; - } rc = next_entry(buf, fp, (sizeof(u32) * 2)); if (rc < 0) @@ -1023,11 +1029,10 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, if (!e) return -ENOMEM; - if (le) { + if (le) le->next = e; - } else { + else c->expr = e; - } rc = next_entry(buf, fp, (sizeof(u32) * 3)); if (rc < 0) @@ -1104,7 +1109,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) ncons = le32_to_cpu(buf[5]); - key = kmalloc(len + 1,GFP_KERNEL); + key = kmalloc(len + 1, GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; @@ -1115,7 +1120,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) key[len] = 0; if (len2) { - cladatum->comkey = kmalloc(len2 + 1,GFP_KERNEL); + cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); if (!cladatum->comkey) { rc = -ENOMEM; goto bad; @@ -1128,7 +1133,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); if (!cladatum->comdatum) { - printk(KERN_ERR "security: unknown common %s\n", + printk(KERN_ERR "SELinux: unknown common %s\n", cladatum->comkey); rc = -EINVAL; goto bad; @@ -1188,7 +1193,7 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) len = le32_to_cpu(buf[0]); role->value = le32_to_cpu(buf[1]); - key = kmalloc(len + 1,GFP_KERNEL); + key = kmalloc(len + 1, GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; @@ -1208,7 +1213,7 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) if (strcmp(key, OBJECT_R) == 0) { if (role->value != OBJECT_R_VAL) { - printk(KERN_ERR "Role %s has wrong value %d\n", + printk(KERN_ERR "SELinux: Role %s has wrong value %d\n", OBJECT_R, role->value); rc = -EINVAL; goto bad; @@ -1235,7 +1240,7 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) __le32 buf[3]; u32 len; - typdatum = kzalloc(sizeof(*typdatum),GFP_KERNEL); + typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); if (!typdatum) { rc = -ENOMEM; return rc; @@ -1249,7 +1254,7 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) typdatum->value = le32_to_cpu(buf[1]); typdatum->primary = le32_to_cpu(buf[2]); - key = kmalloc(len + 1,GFP_KERNEL); + key = kmalloc(len + 1, GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; @@ -1283,13 +1288,13 @@ static int mls_read_level(struct mls_level *lp, void *fp) rc = next_entry(buf, fp, sizeof buf); if (rc < 0) { - printk(KERN_ERR "security: mls: truncated level\n"); + printk(KERN_ERR "SELinux: mls: truncated level\n"); goto bad; } lp->sens = le32_to_cpu(buf[0]); if (ebitmap_read(&lp->cat, fp)) { - printk(KERN_ERR "security: mls: error reading level " + printk(KERN_ERR "SELinux: mls: error reading level " "categories\n"); goto bad; } @@ -1321,7 +1326,7 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) len = le32_to_cpu(buf[0]); usrdatum->value = le32_to_cpu(buf[1]); - key = kmalloc(len + 1,GFP_KERNEL); + key = kmalloc(len + 1, GFP_KERNEL); if (!key) { rc = -ENOMEM; goto bad; @@ -1375,7 +1380,7 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) len = le32_to_cpu(buf[0]); levdatum->isalias = le32_to_cpu(buf[1]); - key = kmalloc(len + 1,GFP_ATOMIC); + key = kmalloc(len + 1, GFP_ATOMIC); if (!key) { rc = -ENOMEM; goto bad; @@ -1427,7 +1432,7 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp) catdatum->value = le32_to_cpu(buf[1]); catdatum->isalias = le32_to_cpu(buf[2]); - key = kmalloc(len + 1,GFP_ATOMIC); + key = kmalloc(len + 1, GFP_ATOMIC); if (!key) { rc = -ENOMEM; goto bad; @@ -1486,12 +1491,12 @@ int policydb_read(struct policydb *p, void *fp) goto out; /* Read the magic number and string length. */ - rc = next_entry(buf, fp, sizeof(u32)* 2); + rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc < 0) goto bad; if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) { - printk(KERN_ERR "security: policydb magic number 0x%x does " + printk(KERN_ERR "SELinux: policydb magic number 0x%x does " "not match expected magic number 0x%x\n", le32_to_cpu(buf[0]), POLICYDB_MAGIC); goto bad; @@ -1499,27 +1504,27 @@ int policydb_read(struct policydb *p, void *fp) len = le32_to_cpu(buf[1]); if (len != strlen(POLICYDB_STRING)) { - printk(KERN_ERR "security: policydb string length %d does not " + printk(KERN_ERR "SELinux: policydb string length %d does not " "match expected length %Zu\n", len, strlen(POLICYDB_STRING)); goto bad; } - policydb_str = kmalloc(len + 1,GFP_KERNEL); + policydb_str = kmalloc(len + 1, GFP_KERNEL); if (!policydb_str) { - printk(KERN_ERR "security: unable to allocate memory for policydb " + printk(KERN_ERR "SELinux: unable to allocate memory for policydb " "string of length %d\n", len); rc = -ENOMEM; goto bad; } rc = next_entry(policydb_str, fp, len); if (rc < 0) { - printk(KERN_ERR "security: truncated policydb string identifier\n"); + printk(KERN_ERR "SELinux: truncated policydb string identifier\n"); kfree(policydb_str); goto bad; } policydb_str[len] = 0; if (strcmp(policydb_str, POLICYDB_STRING)) { - printk(KERN_ERR "security: policydb string %s does not match " + printk(KERN_ERR "SELinux: policydb string %s does not match " "my string %s\n", policydb_str, POLICYDB_STRING); kfree(policydb_str); goto bad; @@ -1536,30 +1541,31 @@ int policydb_read(struct policydb *p, void *fp) p->policyvers = le32_to_cpu(buf[0]); if (p->policyvers < POLICYDB_VERSION_MIN || p->policyvers > POLICYDB_VERSION_MAX) { - printk(KERN_ERR "security: policydb version %d does not match " - "my version range %d-%d\n", - le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); - goto bad; + printk(KERN_ERR "SELinux: policydb version %d does not match " + "my version range %d-%d\n", + le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); + goto bad; } if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { if (ss_initialized && !selinux_mls_enabled) { - printk(KERN_ERR "Cannot switch between non-MLS and MLS " - "policies\n"); + printk(KERN_ERR "SELinux: Cannot switch between non-MLS" + " and MLS policies\n"); goto bad; } selinux_mls_enabled = 1; config |= POLICYDB_CONFIG_MLS; if (p->policyvers < POLICYDB_VERSION_MLS) { - printk(KERN_ERR "security policydb version %d (MLS) " - "not backwards compatible\n", p->policyvers); + printk(KERN_ERR "SELinux: security policydb version %d " + "(MLS) not backwards compatible\n", + p->policyvers); goto bad; } } else { if (ss_initialized && selinux_mls_enabled) { - printk(KERN_ERR "Cannot switch between MLS and non-MLS " - "policies\n"); + printk(KERN_ERR "SELinux: Cannot switch between MLS and" + " non-MLS policies\n"); goto bad; } } @@ -1570,16 +1576,20 @@ int policydb_read(struct policydb *p, void *fp) ebitmap_read(&p->policycaps, fp) != 0) goto bad; + if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE && + ebitmap_read(&p->permissive_map, fp) != 0) + goto bad; + info = policydb_lookup_compat(p->policyvers); if (!info) { - printk(KERN_ERR "security: unable to find policy compat info " + printk(KERN_ERR "SELinux: unable to find policy compat info " "for version %d\n", p->policyvers); goto bad; } if (le32_to_cpu(buf[2]) != info->sym_num || le32_to_cpu(buf[3]) != info->ocon_num) { - printk(KERN_ERR "security: policydb table sizes (%d,%d) do " + printk(KERN_ERR "SELinux: policydb table sizes (%d,%d) do " "not match mine (%d,%d)\n", le32_to_cpu(buf[2]), le32_to_cpu(buf[3]), info->sym_num, info->ocon_num); @@ -1622,11 +1632,10 @@ int policydb_read(struct policydb *p, void *fp) rc = -ENOMEM; goto bad; } - if (ltr) { + if (ltr) ltr->next = tr; - } else { + else p->role_tr = tr; - } rc = next_entry(buf, fp, sizeof(u32)*3); if (rc < 0) goto bad; @@ -1653,11 +1662,10 @@ int policydb_read(struct policydb *p, void *fp) rc = -ENOMEM; goto bad; } - if (lra) { + if (lra) lra->next = ra; - } else { + else p->role_allow = ra; - } rc = next_entry(buf, fp, sizeof(u32)*2); if (rc < 0) goto bad; @@ -1691,11 +1699,10 @@ int policydb_read(struct policydb *p, void *fp) rc = -ENOMEM; goto bad; } - if (l) { + if (l) l->next = c; - } else { + else p->ocontexts[i] = c; - } l = c; rc = -EINVAL; switch (i) { @@ -1714,7 +1721,7 @@ int policydb_read(struct policydb *p, void *fp) if (rc < 0) goto bad; len = le32_to_cpu(buf[0]); - c->u.name = kmalloc(len + 1,GFP_KERNEL); + c->u.name = kmalloc(len + 1, GFP_KERNEL); if (!c->u.name) { rc = -ENOMEM; goto bad; @@ -1742,7 +1749,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; break; case OCON_NODE: - rc = next_entry(buf, fp, sizeof(u32)* 2); + rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc < 0) goto bad; c->u.node.addr = le32_to_cpu(buf[0]); @@ -1759,7 +1766,7 @@ int policydb_read(struct policydb *p, void *fp) if (c->v.behavior > SECURITY_FS_USE_NONE) goto bad; len = le32_to_cpu(buf[1]); - c->u.name = kmalloc(len + 1,GFP_KERNEL); + c->u.name = kmalloc(len + 1, GFP_KERNEL); if (!c->u.name) { rc = -ENOMEM; goto bad; @@ -1807,7 +1814,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; } - newgenfs->fstype = kmalloc(len + 1,GFP_KERNEL); + newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL); if (!newgenfs->fstype) { rc = -ENOMEM; kfree(newgenfs); @@ -1823,7 +1830,7 @@ int policydb_read(struct policydb *p, void *fp) for (genfs_p = NULL, genfs = p->genfs; genfs; genfs_p = genfs, genfs = genfs->next) { if (strcmp(newgenfs->fstype, genfs->fstype) == 0) { - printk(KERN_ERR "security: dup genfs " + printk(KERN_ERR "SELinux: dup genfs " "fstype %s\n", newgenfs->fstype); kfree(newgenfs->fstype); kfree(newgenfs); @@ -1853,7 +1860,7 @@ int policydb_read(struct policydb *p, void *fp) goto bad; } - newc->u.name = kmalloc(len + 1,GFP_KERNEL); + newc->u.name = kmalloc(len + 1, GFP_KERNEL); if (!newc->u.name) { rc = -ENOMEM; goto bad_newc; @@ -1873,7 +1880,7 @@ int policydb_read(struct policydb *p, void *fp) if (!strcmp(newc->u.name, c->u.name) && (!c->v.sclass || !newc->v.sclass || newc->v.sclass == c->v.sclass)) { - printk(KERN_ERR "security: dup genfs " + printk(KERN_ERR "SELinux: dup genfs " "entry (%s,%s)\n", newgenfs->fstype, c->u.name); goto bad_newc; @@ -1931,7 +1938,7 @@ int policydb_read(struct policydb *p, void *fp) if (rc) goto bad; if (!mls_range_isvalid(p, &rt->target_range)) { - printk(KERN_WARNING "security: rangetrans: invalid range\n"); + printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); goto bad; } lrt = rt; @@ -1957,7 +1964,7 @@ int policydb_read(struct policydb *p, void *fp) out: return rc; bad_newc: - ocontext_destroy(newc,OCON_FSUSE); + ocontext_destroy(newc, OCON_FSUSE); bad: if (!rc) rc = -EINVAL; diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index c4ce996e202..ba593a3da87 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -243,6 +243,8 @@ struct policydb { struct ebitmap policycaps; + struct ebitmap permissive_map; + unsigned int policyvers; unsigned int reject_unknown : 1; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index f3741860121..2daaddbb301 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2,7 +2,7 @@ * Implementation of the security services. * * Authors : Stephen Smalley, <sds@epoch.ncsc.mil> - * James Morris <jmorris@redhat.com> + * James Morris <jmorris@redhat.com> * * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> * @@ -11,7 +11,7 @@ * * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> * - * Added conditional policy language extensions + * Added conditional policy language extensions * * Updated: Hewlett-Packard <paul.moore@hp.com> * @@ -27,7 +27,7 @@ * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. */ #include <linux/kernel.h> @@ -40,6 +40,7 @@ #include <linux/sched.h> #include <linux/audit.h> #include <linux/mutex.h> +#include <linux/selinux.h> #include <net/netlabel.h> #include "flask.h" @@ -56,11 +57,13 @@ #include "netlabel.h" #include "xfrm.h" #include "ebitmap.h" +#include "audit.h" extern void selnl_notify_policyload(u32 seqno); unsigned int policydb_loaded_version; int selinux_policycap_netpeer; +int selinux_policycap_openperm; /* * This is declared in avc.c @@ -79,7 +82,7 @@ static DEFINE_MUTEX(load_mutex); static struct sidtab sidtab; struct policydb policydb; -int ss_initialized = 0; +int ss_initialized; /* * The largest sequence number that has been used when @@ -87,7 +90,7 @@ int ss_initialized = 0; * The sequence number only changes when a policy change * occurs. */ -static u32 latest_granting = 0; +static u32 latest_granting; /* Forward declaration. */ static int context_struct_to_string(struct context *context, char **scontext, @@ -160,10 +163,10 @@ static int constraint_expr_eval(struct context *scontext, val1 - 1); continue; case CEXPR_INCOMP: - s[++sp] = ( !ebitmap_get_bit(&r1->dominates, - val2 - 1) && - !ebitmap_get_bit(&r2->dominates, - val1 - 1) ); + s[++sp] = (!ebitmap_get_bit(&r1->dominates, + val2 - 1) && + !ebitmap_get_bit(&r2->dominates, + val1 - 1)); continue; default: break; @@ -406,20 +409,46 @@ static int context_struct_compute_av(struct context *scontext, } if (!ra) avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | - PROCESS__DYNTRANSITION); + PROCESS__DYNTRANSITION); } return 0; inval_class: - printk(KERN_ERR "%s: unrecognized class %d\n", __FUNCTION__, tclass); + printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", __func__, + tclass); return -EINVAL; } +/* + * Given a sid find if the type has the permissive flag set + */ +int security_permissive_sid(u32 sid) +{ + struct context *context; + u32 type; + int rc; + + POLICY_RDLOCK; + + context = sidtab_search(&sidtab, sid); + BUG_ON(!context); + + type = context->type; + /* + * we are intentionally using type here, not type-1, the 0th bit may + * someday indicate that we are globally setting permissive in policy. + */ + rc = ebitmap_get_bit(&policydb.permissive_map, type); + + POLICY_RDUNLOCK; + return rc; +} + static int security_validtrans_handle_fail(struct context *ocontext, - struct context *ncontext, - struct context *tcontext, - u16 tclass) + struct context *ncontext, + struct context *tcontext, + u16 tclass) { char *o = NULL, *n = NULL, *t = NULL; u32 olen, nlen, tlen; @@ -431,9 +460,9 @@ static int security_validtrans_handle_fail(struct context *ocontext, if (context_struct_to_string(tcontext, &t, &tlen) < 0) goto out; audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "security_validate_transition: denied for" - " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", - o, n, t, policydb.p_class_val_to_name[tclass-1]); + "security_validate_transition: denied for" + " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", + o, n, t, policydb.p_class_val_to_name[tclass-1]); out: kfree(o); kfree(n); @@ -445,7 +474,7 @@ out: } int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, - u16 tclass) + u16 tclass) { struct context *ocontext; struct context *ncontext; @@ -471,8 +500,8 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, tclass = SECCLASS_NETLINK_SOCKET; if (!tclass || tclass > policydb.p_classes.nprim) { - printk(KERN_ERR "security_validate_transition: " - "unrecognized class %d\n", tclass); + printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", + __func__, tclass); rc = -EINVAL; goto out; } @@ -480,24 +509,24 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, ocontext = sidtab_search(&sidtab, oldsid); if (!ocontext) { - printk(KERN_ERR "security_validate_transition: " - " unrecognized SID %d\n", oldsid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, oldsid); rc = -EINVAL; goto out; } ncontext = sidtab_search(&sidtab, newsid); if (!ncontext) { - printk(KERN_ERR "security_validate_transition: " - " unrecognized SID %d\n", newsid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, newsid); rc = -EINVAL; goto out; } tcontext = sidtab_search(&sidtab, tasksid); if (!tcontext) { - printk(KERN_ERR "security_validate_transition: " - " unrecognized SID %d\n", tasksid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tasksid); rc = -EINVAL; goto out; } @@ -505,9 +534,9 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, constraint = tclass_datum->validatetrans; while (constraint) { if (!constraint_expr_eval(ocontext, ncontext, tcontext, - constraint->expr)) { + constraint->expr)) { rc = security_validtrans_handle_fail(ocontext, ncontext, - tcontext, tclass); + tcontext, tclass); goto out; } constraint = constraint->next; @@ -553,15 +582,15 @@ int security_compute_av(u32 ssid, scontext = sidtab_search(&sidtab, ssid); if (!scontext) { - printk(KERN_ERR "security_compute_av: unrecognized SID %d\n", - ssid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); rc = -EINVAL; goto out; } tcontext = sidtab_search(&sidtab, tsid); if (!tcontext) { - printk(KERN_ERR "security_compute_av: unrecognized SID %d\n", - tsid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); rc = -EINVAL; goto out; } @@ -595,9 +624,8 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 /* Allocate space for the context; caller must free this space. */ scontextp = kmalloc(*scontext_len, GFP_ATOMIC); - if (!scontextp) { + if (!scontextp) return -ENOMEM; - } *scontext = scontextp; /* @@ -608,8 +636,8 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 policydb.p_role_val_to_name[context->role - 1], policydb.p_type_val_to_name[context->type - 1]); scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) + - 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) + - 1 + strlen(policydb.p_type_val_to_name[context->type - 1]); + 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) + + 1 + strlen(policydb.p_type_val_to_name[context->type - 1]); mls_sid_to_context(context, &scontextp); @@ -650,7 +678,7 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) char *scontextp; *scontext_len = strlen(initial_sid_to_string[sid]) + 1; - scontextp = kmalloc(*scontext_len,GFP_ATOMIC); + scontextp = kmalloc(*scontext_len, GFP_ATOMIC); if (!scontextp) { rc = -ENOMEM; goto out; @@ -659,16 +687,16 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) *scontext = scontextp; goto out; } - printk(KERN_ERR "security_sid_to_context: called before initial " - "load_policy on unknown SID %d\n", sid); + printk(KERN_ERR "SELinux: %s: called before initial " + "load_policy on unknown SID %d\n", __func__, sid); rc = -EINVAL; goto out; } POLICY_RDLOCK; context = sidtab_search(&sidtab, sid); if (!context) { - printk(KERN_ERR "security_sid_to_context: unrecognized SID " - "%d\n", sid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, sid); rc = -EINVAL; goto out_unlock; } @@ -680,7 +708,8 @@ out: } -static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid) +static int security_context_to_sid_core(char *scontext, u32 scontext_len, + u32 *sid, u32 def_sid, gfp_t gfp_flags) { char *scontext2; struct context context; @@ -709,7 +738,7 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *s null suffix to the copy to avoid problems with the existing attr package, which doesn't view the null terminator as part of the attribute value. */ - scontext2 = kmalloc(scontext_len+1,GFP_KERNEL); + scontext2 = kmalloc(scontext_len+1, gfp_flags); if (!scontext2) { rc = -ENOMEM; goto out; @@ -809,7 +838,7 @@ out: int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) { return security_context_to_sid_core(scontext, scontext_len, - sid, SECSID_NULL); + sid, SECSID_NULL, GFP_KERNEL); } /** @@ -829,10 +858,11 @@ int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * memory is available, or 0 on success. */ -int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid) +int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, + u32 def_sid, gfp_t gfp_flags) { return security_context_to_sid_core(scontext, scontext_len, - sid, def_sid); + sid, def_sid, gfp_flags); } static int compute_sid_handle_invalid_context( @@ -896,15 +926,15 @@ static int security_compute_sid(u32 ssid, scontext = sidtab_search(&sidtab, ssid); if (!scontext) { - printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n", - ssid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); rc = -EINVAL; goto out_unlock; } tcontext = sidtab_search(&sidtab, tsid); if (!tcontext) { - printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n", - tsid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); rc = -EINVAL; goto out_unlock; } @@ -944,7 +974,7 @@ static int security_compute_sid(u32 ssid, avdatum = avtab_search(&policydb.te_avtab, &avkey); /* If no permanent rule, also check for enabled conditional rules */ - if(!avdatum) { + if (!avdatum) { node = avtab_search_node(&policydb.te_cond_avtab, &avkey); for (; node != NULL; node = avtab_search_node_next(node, specified)) { if (node->key.specified & AVTAB_ENABLED) { @@ -1094,7 +1124,7 @@ static int validate_classes(struct policydb *p) continue; if (i > p->p_classes.nprim) { printk(KERN_INFO - "security: class %s not defined in policy\n", + "SELinux: class %s not defined in policy\n", def_class); if (p->reject_unknown) return -EINVAL; @@ -1105,7 +1135,7 @@ static int validate_classes(struct policydb *p) pol_class = p->p_class_val_to_name[i-1]; if (strcmp(pol_class, def_class)) { printk(KERN_ERR - "security: class %d is incorrect, found %s but should be %s\n", + "SELinux: class %d is incorrect, found %s but should be %s\n", i, pol_class, def_class); return -EINVAL; } @@ -1123,7 +1153,7 @@ static int validate_classes(struct policydb *p) nprim = 1 << (perms->nprim - 1); if (perm_val > nprim) { printk(KERN_INFO - "security: permission %s in class %s not defined in policy\n", + "SELinux: permission %s in class %s not defined in policy\n", def_perm, pol_class); if (p->reject_unknown) return -EINVAL; @@ -1134,14 +1164,14 @@ static int validate_classes(struct policydb *p) perdatum = hashtab_search(perms->table, def_perm); if (perdatum == NULL) { printk(KERN_ERR - "security: permission %s in class %s not found in policy, bad policy\n", + "SELinux: permission %s in class %s not found in policy, bad policy\n", def_perm, pol_class); return -EINVAL; } pol_val = 1 << (perdatum->value - 1); if (pol_val != perm_val) { printk(KERN_ERR - "security: permission %s in class %s has incorrect value\n", + "SELinux: permission %s in class %s has incorrect value\n", def_perm, pol_class); return -EINVAL; } @@ -1155,7 +1185,7 @@ static int validate_classes(struct policydb *p) BUG_ON(!cladatum); if (!cladatum->comdatum) { printk(KERN_ERR - "security: class %s should have an inherits clause but does not\n", + "SELinux: class %s should have an inherits clause but does not\n", pol_class); return -EINVAL; } @@ -1170,7 +1200,7 @@ static int validate_classes(struct policydb *p) def_perm = kdefs->av_inherit[i].common_pts[j]; if (j >= perms->nprim) { printk(KERN_INFO - "security: permission %s in class %s not defined in policy\n", + "SELinux: permission %s in class %s not defined in policy\n", def_perm, pol_class); if (p->reject_unknown) return -EINVAL; @@ -1181,13 +1211,13 @@ static int validate_classes(struct policydb *p) perdatum = hashtab_search(perms->table, def_perm); if (perdatum == NULL) { printk(KERN_ERR - "security: permission %s in class %s not found in policy, bad policy\n", + "SELinux: permission %s in class %s not found in policy, bad policy\n", def_perm, pol_class); return -EINVAL; } if (perdatum->value != j + 1) { printk(KERN_ERR - "security: permission %s in class %s has incorrect value\n", + "SELinux: permission %s in class %s has incorrect value\n", def_perm, pol_class); return -EINVAL; } @@ -1217,7 +1247,7 @@ static inline int convert_context_handle_invalid_context(struct context *context u32 len; context_struct_to_string(context, &s, &len); - printk(KERN_ERR "security: context %s is invalid\n", s); + printk(KERN_ERR "SELinux: context %s is invalid\n", s); kfree(s); } return rc; @@ -1258,26 +1288,23 @@ static int convert_context(u32 key, /* Convert the user. */ usrdatum = hashtab_search(args->newp->p_users.table, - args->oldp->p_user_val_to_name[c->user - 1]); - if (!usrdatum) { + args->oldp->p_user_val_to_name[c->user - 1]); + if (!usrdatum) goto bad; - } c->user = usrdatum->value; /* Convert the role. */ role = hashtab_search(args->newp->p_roles.table, - args->oldp->p_role_val_to_name[c->role - 1]); - if (!role) { + args->oldp->p_role_val_to_name[c->role - 1]); + if (!role) goto bad; - } c->role = role->value; /* Convert the type. */ typdatum = hashtab_search(args->newp->p_types.table, - args->oldp->p_type_val_to_name[c->type - 1]); - if (!typdatum) { + args->oldp->p_type_val_to_name[c->type - 1]); + if (!typdatum) goto bad; - } c->type = typdatum->value; rc = mls_convert_context(args->oldp, args->newp, c); @@ -1297,7 +1324,7 @@ out: bad: context_struct_to_string(&oldc, &s, &len); context_destroy(&oldc); - printk(KERN_ERR "security: invalidating context %s\n", s); + printk(KERN_ERR "SELinux: invalidating context %s\n", s); kfree(s); goto out; } @@ -1306,6 +1333,8 @@ static void security_load_policycaps(void) { selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, POLICYDB_CAPABILITY_NETPEER); + selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, + POLICYDB_CAPABILITY_OPENPERM); } extern void selinux_complete_init(void); @@ -1348,7 +1377,7 @@ int security_load_policy(void *data, size_t len) /* Verify that the kernel defined classes are correct. */ if (validate_classes(&policydb)) { printk(KERN_ERR - "security: the definition of a class is incorrect\n"); + "SELinux: the definition of a class is incorrect\n"); LOAD_UNLOCK; sidtab_destroy(&sidtab); policydb_destroy(&policydb); @@ -1382,14 +1411,14 @@ int security_load_policy(void *data, size_t len) /* Verify that the kernel defined classes are correct. */ if (validate_classes(&newpolicydb)) { printk(KERN_ERR - "security: the definition of a class is incorrect\n"); + "SELinux: the definition of a class is incorrect\n"); rc = -EINVAL; goto err; } rc = security_preserve_bools(&newpolicydb); if (rc) { - printk(KERN_ERR "security: unable to preserve booleans\n"); + printk(KERN_ERR "SELinux: unable to preserve booleans\n"); goto err; } @@ -1441,17 +1470,11 @@ err: /** * security_port_sid - Obtain the SID for a port. - * @domain: communication domain aka address family - * @type: socket type * @protocol: protocol number * @port: port number * @out_sid: security identifier */ -int security_port_sid(u16 domain, - u16 type, - u8 protocol, - u16 port, - u32 *out_sid) +int security_port_sid(u8 protocol, u16 port, u32 *out_sid) { struct ocontext *c; int rc = 0; @@ -1530,8 +1553,8 @@ static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) { int i, fail = 0; - for(i = 0; i < 4; i++) - if(addr[i] != (input[i] & mask[i])) { + for (i = 0; i < 4; i++) + if (addr[i] != (input[i] & mask[i])) { fail = 1; break; } @@ -1630,7 +1653,7 @@ out: */ int security_get_user_sids(u32 fromsid, - char *username, + char *username, u32 **sids, u32 *nel) { @@ -1740,7 +1763,7 @@ out: * transition SIDs or task SIDs. */ int security_genfs_sid(const char *fstype, - char *path, + char *path, u16 sclass, u32 *sid) { @@ -1855,7 +1878,7 @@ int security_get_bools(int *len, char ***names, int **values) goto out; } - *names = kcalloc(*len, sizeof(char*), GFP_ATOMIC); + *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); if (!*names) goto err; @@ -1867,7 +1890,7 @@ int security_get_bools(int *len, char ***names, int **values) size_t name_len; (*values)[i] = policydb.bool_val_to_struct[i]->state; name_len = strlen(policydb.p_bool_val_to_name[i]) + 1; - (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); + (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); if (!(*names)[i]) goto err; strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len); @@ -1912,11 +1935,10 @@ int security_set_bools(int len, int *values) audit_get_loginuid(current), audit_get_sessionid(current)); } - if (values[i]) { + if (values[i]) policydb.bool_val_to_struct[i]->state = 1; - } else { + else policydb.bool_val_to_struct[i]->state = 0; - } } for (cur = policydb.cond_list; cur != NULL; cur = cur->next) { @@ -2010,16 +2032,16 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) POLICY_RDLOCK; context1 = sidtab_search(&sidtab, sid); if (!context1) { - printk(KERN_ERR "security_sid_mls_copy: unrecognized SID " - "%d\n", sid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, sid); rc = -EINVAL; goto out_unlock; } context2 = sidtab_search(&sidtab, mls_sid); if (!context2) { - printk(KERN_ERR "security_sid_mls_copy: unrecognized SID " - "%d\n", mls_sid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, mls_sid); rc = -EINVAL; goto out_unlock; } @@ -2110,17 +2132,15 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); if (!nlbl_ctx) { - printk(KERN_ERR - "security_sid_mls_cmp: unrecognized SID %d\n", - nlbl_sid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, nlbl_sid); rc = -EINVAL; goto out_slowpath; } xfrm_ctx = sidtab_search(&sidtab, xfrm_sid); if (!xfrm_ctx) { - printk(KERN_ERR - "security_sid_mls_cmp: unrecognized SID %d\n", - xfrm_sid); + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, xfrm_sid); rc = -EINVAL; goto out_slowpath; } @@ -2200,8 +2220,8 @@ int security_get_permissions(char *class, char ***perms, int *nperms) match = hashtab_search(policydb.p_classes.table, class); if (!match) { - printk(KERN_ERR "%s: unrecognized class %s\n", - __FUNCTION__, class); + printk(KERN_ERR "SELinux: %s: unrecognized class %s\n", + __func__, class); rc = -EINVAL; goto out; } @@ -2271,21 +2291,23 @@ struct selinux_audit_rule { struct context au_ctxt; }; -void selinux_audit_rule_free(struct selinux_audit_rule *rule) +void selinux_audit_rule_free(void *vrule) { + struct selinux_audit_rule *rule = vrule; + if (rule) { context_destroy(&rule->au_ctxt); kfree(rule); } } -int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, - struct selinux_audit_rule **rule) +int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) { struct selinux_audit_rule *tmprule; struct role_datum *roledatum; struct type_datum *typedatum; struct user_datum *userdatum; + struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; int rc = 0; *rule = NULL; @@ -2372,17 +2394,42 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, return rc; } -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, - struct selinux_audit_rule *rule, +/* Check to see if the rule contains any selinux fields */ +int selinux_audit_rule_known(struct audit_krule *rule) +{ + int i; + + for (i = 0; i < rule->field_count; i++) { + struct audit_field *f = &rule->fields[i]; + switch (f->type) { + case AUDIT_SUBJ_USER: + case AUDIT_SUBJ_ROLE: + case AUDIT_SUBJ_TYPE: + case AUDIT_SUBJ_SEN: + case AUDIT_SUBJ_CLR: + case AUDIT_OBJ_USER: + case AUDIT_OBJ_ROLE: + case AUDIT_OBJ_TYPE: + case AUDIT_OBJ_LEV_LOW: + case AUDIT_OBJ_LEV_HIGH: + return 1; + } + } + + return 0; +} + +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, struct audit_context *actx) { struct context *ctxt; struct mls_level *level; + struct selinux_audit_rule *rule = vrule; int match = 0; if (!rule) { audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "selinux_audit_rule_match: missing rule\n"); + "selinux_audit_rule_match: missing rule\n"); return -ENOENT; } @@ -2390,7 +2437,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, if (rule->au_seqno < latest_granting) { audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "selinux_audit_rule_match: stale rule\n"); + "selinux_audit_rule_match: stale rule\n"); match = -ESTALE; goto out; } @@ -2398,8 +2445,8 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, ctxt = sidtab_search(&sidtab, sid); if (!ctxt) { audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "selinux_audit_rule_match: unrecognized SID %d\n", - sid); + "selinux_audit_rule_match: unrecognized SID %d\n", + sid); match = -ENOENT; goto out; } @@ -2445,36 +2492,36 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: level = ((field == AUDIT_SUBJ_SEN || - field == AUDIT_OBJ_LEV_LOW) ? - &ctxt->range.level[0] : &ctxt->range.level[1]); + field == AUDIT_OBJ_LEV_LOW) ? + &ctxt->range.level[0] : &ctxt->range.level[1]); switch (op) { case AUDIT_EQUAL: match = mls_level_eq(&rule->au_ctxt.range.level[0], - level); + level); break; case AUDIT_NOT_EQUAL: match = !mls_level_eq(&rule->au_ctxt.range.level[0], - level); + level); break; case AUDIT_LESS_THAN: match = (mls_level_dom(&rule->au_ctxt.range.level[0], - level) && - !mls_level_eq(&rule->au_ctxt.range.level[0], - level)); + level) && + !mls_level_eq(&rule->au_ctxt.range.level[0], + level)); break; case AUDIT_LESS_THAN_OR_EQUAL: match = mls_level_dom(&rule->au_ctxt.range.level[0], - level); + level); break; case AUDIT_GREATER_THAN: match = (mls_level_dom(level, - &rule->au_ctxt.range.level[0]) && - !mls_level_eq(level, - &rule->au_ctxt.range.level[0])); + &rule->au_ctxt.range.level[0]) && + !mls_level_eq(level, + &rule->au_ctxt.range.level[0])); break; case AUDIT_GREATER_THAN_OR_EQUAL: match = mls_level_dom(level, - &rule->au_ctxt.range.level[0]); + &rule->au_ctxt.range.level[0]); break; } } @@ -2484,7 +2531,7 @@ out: return match; } -static int (*aurule_callback)(void) = NULL; +static int (*aurule_callback)(void) = audit_update_lsm_rules; static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, u16 class, u32 perms, u32 *retained) @@ -2501,7 +2548,7 @@ static int __init aurule_init(void) int err; err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET, - SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); + SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); if (err) panic("avc_add_callback() failed, error %d\n", err); @@ -2509,11 +2556,6 @@ static int __init aurule_init(void) } __initcall(aurule_init); -void selinux_audit_set_callback(int (*callback)(void)) -{ - aurule_callback = callback; -} - #ifdef CONFIG_NETLABEL /** * security_netlbl_cache_add - Add an entry to the NetLabel cache @@ -2649,7 +2691,7 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) goto netlbl_sid_to_secattr_failure; secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], GFP_ATOMIC); - secattr->flags |= NETLBL_SECATTR_DOMAIN; + secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY; mls_export_netlbl_lvl(ctx, secattr); rc = mls_export_netlbl_cat(ctx, secattr); if (rc != 0) diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c index 53a54a77f1f..4a516ff4bcd 100644 --- a/security/selinux/ss/sidtab.c +++ b/security/selinux/ss/sidtab.c @@ -156,12 +156,10 @@ void sidtab_map_remove_on_error(struct sidtab *s, while (cur != NULL) { ret = apply(cur->sid, &cur->context, args); if (ret) { - if (last) { + if (last) last->next = cur->next; - } else { + else s->htable[i] = cur->next; - } - temp = cur; cur = cur->next; context_destroy(&temp->context); diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 7e158205d08..8f17f542a11 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -45,7 +45,6 @@ #include <net/xfrm.h> #include <net/checksum.h> #include <net/udp.h> -#include <asm/semaphore.h> #include <asm/atomic.h> #include "avc.h" @@ -77,20 +76,18 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) * LSM hook implementation that authorizes that a flow can use * a xfrm policy rule. */ -int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) +int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) { int rc; u32 sel_sid; - struct xfrm_sec_ctx *ctx; /* Context sid is either set to label or ANY_ASSOC */ - if ((ctx = xp->security)) { + if (ctx) { if (!selinux_authorizable_ctx(ctx)) return -EINVAL; sel_sid = ctx->ctx_sid; - } - else + } else /* * All flows should be treated as polmatch'ing an * otherwise applicable "non-labeled" policy. This @@ -103,7 +100,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) NULL); if (rc == -EACCES) - rc = -ESRCH; + return -ESRCH; return rc; } @@ -183,8 +180,7 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) if (!ckall) break; - } - else if (*sid != ctx->ctx_sid) + } else if (*sid != ctx->ctx_sid) return -EINVAL; } } @@ -287,15 +283,14 @@ out2: * LSM hook implementation that allocs and transfers uctx spec to * xfrm_policy. */ -int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *uctx) +int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *uctx) { int err; - BUG_ON(!xp); BUG_ON(!uctx); - err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); + err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0); if (err == 0) atomic_inc(&selinux_xfrm_refcount); @@ -307,43 +302,38 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, * LSM hook implementation that copies security data structure from old to * new for policy cloning. */ -int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) +int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { - struct xfrm_sec_ctx *old_ctx, *new_ctx; - - old_ctx = old->security; + struct xfrm_sec_ctx *new_ctx; if (old_ctx) { - new_ctx = new->security = kmalloc(sizeof(*new_ctx) + - old_ctx->ctx_len, - GFP_KERNEL); - + new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, + GFP_KERNEL); if (!new_ctx) return -ENOMEM; memcpy(new_ctx, old_ctx, sizeof(*new_ctx)); memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len); + *new_ctxp = new_ctx; } return 0; } /* - * LSM hook implementation that frees xfrm_policy security information. + * LSM hook implementation that frees xfrm_sec_ctx security information. */ -void selinux_xfrm_policy_free(struct xfrm_policy *xp) +void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { - struct xfrm_sec_ctx *ctx = xp->security; - if (ctx) - kfree(ctx); + kfree(ctx); } /* * LSM hook implementation that authorizes deletion of labeled policies. */ -int selinux_xfrm_policy_delete(struct xfrm_policy *xp) +int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { struct task_security_struct *tsec = current->security; - struct xfrm_sec_ctx *ctx = xp->security; int rc = 0; if (ctx) { @@ -380,8 +370,7 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct void selinux_xfrm_state_free(struct xfrm_state *x) { struct xfrm_sec_ctx *ctx = x->security; - if (ctx) - kfree(ctx); + kfree(ctx); } /* diff --git a/security/smack/smack.h b/security/smack/smack.h index 62c1e982849..4a4477f5afd 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -15,6 +15,7 @@ #include <linux/capability.h> #include <linux/spinlock.h> +#include <linux/security.h> #include <net/netlabel.h> /* @@ -187,6 +188,7 @@ extern struct smack_known smack_known_star; extern struct smack_known smack_known_unset; extern struct smk_list_entry *smack_list; +extern struct security_operations smack_ops; /* * Stricly for CIPSO level manipulation. diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 0241fd35967..4215971434e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -315,10 +315,10 @@ static int smack_sb_statfs(struct dentry *dentry) * Returns 0 if current can write the floor of the filesystem * being mounted on, an error code otherwise. */ -static int smack_sb_mount(char *dev_name, struct nameidata *nd, +static int smack_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { - struct superblock_smack *sbp = nd->path.mnt->mnt_sb->s_security; + struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; return smk_curacc(sbp->smk_floor, MAY_WRITE); } @@ -1117,11 +1117,6 @@ static int smack_task_movememory(struct task_struct *p) static int smack_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid) { - int rc; - - rc = cap_task_kill(p, info, sig, secid); - if (rc != 0) - return rc; /* * Special cases where signals really ought to go through * in spite of policy. Stephen Smalley suggests it may @@ -1280,7 +1275,7 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) switch (smack_net_nltype) { case NETLBL_NLTYPE_CIPSOV4: - nlsp->domain = kstrdup(smack, GFP_ATOMIC); + nlsp->domain = smack; nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; rc = smack_to_cipso(smack, &cipso); @@ -1508,7 +1503,7 @@ static int smack_shm_associate(struct shmid_kernel *shp, int shmflg) */ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) { - char *ssp = smack_of_shm(shp); + char *ssp; int may; switch (cmd) { @@ -1532,6 +1527,7 @@ static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd) return -EINVAL; } + ssp = smack_of_shm(shp); return smk_curacc(ssp, may); } @@ -1616,7 +1612,7 @@ static int smack_sem_associate(struct sem_array *sma, int semflg) */ static int smack_sem_semctl(struct sem_array *sma, int cmd) { - char *ssp = smack_of_sem(sma); + char *ssp; int may; switch (cmd) { @@ -1645,6 +1641,7 @@ static int smack_sem_semctl(struct sem_array *sma, int cmd) return -EINVAL; } + ssp = smack_of_sem(sma); return smk_curacc(ssp, may); } @@ -1730,7 +1727,7 @@ static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg) */ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) { - char *msp = smack_of_msq(msq); + char *msp; int may; switch (cmd) { @@ -1752,6 +1749,7 @@ static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd) return -EINVAL; } + msp = smack_of_msq(msq); return smk_curacc(msp, may); } @@ -2426,7 +2424,9 @@ static void smack_release_secctx(char *secdata, u32 seclen) { } -static struct security_operations smack_ops = { +struct security_operations smack_ops = { + .name = "smack", + .ptrace = smack_ptrace, .capget = cap_capget, .capset_check = cap_capset_check, @@ -2559,6 +2559,9 @@ static struct security_operations smack_ops = { */ static __init int smack_init(void) { + if (!security_module_enable(&smack_ops)) + return 0; + printk(KERN_INFO "Smack: Initializing.\n"); /* diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index afe7c9b0732..6ba283783b7 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -74,11 +74,6 @@ struct smk_list_entry *smack_list; #define SEQ_READ_FINISHED 1 /* - * Disable concurrent writing open() operations - */ -static struct semaphore smack_write_sem; - -/* * Values for parsing cipso rules * SMK_DIGITLEN: Length of a digit field in a rule. * SMK_CIPSOMIN: Minimum possible cipso rule length. @@ -168,32 +163,7 @@ static struct seq_operations load_seq_ops = { */ static int smk_open_load(struct inode *inode, struct file *file) { - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - return seq_open(file, &load_seq_ops); - - if (down_interruptible(&smack_write_sem)) - return -ERESTARTSYS; - - return 0; -} - -/** - * smk_release_load - release() for /smack/load - * @inode: inode structure representing file - * @file: "load" file pointer - * - * For a reading session, use the seq_file release - * implementation. - * Otherwise, we are at the end of a writing session so - * clean everything up. - */ -static int smk_release_load(struct inode *inode, struct file *file) -{ - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - return seq_release(inode, file); - - up(&smack_write_sem); - return 0; + return seq_open(file, &load_seq_ops); } /** @@ -341,7 +311,7 @@ static const struct file_operations smk_load_ops = { .read = seq_read, .llseek = seq_lseek, .write = smk_write_load, - .release = smk_release_load, + .release = seq_release, }; /** @@ -995,12 +965,21 @@ static struct vfsmount *smackfs_mount; * * register the smackfs * - * Returns 0 unless the registration fails. + * Do not register smackfs if Smack wasn't enabled + * on boot. We can not put this method normally under the + * smack_init() code path since the security subsystem get + * initialized before the vfs caches. + * + * Returns true if we were not chosen on boot or if + * we were chosen and filesystem registration succeeded. */ static int __init init_smk_fs(void) { int err; + if (!security_module_enable(&smack_ops)) + return 0; + err = register_filesystem(&smk_fs_type); if (!err) { smackfs_mount = kern_mount(&smk_fs_type); @@ -1011,7 +990,6 @@ static int __init init_smk_fs(void) } } - sema_init(&smack_write_sem, 1); smk_cipso_doi(); smk_unlbl_ambient(NULL); |