diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/Kconfig | 49 | ||||
| -rw-r--r-- | security/commoncap.c | 11 | ||||
| -rw-r--r-- | security/inode.c | 2 | ||||
| -rw-r--r-- | security/lsm_audit.c | 4 | ||||
| -rw-r--r-- | security/security.c | 1 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 35 | ||||
| -rw-r--r-- | security/selinux/include/classmap.h | 4 | ||||
| -rw-r--r-- | security/selinux/include/security.h | 2 | ||||
| -rw-r--r-- | security/selinux/nlmsgtab.c | 25 | ||||
| -rw-r--r-- | security/selinux/ss/avtab.c | 69 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.c | 4 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.h | 2 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 4 |
13 files changed, 199 insertions, 13 deletions
diff --git a/security/Kconfig b/security/Kconfig index a3ebb6ee5bd5..7bcb805f36a4 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -18,6 +18,15 @@ config SECURITY_DMESG_RESTRICT If you are unsure how to answer this question, answer N. +config SECURITY_PERF_EVENTS_RESTRICT + bool "Restrict unprivileged use of performance events" + depends on PERF_EVENTS + help + If you say Y here, the kernel.perf_event_paranoid sysctl + will be set to 3 by default, and no unprivileged use of the + perf_event_open syscall will be permitted unless it is + changed. + config SECURITY bool "Enable different security models" depends on SYSFS @@ -128,6 +137,46 @@ config LSM_MMAP_MIN_ADDR this low address space will need the permission specific to the systems running LSM. +config HAVE_HARDENED_USERCOPY_ALLOCATOR + bool + help + The heap allocator implements __check_heap_object() for + validating memory ranges against heap object sizes in + support of CONFIG_HARDENED_USERCOPY. + +config HAVE_ARCH_HARDENED_USERCOPY + bool + help + The architecture supports CONFIG_HARDENED_USERCOPY by + calling check_object_size() just before performing the + userspace copies in the low level implementation of + copy_to_user() and copy_from_user(). + +config HARDENED_USERCOPY + bool "Harden memory copies between kernel and userspace" + depends on HAVE_ARCH_HARDENED_USERCOPY + depends on HAVE_HARDENED_USERCOPY_ALLOCATOR + select BUG + help + This option checks for obviously wrong memory regions when + copying memory to/from the kernel (via copy_to_user() and + copy_from_user() functions) by rejecting memory ranges that + are larger than the specified heap object, span multiple + separately allocates pages, are not on the process stack, + or are part of the kernel text. This kills entire classes + of heap overflow exploits and similar kernel memory exposures. + +config HARDENED_USERCOPY_PAGESPAN + bool "Refuse to copy allocations that span multiple pages" + depends on HARDENED_USERCOPY + depends on !COMPILE_TEST + help + When a multi-page allocation is done without __GFP_COMP, + hardened usercopy will reject attempts to copy it. There are, + however, several cases of this in the kernel that have not all + been removed. This config is intended to be used only while + trying to find such users. + source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig diff --git a/security/commoncap.c b/security/commoncap.c index b62f97d83fd8..368631db0933 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -31,6 +31,10 @@ #include <linux/binfmts.h> #include <linux/personality.h> +#ifdef CONFIG_ANDROID_PARANOID_NETWORK +#include <linux/android_aid.h> +#endif + /* * If a non-root user executes a setuid-root binary in * !secure(SECURE_NOROOT) mode, then we raise capabilities. @@ -73,6 +77,13 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, { struct user_namespace *ns = targ_ns; +#ifdef CONFIG_ANDROID_PARANOID_NETWORK + if (cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW)) + return 0; + if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN)) + return 0; +#endif + /* See if cred has the capability in the target user namespace * by examining the target user namespace and all of the target * user namespace's parents. diff --git a/security/inode.c b/security/inode.c index 16622aef9bde..0f1a041bf6cb 100644 --- a/security/inode.c +++ b/security/inode.c @@ -100,7 +100,7 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode, dir = d_inode(parent); mutex_lock(&dir->i_mutex); - dentry = lookup_one_len(name, parent, strlen(name)); + dentry = lookup_one_len2(name, mount, parent, strlen(name)); if (IS_ERR(dentry)) goto out; diff --git a/security/lsm_audit.c b/security/lsm_audit.c index d4f9e2b69caa..24ea1eeee9cd 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -220,7 +220,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, */ BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2); - audit_log_format(ab, " pid=%d comm=", task_pid_nr(current)); + audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current)); audit_log_untrustedstring(ab, memcpy(comm, current->comm, sizeof(comm))); switch (a->type) { @@ -297,7 +297,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, case LSM_AUDIT_DATA_TASK: { struct task_struct *tsk = a->u.tsk; if (tsk) { - pid_t pid = task_pid_nr(tsk); + pid_t pid = task_tgid_nr(tsk); if (pid) { char comm[sizeof(tsk->comm)]; audit_log_format(ab, " opid=%d ocomm=", pid); diff --git a/security/security.c b/security/security.c index b81a709ff331..dfee1833967a 100644 --- a/security/security.c +++ b/security/security.c @@ -498,6 +498,7 @@ int security_path_chown(struct path *path, kuid_t uid, kgid_t gid) return 0; return call_int_hook(path_chown, 0, path, uid, gid); } +EXPORT_SYMBOL(security_path_chown); int security_path_chroot(struct path *path) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 44f4495e3fbd..25d784070cf8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -402,6 +402,7 @@ static int selinux_is_genfs_special_handling(struct super_block *sb) return !strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "pstore") || !strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "rootfs"); } @@ -745,6 +746,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, sbsec->flags |= SE_SBPROC | SE_SBGENFS; if (!strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "pstore")) sbsec->flags |= SE_SBGENFS; @@ -3658,6 +3660,38 @@ static int selinux_kernel_module_request(char *kmod_name) SYSTEM__MODULE_REQUEST, &ad); } +static int selinux_kernel_module_from_file(struct file *file) +{ + struct common_audit_data ad; + struct inode_security_struct *isec; + struct file_security_struct *fsec; + struct inode *inode; + u32 sid = current_sid(); + int rc; + + /* init_module */ + if (file == NULL) + return avc_has_perm(sid, sid, SECCLASS_SYSTEM, + SYSTEM__MODULE_LOAD, NULL); + + /* finit_module */ + ad.type = LSM_AUDIT_DATA_PATH; + ad.u.path = file->f_path; + + inode = file_inode(file); + isec = inode->i_security; + fsec = file->f_security; + + if (sid != fsec->sid) { + rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); + if (rc) + return rc; + } + + return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM, + SYSTEM__MODULE_LOAD, &ad); +} + static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) { return current_has_perm(p, PROCESS__SETPGID); @@ -5979,6 +6013,7 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as), LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as), LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request), + LSM_HOOK_INIT(kernel_module_from_file, selinux_kernel_module_from_file), LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid), LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid), LSM_HOOK_INIT(task_getsid, selinux_task_getsid), diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 5a4eef59aeff..31dc821a6be0 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -32,7 +32,7 @@ struct security_class_mapping secclass_map[] = { "setsockcreate", NULL } }, { "system", { "ipc_info", "syslog_read", "syslog_mod", - "syslog_console", "module_request", NULL } }, + "syslog_console", "module_request", "module_load", NULL } }, { "capability", { "chown", "dac_override", "dac_read_search", "fowner", "fsetid", "kill", "setgid", "setuid", "setpcap", @@ -100,7 +100,7 @@ struct security_class_mapping secclass_map[] = { { COMMON_IPC_PERMS, NULL } }, { "netlink_route_socket", { COMMON_SOCK_PERMS, - "nlmsg_read", "nlmsg_write", NULL } }, + "nlmsg_read", "nlmsg_write", "nlmsg_readpriv", NULL } }, { "netlink_tcpdiag_socket", { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } }, diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 223e9fd15d66..dff1d1a1367a 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -79,6 +79,7 @@ enum { }; #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) +extern int selinux_android_netlink_route; extern int selinux_policycap_netpeer; extern int selinux_policycap_openperm; extern int selinux_policycap_alwaysnetwork; @@ -264,6 +265,7 @@ extern struct vfsmount *selinuxfs_mount; extern void selnl_notify_setenforce(int val); extern void selnl_notify_policyload(u32 seqno); extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); +extern void selinux_nlmsg_init(void); #endif /* _SELINUX_SECURITY_H_ */ diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 2bbb41822d8e..78a8c420b1f5 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -83,6 +83,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] = { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { SOCK_DESTROY_BACKPORT,NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE }, }; static struct nlmsg_perm nlmsg_xfrm_perms[] = @@ -190,3 +191,27 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) return err; } + +static void nlmsg_set_getlink_perm(u32 perm) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nlmsg_route_perms); i++) { + if (nlmsg_route_perms[i].nlmsg_type == RTM_GETLINK) { + nlmsg_route_perms[i].perm = perm; + break; + } + } +} + +/** + * Use nlmsg_readpriv as the permission for RTM_GETLINK messages if the + * netlink_route_getlink policy capability is set. Otherwise use nlmsg_read. + */ +void selinux_nlmsg_init(void) +{ + if (selinux_android_netlink_route) + nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READPRIV); + else + nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READ); +} diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 3628d3a868b6..31345376aa9b 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -374,6 +374,32 @@ void avtab_hash_eval(struct avtab *h, char *tag) chain2_len_sum); } +/* + * extended permissions compatibility. Make ToT Android kernels compatible + * with Android M releases + */ +#define AVTAB_OPTYPE_ALLOWED 0x1000 +#define AVTAB_OPTYPE_AUDITALLOW 0x2000 +#define AVTAB_OPTYPE_DONTAUDIT 0x4000 +#define AVTAB_OPTYPE (AVTAB_OPTYPE_ALLOWED | \ + AVTAB_OPTYPE_AUDITALLOW | \ + AVTAB_OPTYPE_DONTAUDIT) +#define AVTAB_XPERMS_OPTYPE 4 + +#define avtab_xperms_to_optype(x) (x << AVTAB_XPERMS_OPTYPE) +#define avtab_optype_to_xperms(x) (x >> AVTAB_XPERMS_OPTYPE) + +static unsigned int avtab_android_m_compat; + +static void avtab_android_m_compat_set(void) +{ + if (!avtab_android_m_compat) { + pr_info("SELinux: Android master kernel running Android" + " M policy in compatibility mode.\n"); + avtab_android_m_compat = 1; + } +} + static uint16_t spec_order[] = { AVTAB_ALLOWED, AVTAB_AUDITDENY, @@ -398,6 +424,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, struct avtab_datum datum; struct avtab_extended_perms xperms; __le32 buf32[ARRAY_SIZE(xperms.perms.p)]; + unsigned int android_m_compat_optype = 0; int i, rc; unsigned set; @@ -488,6 +515,13 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, key.target_class = le16_to_cpu(buf16[items++]); key.specified = le16_to_cpu(buf16[items++]); + if ((key.specified & AVTAB_OPTYPE) && + (vers == POLICYDB_VERSION_XPERMS_IOCTL)) { + key.specified = avtab_optype_to_xperms(key.specified); + android_m_compat_optype = 1; + avtab_android_m_compat_set(); + } + if (!policydb_type_isvalid(pol, key.source_type) || !policydb_type_isvalid(pol, key.target_type) || !policydb_class_isvalid(pol, key.target_class)) { @@ -518,10 +552,22 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: truncated entry\n"); return rc; } - rc = next_entry(&xperms.driver, fp, sizeof(u8)); - if (rc) { - printk(KERN_ERR "SELinux: avtab: truncated entry\n"); - return rc; + if (avtab_android_m_compat || + ((xperms.specified != AVTAB_XPERMS_IOCTLFUNCTION) && + (xperms.specified != AVTAB_XPERMS_IOCTLDRIVER) && + (vers == POLICYDB_VERSION_XPERMS_IOCTL))) { + xperms.driver = xperms.specified; + if (android_m_compat_optype) + xperms.specified = AVTAB_XPERMS_IOCTLDRIVER; + else + xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION; + avtab_android_m_compat_set(); + } else { + rc = next_entry(&xperms.driver, fp, sizeof(u8)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } } rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p)); if (rc) { @@ -607,15 +653,22 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) buf16[0] = cpu_to_le16(cur->key.source_type); buf16[1] = cpu_to_le16(cur->key.target_type); buf16[2] = cpu_to_le16(cur->key.target_class); - buf16[3] = cpu_to_le16(cur->key.specified); + if (avtab_android_m_compat && (cur->key.specified & AVTAB_XPERMS) && + (cur->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER)) + buf16[3] = cpu_to_le16(avtab_xperms_to_optype(cur->key.specified)); + else + buf16[3] = cpu_to_le16(cur->key.specified); rc = put_entry(buf16, sizeof(u16), 4, fp); if (rc) return rc; if (cur->key.specified & AVTAB_XPERMS) { - rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp); - if (rc) - return rc; + if (avtab_android_m_compat == 0) { + rc = put_entry(&cur->datum.u.xperms->specified, + sizeof(u8), 1, fp); + if (rc) + return rc; + } rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp); if (rc) return rc; diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 01fbbbf89f41..5ee23e3a3678 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -2329,6 +2329,10 @@ int policydb_read(struct policydb *p, void *fp) p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); + if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE)) { + p->android_netlink_route = 1; + } + if (p->policyvers >= POLICYDB_VERSION_POLCAP) { rc = ebitmap_read(&p->policycaps, fp); if (rc) diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 725d5945a97e..0d511cf3c1e9 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -227,6 +227,7 @@ struct genfs { /* The policy database */ struct policydb { int mls_enabled; + int android_netlink_route; /* symbol tables */ struct symtab symtab[SYM_NUM]; @@ -313,6 +314,7 @@ extern int policydb_write(struct policydb *p, void *fp); #define PERM_SYMTAB_SIZE 32 #define POLICYDB_CONFIG_MLS 1 +#define POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE (1 << 31) /* the config flags related to unknown classes/perms are bits 2 and 3 */ #define REJECT_UNKNOWN 0x00000002 diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 55c869e0a3a0..52cf500a8418 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -70,6 +70,7 @@ #include "ebitmap.h" #include "audit.h" +int selinux_android_netlink_route; int selinux_policycap_netpeer; int selinux_policycap_openperm; int selinux_policycap_alwaysnetwork; @@ -1997,6 +1998,9 @@ static void security_load_policycaps(void) POLICYDB_CAPABILITY_OPENPERM); selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps, POLICYDB_CAPABILITY_ALWAYSNETWORK); + + selinux_android_netlink_route = policydb.android_netlink_route; + selinux_nlmsg_init(); } static int security_preserve_bools(struct policydb *p); |
