Security/SELinux: seperate lsm specific mmap_min_addr
Currently SELinux enforcement of controls on the ability to map low memory is determined by the mmap_min_addr tunable. This patch causes SELinux to ignore the tunable and instead use a seperate Kconfig option specific to how much space the LSM should protect. The tunable will now only control the need for CAP_SYS_RAWIO and SELinux permissions will always protect the amount of low memory designated by CONFIG_LSM_MMAP_MIN_ADDR. This allows users who need to disable the mmap_min_addr controls (usual reason being they run WINE as a non-root user) to do so and still have SELinux controls preventing confined domains (like a web server) from being able to map some area of low memory. Signed-off-by: Eric Paris <eparis@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
84336d1a77
commit
a2551df7ec
|
@ -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,
|
||||||
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 @@
|
||||||
#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>
|
||||||
|
@ -95,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
|
||||||
*/
|
*/
|
||||||
|
@ -147,6 +149,21 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||||
opts->num_mnt_opts = 0;
|
opts->num_mnt_opts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
/**
|
/**
|
||||||
* struct security_operations - main security structure
|
* struct security_operations - main security structure
|
||||||
*
|
*
|
||||||
|
|
|
@ -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[] = {
|
||||||
{
|
{
|
||||||
.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
|
||||||
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% */
|
||||||
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;
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
|
|
|
@ -1005,7 +1005,7 @@ int cap_file_mmap(struct file *file, unsigned long reqprot,
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (addr < mmap_min_addr) {
|
if (addr < dac_mmap_min_addr) {
|
||||||
ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO,
|
ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO,
|
||||||
SECURITY_CAP_AUDIT);
|
SECURITY_CAP_AUDIT);
|
||||||
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
|
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
#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);
|
|
@ -3040,7 +3040,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
|
||||||
* at bad behaviour/exploit that we always want to get the AVC, even
|
* at bad behaviour/exploit that we always want to get the AVC, even
|
||||||
* if DAC would have also denied the operation.
|
* if DAC would have also denied the operation.
|
||||||
*/
|
*/
|
||||||
if (addr < mmap_min_addr) {
|
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)
|
if (rc)
|
||||||
|
|
Loading…
Reference in New Issue