Commit 52dec22e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of...

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6:
  security: define round_hint_to_min in !CONFIG_SECURITY
  Security/SELinux: seperate lsm specific mmap_min_addr
  SELinux: call cap_file_mmap in selinux_file_mmap
  Capabilities: move cap_file_mmap to commoncap.c
parents 08e53fcb 1d995973
...@@ -34,8 +34,6 @@ extern int sysctl_legacy_va_layout; ...@@ -34,8 +34,6 @@ extern int sysctl_legacy_va_layout;
#define sysctl_legacy_va_layout 0 #define sysctl_legacy_va_layout 0
#endif #endif
extern unsigned long mmap_min_addr;
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -574,19 +572,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone, ...@@ -574,19 +572,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
set_page_section(page, pfn_to_section_nr(pfn)); set_page_section(page, pfn_to_section_nr(pfn));
} }
/*
* If a hint addr is less than mmap_min_addr change hint to be as
* low as possible but still greater than mmap_min_addr
*/
static inline unsigned long round_hint_to_min(unsigned long hint)
{
hint &= PAGE_MASK;
if (((void *)hint != NULL) &&
(hint < mmap_min_addr))
return PAGE_ALIGN(mmap_min_addr);
return hint;
}
/* /*
* Some inline functions in vmstat.h depend on page_zone() * Some inline functions in vmstat.h depend on page_zone()
*/ */
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/resource.h> #include <linux/resource.h>
#include <linux/sem.h> #include <linux/sem.h>
#include <linux/shm.h> #include <linux/shm.h>
#include <linux/mm.h> /* PAGE_ALIGN */
#include <linux/msg.h> #include <linux/msg.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/key.h> #include <linux/key.h>
...@@ -66,6 +67,9 @@ extern int cap_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -66,6 +67,9 @@ extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
extern int cap_inode_removexattr(struct dentry *dentry, const char *name); extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
extern int cap_inode_need_killpriv(struct dentry *dentry); extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry); extern int cap_inode_killpriv(struct dentry *dentry);
extern int cap_file_mmap(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags,
unsigned long addr, unsigned long addr_only);
extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags); extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5); unsigned long arg4, unsigned long arg5);
...@@ -92,6 +96,7 @@ extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); ...@@ -92,6 +96,7 @@ extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
extern int cap_netlink_recv(struct sk_buff *skb, int cap); extern int cap_netlink_recv(struct sk_buff *skb, int cap);
extern unsigned long mmap_min_addr; extern unsigned long mmap_min_addr;
extern unsigned long dac_mmap_min_addr;
/* /*
* Values used in the task_security_ops calls * Values used in the task_security_ops calls
*/ */
...@@ -116,6 +121,21 @@ struct request_sock; ...@@ -116,6 +121,21 @@ struct request_sock;
#define LSM_UNSAFE_PTRACE 2 #define LSM_UNSAFE_PTRACE 2
#define LSM_UNSAFE_PTRACE_CAP 4 #define LSM_UNSAFE_PTRACE_CAP 4
/*
* If a hint addr is less than mmap_min_addr change hint to be as
* low as possible but still greater than mmap_min_addr
*/
static inline unsigned long round_hint_to_min(unsigned long hint)
{
hint &= PAGE_MASK;
if (((void *)hint != NULL) &&
(hint < mmap_min_addr))
return PAGE_ALIGN(mmap_min_addr);
return hint;
}
extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
struct security_mnt_opts { struct security_mnt_opts {
...@@ -2197,9 +2217,7 @@ static inline int security_file_mmap(struct file *file, unsigned long reqprot, ...@@ -2197,9 +2217,7 @@ static inline int security_file_mmap(struct file *file, unsigned long reqprot,
unsigned long addr, unsigned long addr,
unsigned long addr_only) unsigned long addr_only)
{ {
if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) return cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
return -EACCES;
return 0;
} }
static inline int security_file_mprotect(struct vm_area_struct *vma, static inline int security_file_mprotect(struct vm_area_struct *vma,
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/security.h>
#include <linux/slow-work.h> #include <linux/slow-work.h>
#include <linux/perf_counter.h> #include <linux/perf_counter.h>
...@@ -1306,10 +1307,10 @@ static struct ctl_table vm_table[] = { ...@@ -1306,10 +1307,10 @@ static struct ctl_table vm_table[] = {
{ {
.ctl_name = CTL_UNNUMBERED, .ctl_name = CTL_UNNUMBERED,
.procname = "mmap_min_addr", .procname = "mmap_min_addr",
.data = &mmap_min_addr, .data = &dac_mmap_min_addr,
.maxlen = sizeof(unsigned long), .maxlen = sizeof(unsigned long),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_doulongvec_minmax, .proc_handler = &mmap_min_addr_handler,
}, },
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
{ {
......
...@@ -225,9 +225,9 @@ config DEFAULT_MMAP_MIN_ADDR ...@@ -225,9 +225,9 @@ config DEFAULT_MMAP_MIN_ADDR
For most ia64, ppc64 and x86 users with lots of address space For most ia64, ppc64 and x86 users with lots of address space
a value of 65536 is reasonable and should cause no problems. a value of 65536 is reasonable and should cause no problems.
On arm and other archs it should not be higher than 32768. On arm and other archs it should not be higher than 32768.
Programs which use vm86 functionality would either need additional Programs which use vm86 functionality or have some need to map
permissions from either the LSM or the capabilities module or have this low address space will need CAP_SYS_RAWIO or disable this
this protection disabled. protection by setting the value to 0.
This value can be changed after boot using the This value can be changed after boot using the
/proc/sys/vm/mmap_min_addr tunable. /proc/sys/vm/mmap_min_addr tunable.
......
...@@ -88,9 +88,6 @@ int sysctl_overcommit_ratio = 50; /* default is 50% */ ...@@ -88,9 +88,6 @@ int sysctl_overcommit_ratio = 50; /* default is 50% */
int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
struct percpu_counter vm_committed_as; struct percpu_counter vm_committed_as;
/* amount of vm to protect from userspace access */
unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
/* /*
* Check that a process has enough memory to allocate a new virtual * Check that a process has enough memory to allocate a new virtual
* mapping. 0 means there is enough memory for the allocation to * mapping. 0 means there is enough memory for the allocation to
......
...@@ -69,9 +69,6 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; ...@@ -69,9 +69,6 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS; int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS;
int heap_stack_gap = 0; int heap_stack_gap = 0;
/* amount of vm to protect from userspace access */
unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
atomic_long_t mmap_pages_allocated; atomic_long_t mmap_pages_allocated;
EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(mem_map);
......
...@@ -113,6 +113,22 @@ config SECURITY_ROOTPLUG ...@@ -113,6 +113,22 @@ config SECURITY_ROOTPLUG
If you are unsure how to answer this question, answer N. If you are unsure how to answer this question, answer N.
config LSM_MMAP_MIN_ADDR
int "Low address space for LSM to from user allocation"
depends on SECURITY && SECURITY_SELINUX
default 65535
help
This is the portion of low virtual memory which should be protected
from userspace allocation. Keeping a user from writing to low pages
can help reduce the impact of kernel NULL pointer bugs.
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 or have some need to map
this low address space will need the permission specific to the
systems running LSM.
source security/selinux/Kconfig source security/selinux/Kconfig
source security/smack/Kconfig source security/smack/Kconfig
source security/tomoyo/Kconfig source security/tomoyo/Kconfig
......
...@@ -8,7 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack ...@@ -8,7 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK) += smack
subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
# always enable default capabilities # always enable default capabilities
obj-y += commoncap.o obj-y += commoncap.o min_addr.o
# Object file lists # Object file lists
obj-$(CONFIG_SECURITY) += security.o capability.o obj-$(CONFIG_SECURITY) += security.o capability.o
......
...@@ -330,15 +330,6 @@ static int cap_file_ioctl(struct file *file, unsigned int command, ...@@ -330,15 +330,6 @@ static int cap_file_ioctl(struct file *file, unsigned int command,
return 0; return 0;
} }
static int cap_file_mmap(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags,
unsigned long addr, unsigned long addr_only)
{
if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
return -EACCES;
return 0;
}
static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot) unsigned long prot)
{ {
......
...@@ -984,3 +984,33 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) ...@@ -984,3 +984,33 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
cap_sys_admin = 1; cap_sys_admin = 1;
return __vm_enough_memory(mm, pages, cap_sys_admin); return __vm_enough_memory(mm, pages, cap_sys_admin);
} }
/*
* cap_file_mmap - check if able to map given addr
* @file: unused
* @reqprot: unused
* @prot: unused
* @flags: unused
* @addr: address attempting to be mapped
* @addr_only: unused
*
* If the process is attempting to map memory below mmap_min_addr they need
* CAP_SYS_RAWIO. The other parameters to this function are unused by the
* capability security module. Returns 0 if this mapping should be allowed
* -EPERM if not.
*/
int cap_file_mmap(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags,
unsigned long addr, unsigned long addr_only)
{
int ret = 0;
if (addr < dac_mmap_min_addr) {
ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO,
SECURITY_CAP_AUDIT);
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
if (ret == 0)
current->flags |= PF_SUPERPRIV;
}
return ret;
}
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/security.h>
#include <linux/sysctl.h>
/* amount of vm to protect from userspace access by both DAC and the LSM*/
unsigned long mmap_min_addr;
/* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
/* amount of vm to protect from userspace using the LSM = CONFIG_LSM_MMAP_MIN_ADDR */
/*
* Update mmap_min_addr = max(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR)
*/
static void update_mmap_min_addr(void)
{
#ifdef CONFIG_LSM_MMAP_MIN_ADDR
if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR)
mmap_min_addr = dac_mmap_min_addr;
else
mmap_min_addr = CONFIG_LSM_MMAP_MIN_ADDR;
#else
mmap_min_addr = dac_mmap_min_addr;
#endif
}
/*
* sysctl handler which just sets dac_mmap_min_addr = the new value and then
* calls update_mmap_min_addr() so non MAP_FIXED hints get rounded properly
*/
int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int ret;
ret = proc_doulongvec_minmax(table, write, filp, buffer, lenp, ppos);
update_mmap_min_addr();
return ret;
}
int __init init_mmap_min_addr(void)
{
update_mmap_min_addr();
return 0;
}
pure_initcall(init_mmap_min_addr);
...@@ -3030,9 +3030,21 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot, ...@@ -3030,9 +3030,21 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
int rc = 0; int rc = 0;
u32 sid = current_sid(); u32 sid = current_sid();
if (addr < mmap_min_addr) /*
* notice that we are intentionally putting the SELinux check before
* the secondary cap_file_mmap check. This is such a likely attempt
* at bad behaviour/exploit that we always want to get the AVC, even
* if DAC would have also denied the operation.
*/
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
MEMPROTECT__MMAP_ZERO, NULL); MEMPROTECT__MMAP_ZERO, NULL);
if (rc)
return rc;
}
/* do DAC check on address space usage */
rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
if (rc || addr_only) if (rc || addr_only)
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment