Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timgad lsm v1 test #384

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,7 @@ union security_list_options {
int (*file_open)(struct file *file, const struct cred *cred);

int (*task_create)(unsigned long clone_flags);
int (*task_copy)(struct task_struct *task);
void (*task_free)(struct task_struct *task);
int (*cred_alloc_blank)(struct cred *cred, gfp_t gfp);
void (*cred_free)(struct cred *cred);
Expand Down Expand Up @@ -1745,6 +1746,7 @@ struct security_hook_heads {
struct list_head file_receive;
struct list_head file_open;
struct list_head task_create;
struct list_head task_copy;
struct list_head task_free;
struct list_head cred_alloc_blank;
struct list_head cred_free;
Expand Down
6 changes: 6 additions & 0 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,
int security_file_receive(struct file *file);
int security_file_open(struct file *file, const struct cred *cred);
int security_task_create(unsigned long clone_flags);
int security_task_copy(struct task_struct *task);
void security_task_free(struct task_struct *task);
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
void security_cred_free(struct cred *cred);
Expand Down Expand Up @@ -857,6 +858,11 @@ static inline int security_task_create(unsigned long clone_flags)
return 0;
}

static inline int security_task_copy(struct task_struct *task)
{
return 0;
}

static inline void security_task_free(struct task_struct *task)
{ }

Expand Down
4 changes: 4 additions & 0 deletions include/uapi/linux/prctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,8 @@ struct prctl_mm_map {
# define PR_CAP_AMBIENT_LOWER 3
# define PR_CAP_AMBIENT_CLEAR_ALL 4

#define PR_TIMGAD_OPTS 48
# define PR_TIMGAD_SET_MOD_HARDEN 1
# define PR_TIMGAD_GET_MOD_HARDEN 2

#endif /* _LINUX_PRCTL_H */
4 changes: 4 additions & 0 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,10 @@ static __latent_entropy struct task_struct *copy_process(
if (retval)
goto bad_fork_free_pid;

retval = security_task_copy(p);
if (retval)
goto bad_fork_cancel_cgroup;

/*
* Make it visible to the rest of the system, but dont wake it up yet.
* Need tasklist lock for parent etc handling!
Expand Down
1 change: 1 addition & 0 deletions security/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ source security/tomoyo/Kconfig
source security/apparmor/Kconfig
source security/loadpin/Kconfig
source security/yama/Kconfig
source security/timgad/Kconfig

source security/integrity/Kconfig

Expand Down
6 changes: 6 additions & 0 deletions security/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,11 @@ int security_task_create(unsigned long clone_flags)
return call_int_hook(task_create, 0, clone_flags);
}

int security_task_copy(struct task_struct *task)
{
return call_int_hook(task_copy, 0, task);
}

void security_task_free(struct task_struct *task)
{
call_void_hook(task_free, task);
Expand Down Expand Up @@ -1731,6 +1736,7 @@ struct security_hook_heads security_hook_heads = {
.file_receive = LIST_HEAD_INIT(security_hook_heads.file_receive),
.file_open = LIST_HEAD_INIT(security_hook_heads.file_open),
.task_create = LIST_HEAD_INIT(security_hook_heads.task_create),
.task_copy = LIST_HEAD_INIT(security_hook_heads.task_copy),
.task_free = LIST_HEAD_INIT(security_hook_heads.task_free),
.cred_alloc_blank =
LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank),
Expand Down
10 changes: 10 additions & 0 deletions security/timgad/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
config SECURITY_TIMGAD
bool "TIMGAD support"
depends on SECURITY
default n
help
This selects TIMGAD, which applies restrictions on module auto-loading
feature. Further information can be found in
Documentation/security/timgad.txt.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing the further documentation. Also, Linus doesn't accept PRs on Github.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Propheis thx


If you are unsure how to answer this question, answer N.
3 changes: 3 additions & 0 deletions security/timgad/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
obj-$(CONFIG_SECURITY_TIMGAD) := timgad.o

timgad-y := timgad_core.o timgad_lsm.o
214 changes: 214 additions & 0 deletions security/timgad/timgad_core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/*
* Timgad Linux Security Module
*
* Author: Djalal Harouni
*
* Copyright (C) 2017 Endocode AG.
* Copyright (c) 2016 Djalal Harouni
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*/

#include <linux/ctype.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/prctl.h>
#include <linux/rhashtable.h>
#include <linux/sched.h>
#include <linux/security.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/workqueue.h>

struct timgad_task {
atomic_t usage;

struct rhash_head node;
unsigned long key;

struct task_struct *task;

int mod_harden:2;

struct work_struct clean_work;
};

static struct rhashtable timgad_tasks_table;

static inline int cmp_timgad_task(struct rhashtable_compare_arg *arg,
const void *obj)
{
const unsigned long key = *(unsigned long *)arg->key;
const struct timgad_task *ttask = obj;

return atomic_read(&ttask->usage) == 0 || ttask->key != key;
}

static const struct rhashtable_params timgad_tasks_params = {
.nelem_hint = 1024,
.head_offset = offsetof(struct timgad_task, node),
.key_offset = offsetof(struct timgad_task, key),
.key_len = sizeof(unsigned long),
.max_size = 16384,
.min_size = 256,
.obj_cmpfn = cmp_timgad_task,
.automatic_shrinking = true,
};

int timgad_tasks_init(void)
{
return rhashtable_init(&timgad_tasks_table, &timgad_tasks_params);
}

void timgad_tasks_clean(void)
{
rhashtable_destroy(&timgad_tasks_table);
}

static int get_timgad_task_new_flags(unsigned long op, unsigned long used,
unsigned long flag, int *new_flags)
{
int ret = -EINVAL;

return ret;
}

static int update_timgad_task_flags(struct timgad_task *timgad_tsk,
unsigned long op, int new_flags)
{
int ret = -EINVAL;

return ret;
}

int timgad_task_is_op_set(struct timgad_task *timgad_tsk, unsigned long op)
{
if (op == PR_TIMGAD_SET_MOD_HARDEN)
return timgad_tsk->mod_harden;

return -EINVAL;
}

int timgad_task_set_op_flag(struct timgad_task *timgad_tsk, unsigned long op,
unsigned long flag, unsigned long value)
{
int ret = -EINVAL;
int new_flag = 0;
int used = timgad_task_is_op_set(timgad_tsk, op);

ret = get_timgad_task_new_flags(op, used, flag, &new_flag);
if (ret < 0)
return ret;

/* Nothing to do if new flag did not change */
if (new_flag == used)
return 0;

return update_timgad_task_flags(timgad_tsk, op, new_flag);
}

static struct timgad_task *__lookup_timgad_task(struct task_struct *tsk)
{
return rhashtable_lookup_fast(&timgad_tasks_table, tsk,
timgad_tasks_params);
}

struct timgad_task *get_timgad_task(struct task_struct *tsk)
{
struct timgad_task *ttask;

rcu_read_lock();
ttask = __lookup_timgad_task(tsk);
if (ttask)
atomic_inc(&ttask->usage);
rcu_read_unlock();

return ttask;
}

void put_timgad_task(struct timgad_task *timgad_tsk)
{
if (timgad_tsk && atomic_dec_and_test(&timgad_tsk->usage))
schedule_work(&timgad_tsk->clean_work);
}

struct timgad_task *lookup_timgad_task(struct task_struct *tsk)
{
struct timgad_task *ttask;

rcu_read_lock();
ttask = __lookup_timgad_task(tsk);
rcu_read_unlock();

return ttask;
}

int insert_timgad_task(struct timgad_task *timgad_tsk)
{
int ret;

atomic_inc(&timgad_tsk->usage);
ret = rhashtable_lookup_insert_key(&timgad_tasks_table,
timgad_tsk->task, &timgad_tsk->node,
timgad_tasks_params);
if (ret)
atomic_dec(&timgad_tsk->usage);

return ret;
}

static void reclaim_timgad_task(struct work_struct *work)
{
struct timgad_task *ttask = container_of(work, struct timgad_task,
clean_work);

WARN_ON(atomic_read(&ttask->usage) != 0);

rhashtable_remove_fast(&timgad_tasks_table, &ttask->node,
timgad_tasks_params);

kfree(ttask);
}

struct timgad_task *init_timgad_task(struct task_struct *tsk,
unsigned long value)
{
struct timgad_task *ttask;

ttask = kzalloc(sizeof(*ttask), GFP_KERNEL | __GFP_NOWARN);
if (ttask == NULL)
return ERR_PTR(-ENOMEM);

ttask->task = tsk;
ttask->mod_harden = value;

atomic_set(&ttask->usage, 0);
INIT_WORK(&ttask->clean_work, reclaim_timgad_task);

return ttask;
}

/* On success, callers have to do put_timgad_task() */
struct timgad_task *give_me_timgad_task(struct task_struct *tsk,
unsigned long value)
{
int ret;
struct timgad_task *ttask;

ttask = init_timgad_task(tsk, value);
if (IS_ERR(ttask))
return ttask;

/* Mark it as active */
ret = insert_timgad_task(ttask);
if (ret) {
kfree(ttask);
return ERR_PTR(ret);
}

return ttask;
}
48 changes: 48 additions & 0 deletions security/timgad/timgad_core.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Timgad Linux Security Module
*
* Author: Djalal Harouni
*
* Copyright (c) 2016 Djalal Harouni
* Copyright (c) 2017 Endocode AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*/

#define TIMGAD_MOD_HARDEN 0x00000001
#define TIMGAD_MOD_HARDEN_STRICT 0x00000002

#define TIMGAD_OPTS_ALL \
((unsigned long) (TIMGAD_MOD_HARDEN | \
TIMGAD_MOD_HARDEN_STRICT))

struct timgad_task;

static inline int timgad_op_to_flag(unsigned long op,
unsigned long value,
unsigned long *rvalue)
{
return 0;
}

int timgad_task_set_op_flag(struct timgad_task *timgad_tsk,
unsigned long op, unsigned long flag,
unsigned long value);

int timgad_task_is_op_set(struct timgad_task *timgad_tsk, unsigned long op);

struct timgad_task *get_timgad_task(struct task_struct *tsk);
void put_timgad_task(struct timgad_task *timgad_tsk);
struct timgad_task *lookup_timgad_task(struct task_struct *tsk);
int insert_timgad_task(struct timgad_task *timgad_tsk);

struct timgad_task *init_timgad_task(struct task_struct *tsk,
unsigned long flag);
struct timgad_task *give_me_timgad_task(struct task_struct *tsk,
unsigned long value);

int timgad_tasks_init(void);
void timgad_tasks_clean(void);
Loading