Skip to content

Commit

Permalink
S.A.R.A.: /proc/*/mem write limitation
Browse files Browse the repository at this point in the history
Prevent a task from opening, in "write" mode, any /proc/*/mem
file that operates on the task's mm.
A process could use it to overwrite read-only memory, bypassing
S.A.R.A. restrictions.

Signed-off-by: Salvatore Mesoraca <[email protected]>
  • Loading branch information
smeso committed Jun 15, 2018
1 parent a1db0d0 commit 61ce88e
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 2 deletions.
8 changes: 8 additions & 0 deletions security/sara/include/sara_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef __SARA_DATA_H
#define __SARA_DATA_H

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/spinlock.h>

Expand All @@ -36,6 +37,10 @@ struct sara_shm_data {
spinlock_t lock;
};

struct sara_inode_data {
struct task_struct *task;
};

#define get_sara_data_leftvalue(X) ((X)->security_sara)
#define get_sara_data(X) ((struct sara_data *) (X)->security_sara)
#define get_current_sara_data() get_sara_data(current_cred())
Expand Down Expand Up @@ -65,6 +70,9 @@ struct sara_shm_data {
#define lock_sara_shm(X) (spin_lock(&get_sara_shm_data((X))->lock))
#define unlock_sara_shm(X) (spin_unlock(&get_sara_shm_data((X))->lock))

#define get_sara_inode_data(X) ((struct sara_inode_data *) (X)->security_sara)
#define get_sara_inode_task(X) (get_sara_inode_data((X))->task)

#endif

#endif /* __SARA_H */
41 changes: 39 additions & 2 deletions security/sara/sara_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
#include <linux/cred.h>
#include <linux/lsm_hooks.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>

static struct kmem_cache *sara_inode_cache;

static int sara_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
struct sara_data *d;
Expand Down Expand Up @@ -75,20 +78,54 @@ static void sara_shm_free_security(struct kern_ipc_perm *shp)
kfree(get_sara_data_leftvalue(shp));
}

static int sara_inode_alloc_security(struct inode *inode)
{
struct sara_inode_data *d;

d = kmem_cache_zalloc(sara_inode_cache, GFP_NOFS);
if (d == NULL)
return -ENOMEM;
get_sara_data_leftvalue(inode) = d;
return 0;
}

static void sara_inode_free_security(struct inode *inode)
{
kmem_cache_free(sara_inode_cache, get_sara_data_leftvalue(inode));
}

static void sara_task_to_inode(struct task_struct *t, struct inode *i)
{
get_sara_inode_task(i) = t;
}

static struct security_hook_list data_hooks[] __ro_after_init = {
LSM_HOOK_INIT(cred_alloc_blank, sara_cred_alloc_blank),
LSM_HOOK_INIT(cred_free, sara_cred_free),
LSM_HOOK_INIT(cred_prepare, sara_cred_prepare),
LSM_HOOK_INIT(cred_transfer, sara_cred_transfer),
LSM_HOOK_INIT(shm_alloc_security, sara_shm_alloc_security),
LSM_HOOK_INIT(shm_free_security, sara_shm_free_security),
LSM_HOOK_INIT(inode_alloc_security, sara_inode_alloc_security),
LSM_HOOK_INIT(inode_free_security, sara_inode_free_security),
LSM_HOOK_INIT(task_to_inode, sara_task_to_inode),
};

int __init sara_data_init(void)
{
int ret;

sara_inode_cache = KMEM_CACHE(sara_inode_data, 0);
if (!sara_inode_cache)
return -ENOMEM;
ret = sara_cred_alloc_blank((struct cred *) current->real_cred,
GFP_KERNEL);
if (ret) {
kmem_cache_destroy(sara_inode_cache);
return ret;
}
security_add_hooks(data_hooks, ARRAY_SIZE(data_hooks), "sara");
return sara_cred_alloc_blank((struct cred *) current->real_cred,
GFP_KERNEL);
return ret;
}

#else /* CONFIG_SECURITY_SARA_WXPROT */
Expand Down
41 changes: 41 additions & 0 deletions security/sara/wxprot.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/sched/mm.h>
#include <linux/sched/task.h>
#include <linux/spinlock.h>
#include <linux/xattr.h>

Expand Down Expand Up @@ -631,6 +634,43 @@ static int sara_file_mprotect(struct vm_area_struct *vma,
return 0;
}

static int sara_file_open(struct file *file, const struct cred *cred)
{
struct task_struct *t;
struct mm_struct *mm;
u16 sara_wxp_flags = get_current_sara_wxp_flags();

/*
* Prevent write access to /proc/.../mem
* if it operates on the mm_struct of the
* current process: it could be used to
* bypass W^X.
*/

if (!sara_enabled ||
!wxprot_enabled ||
!(sara_wxp_flags & SARA_WXP_WXORX) ||
!(file->f_mode & FMODE_WRITE))
return 0;

t = get_sara_inode_task(file_inode(file));
if (unlikely(t != NULL &&
strcmp(file->f_path.dentry->d_name.name,
"mem") == 0)) {
get_task_struct(t);
mm = get_task_mm(t);
put_task_struct(t);
if (unlikely(mm == current->mm))
sara_warn_or_goto(error,
"write access to /proc/*/mem");
mmput(mm);
}
return 0;
error:
mmput(mm);
return -EACCES;
}

#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
static int sara_pagefault_handler(struct pt_regs *regs,
unsigned long error_code,
Expand Down Expand Up @@ -794,6 +834,7 @@ static struct security_hook_list wxprot_hooks[] __ro_after_init = {
LSM_HOOK_INIT(check_vmflags, sara_check_vmflags),
LSM_HOOK_INIT(shm_shmat, sara_shm_shmat),
LSM_HOOK_INIT(file_mprotect, sara_file_mprotect),
LSM_HOOK_INIT(file_open, sara_file_open),
#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP
LSM_HOOK_INIT(pagefault_handler, sara_pagefault_handler),
#endif
Expand Down

0 comments on commit 61ce88e

Please sign in to comment.