Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad658cec authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6:
  VM/Security: add security hook to do_brk
  Security: round mmap hint address above mmap_min_addr
  security: protect from stack expantion into low vm addresses
  Security: allow capable check to permit mmap or low vm space
  SELinux: detect dead booleans
  SELinux: do not clear f_op when removing entries
parents 2a1292b3 5a211a5d
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/prio_tree.h>
#include <linux/debug_locks.h>
#include <linux/mm_types.h>
#include <linux/security.h>

struct mempolicy;
struct anon_vma;
@@ -512,6 +513,21 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
	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)
{
#ifdef CONFIG_SECURITY
	hint &= PAGE_MASK;
	if (((void *)hint != NULL) &&
	    (hint < mmap_min_addr))
		return PAGE_ALIGN(mmap_min_addr);
#endif
	return hint;
}

/*
 * Some inline functions in vmstat.h depend on page_zone()
 */
+9 −2
Original line number Diff line number Diff line
@@ -912,6 +912,9 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
	if (!len)
		return -EINVAL;

	if (!(flags & MAP_FIXED))
		addr = round_hint_to_min(addr);

	error = arch_mmap_check(addr, len, flags);
	if (error)
		return error;
@@ -1615,6 +1618,12 @@ static inline int expand_downwards(struct vm_area_struct *vma,
	 */
	if (unlikely(anon_vma_prepare(vma)))
		return -ENOMEM;

	address &= PAGE_MASK;
	error = security_file_mmap(0, 0, 0, 0, address, 1);
	if (error)
		return error;

	anon_vma_lock(vma);

	/*
@@ -1622,8 +1631,6 @@ static inline int expand_downwards(struct vm_area_struct *vma,
	 * is required to hold the mmap_sem in read mode.  We need the
	 * anon_vma lock to serialize against concurrent expand_stacks.
	 */
	address &= PAGE_MASK;
	error = 0;

	/* Somebody else might have raced and expanded it already */
	if (address < vma->vm_start) {
+3 −0
Original line number Diff line number Diff line
@@ -829,6 +829,9 @@ unsigned long do_mmap_pgoff(struct file *file,
	void *result;
	int ret;

	if (!(flags & MAP_FIXED))
		addr = round_hint_to_min(addr);

	/* decide whether we should attempt the mapping, and if so what sort of
	 * mapping */
	ret = validate_mmap_request(file, addr, len, prot, flags, pgoff,
+1 −1
Original line number Diff line number Diff line
@@ -426,7 +426,7 @@ static int dummy_file_mmap (struct file *file, unsigned long reqprot,
			    unsigned long addr,
			    unsigned long addr_only)
{
	if (addr < mmap_min_addr)
	if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
		return -EACCES;
	return 0;
}
+28 −37
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ static DEFINE_MUTEX(sel_mutex);
/* global data for booleans */
static struct dentry *bool_dir = NULL;
static int bool_num = 0;
static char **bool_pending_names;
static int *bool_pending_values = NULL;

/* global data for classes */
@@ -832,15 +833,16 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
	ssize_t length;
	ssize_t ret;
	int cur_enforcing;
	struct inode *inode;
	struct inode *inode = filep->f_path.dentry->d_inode;
	unsigned index = inode->i_ino & SEL_INO_MASK;
	const char *name = filep->f_path.dentry->d_name.name;

	mutex_lock(&sel_mutex);

	ret = -EFAULT;

	/* check to see if this file has been deleted */
	if (!filep->f_op)
	if (index >= bool_num || strcmp(name, bool_pending_names[index])) {
		ret = -EINVAL;
		goto out;
	}

	if (count > PAGE_SIZE) {
		ret = -EINVAL;
@@ -851,15 +853,13 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
		goto out;
	}

	inode = filep->f_path.dentry->d_inode;
	cur_enforcing = security_get_bool_value(inode->i_ino&SEL_INO_MASK);
	cur_enforcing = security_get_bool_value(index);
	if (cur_enforcing < 0) {
		ret = cur_enforcing;
		goto out;
	}

	length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
			  bool_pending_values[inode->i_ino&SEL_INO_MASK]);
			  bool_pending_values[index]);
	ret = simple_read_from_buffer(buf, count, ppos, page, length);
out:
	mutex_unlock(&sel_mutex);
@@ -872,9 +872,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
			      size_t count, loff_t *ppos)
{
	char *page = NULL;
	ssize_t length = -EFAULT;
	ssize_t length;
	int new_value;
	struct inode *inode;
	struct inode *inode = filep->f_path.dentry->d_inode;
	unsigned index = inode->i_ino & SEL_INO_MASK;
	const char *name = filep->f_path.dentry->d_name.name;

	mutex_lock(&sel_mutex);

@@ -882,16 +884,19 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
	if (length)
		goto out;

	/* check to see if this file has been deleted */
	if (!filep->f_op)
	if (index >= bool_num || strcmp(name, bool_pending_names[index])) {
		length = -EINVAL;
		goto out;
	}

	if (count >= PAGE_SIZE) {
		length = -ENOMEM;
		goto out;
	}

	if (*ppos != 0) {
		/* No partial writes. */
		length = -EINVAL;
		goto out;
	}
	page = (char*)get_zeroed_page(GFP_KERNEL);
@@ -900,6 +905,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
		goto out;
	}

	length = -EFAULT;
	if (copy_from_user(page, buf, count))
		goto out;

@@ -910,8 +916,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
	if (new_value)
		new_value = 1;

	inode = filep->f_path.dentry->d_inode;
	bool_pending_values[inode->i_ino&SEL_INO_MASK] = new_value;
	bool_pending_values[index] = new_value;
	length = count;

out:
@@ -931,7 +936,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
				      size_t count, loff_t *ppos)
{
	char *page = NULL;
	ssize_t length = -EFAULT;
	ssize_t length;
	int new_value;

	mutex_lock(&sel_mutex);
@@ -940,10 +945,6 @@ static ssize_t sel_commit_bools_write(struct file *filep,
	if (length)
		goto out;

	/* check to see if this file has been deleted */
	if (!filep->f_op)
		goto out;

	if (count >= PAGE_SIZE) {
		length = -ENOMEM;
		goto out;
@@ -958,6 +959,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
		goto out;
	}

	length = -EFAULT;
	if (copy_from_user(page, buf, count))
		goto out;

@@ -982,11 +984,9 @@ static const struct file_operations sel_commit_bools_ops = {
	.write          = sel_commit_bools_write,
};

/* partial revoke() from fs/proc/generic.c proc_kill_inodes */
static void sel_remove_entries(struct dentry *de)
{
	struct list_head *p, *node;
	struct super_block *sb = de->d_sb;
	struct list_head *node;

	spin_lock(&dcache_lock);
	node = de->d_subdirs.next;
@@ -1006,18 +1006,6 @@ static void sel_remove_entries(struct dentry *de)
	}

	spin_unlock(&dcache_lock);

	file_list_lock();
	list_for_each(p, &sb->s_files) {
		struct file * filp = list_entry(p, struct file, f_u.fu_list);
		struct dentry * dentry = filp->f_path.dentry;

		if (dentry->d_parent != de) {
			continue;
		}
		filp->f_op = NULL;
	}
	file_list_unlock();
}

#define BOOL_DIR_NAME "booleans"
@@ -1036,7 +1024,9 @@ static int sel_make_bools(void)
	u32 sid;

	/* remove any existing files */
	kfree(bool_pending_names);
	kfree(bool_pending_values);
	bool_pending_names = NULL;
	bool_pending_values = NULL;

	sel_remove_entries(dir);
@@ -1078,16 +1068,17 @@ static int sel_make_bools(void)
		d_add(dentry, inode);
	}
	bool_num = num;
	bool_pending_names = names;
	bool_pending_values = values;
out:
	free_page((unsigned long)page);
	return ret;
err:
	if (names) {
		for (i = 0; i < num; i++)
			kfree(names[i]);
		kfree(names);
	}
	return ret;
err:
	kfree(values);
	sel_remove_entries(dir);
	ret = -ENOMEM;