Skip to content

Commit

Permalink
audit: collect audit task parameters
Browse files Browse the repository at this point in the history
The audit-related parameters in struct task_struct should ideally be
collected together and accessed through a standard audit API and the audit
structures made opaque to other kernel subsystems.

Collect the existing loginuid, sessionid and audit_context together in a
new opaque struct audit_task_info called "audit" in struct task_struct.

Use kmem_cache to manage this pool of memory.
Un-inline audit_free() to be able to always recover that memory.

Please see the upstream github issues
linux-audit/audit-kernel#81
linux-audit/audit-kernel#90

Signed-off-by: Richard Guy Briggs <[email protected]>
  • Loading branch information
rgbriggs authored and intel-lab-lkp committed Jan 12, 2021
1 parent 09b5b5f commit 4cedf1c
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 66 deletions.
8 changes: 4 additions & 4 deletions fs/io-wq.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,8 +499,8 @@ static void io_impersonate_work(struct io_worker *worker,
current->signal->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
io_wq_switch_blkcg(worker, work);
#ifdef CONFIG_AUDIT
current->loginuid = work->identity->loginuid;
current->sessionid = work->identity->sessionid;
audit_set_loginuid_iouring(work->identity->loginuid);
audit_set_sessionid_iouring(work->identity->sessionid);
#endif
}

Expand All @@ -515,8 +515,8 @@ static void io_assign_current_work(struct io_worker *worker,
}

#ifdef CONFIG_AUDIT
current->loginuid = KUIDT_INIT(AUDIT_UID_UNSET);
current->sessionid = AUDIT_SID_UNSET;
audit_set_loginuid_iouring(KUIDT_INIT(AUDIT_UID_UNSET));
audit_set_sessionid_iouring(AUDIT_SID_UNSET);
#endif

spin_lock_irq(&worker->lock);
Expand Down
16 changes: 8 additions & 8 deletions fs/io_uring.c
Original file line number Diff line number Diff line change
Expand Up @@ -1216,8 +1216,8 @@ static void io_init_identity(struct io_identity *id)
id->fs = current->fs;
id->fsize = rlimit(RLIMIT_FSIZE);
#ifdef CONFIG_AUDIT
id->loginuid = current->loginuid;
id->sessionid = current->sessionid;
id->loginuid = audit_get_loginuid(current);
id->sessionid = audit_get_sessionid(current);
#endif
refcount_set(&id->count, 1);
}
Expand Down Expand Up @@ -1473,8 +1473,8 @@ static bool io_grab_identity(struct io_kiocb *req)
req->work.flags |= IO_WQ_WORK_CREDS;
}
#ifdef CONFIG_AUDIT
if (!uid_eq(current->loginuid, id->loginuid) ||
current->sessionid != id->sessionid)
if (!uid_eq(audit_get_loginuid(current), id->loginuid) ||
audit_get_sessionid(current) != id->sessionid)
return false;
#endif
if (!(req->work.flags & IO_WQ_WORK_FS) &&
Expand Down Expand Up @@ -7016,8 +7016,8 @@ static int io_sq_thread(void *data)
}
io_sq_thread_associate_blkcg(ctx, &cur_css);
#ifdef CONFIG_AUDIT
current->loginuid = ctx->loginuid;
current->sessionid = ctx->sessionid;
audit_set_loginuid_iouring(ctx->loginuid);
audit_set_sessionid_iouring(ctx->sessionid);
#endif

ret = __io_sq_thread(ctx, cap_entries);
Expand Down Expand Up @@ -9528,8 +9528,8 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p,
ctx->user = user;
ctx->creds = get_current_cred();
#ifdef CONFIG_AUDIT
ctx->loginuid = current->loginuid;
ctx->sessionid = current->sessionid;
ctx->loginuid = audit_get_loginuid(current);
ctx->sessionid = audit_get_sessionid(current);
#endif
ctx->sqo_task = get_task_struct(current);

Expand Down
49 changes: 17 additions & 32 deletions include/linux/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ struct filename;
#ifdef CONFIG_AUDIT
/* These are defined in audit.c */
/* Public API */
extern int audit_alloc(struct task_struct *task);
extern void audit_free(struct task_struct *task);
extern void __init audit_task_init(void);
extern __printf(4, 5)
void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
const char *fmt, ...);
Expand Down Expand Up @@ -194,22 +197,26 @@ extern int audit_rule_change(int type, int seq, void *data, size_t datasz);
extern int audit_list_rules_send(struct sk_buff *request_skb, int seq);

extern int audit_set_loginuid(kuid_t loginuid);
extern void audit_set_loginuid_iouring(kuid_t loginuid);

static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
{
return tsk->loginuid;
}
extern kuid_t audit_get_loginuid(struct task_struct *tsk);

static inline unsigned int audit_get_sessionid(struct task_struct *tsk)
{
return tsk->sessionid;
}
extern unsigned int audit_get_sessionid(struct task_struct *tsk);
extern void audit_set_sessionid_iouring(unsigned int sessionid);

extern u32 audit_enabled;

extern int audit_signal_info(int sig, struct task_struct *t);

#else /* CONFIG_AUDIT */
static inline int audit_alloc(struct task_struct *task)
{
return 0;
}
static inline void audit_free(struct task_struct *task)
{ }
static inline void __init audit_task_init(void)
{ }
static inline __printf(4, 5)
void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
const char *fmt, ...)
Expand Down Expand Up @@ -285,8 +292,6 @@ static inline int audit_signal_info(int sig, struct task_struct *t)

/* These are defined in auditsc.c */
/* Public API */
extern int audit_alloc(struct task_struct *task);
extern void __audit_free(struct task_struct *task);
extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
extern void __audit_syscall_exit(int ret_success, long ret_value);
Expand All @@ -303,26 +308,14 @@ extern void audit_seccomp_actions_logged(const char *names,
const char *old_names, int res);
extern void __audit_ptrace(struct task_struct *t);

static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
{
task->audit_context = ctx;
}

static inline struct audit_context *audit_context(void)
{
return current->audit_context;
}
extern struct audit_context *audit_context(void);

static inline bool audit_dummy_context(void)
{
void *p = audit_context();
return !p || *(int *)p;
}
static inline void audit_free(struct task_struct *task)
{
if (unlikely(task->audit_context))
__audit_free(task);
}

static inline void audit_syscall_entry(int major, unsigned long a0,
unsigned long a1, unsigned long a2,
unsigned long a3)
Expand Down Expand Up @@ -550,12 +543,6 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
extern int audit_n_rules;
extern int audit_signals;
#else /* CONFIG_AUDITSYSCALL */
static inline int audit_alloc(struct task_struct *task)
{
return 0;
}
static inline void audit_free(struct task_struct *task)
{ }
static inline void audit_syscall_entry(int major, unsigned long a0,
unsigned long a1, unsigned long a2,
unsigned long a3)
Expand All @@ -566,8 +553,6 @@ static inline bool audit_dummy_context(void)
{
return true;
}
static inline void audit_set_context(struct task_struct *task, struct audit_context *ctx)
{ }
static inline struct audit_context *audit_context(void)
{
return NULL;
Expand Down
7 changes: 1 addition & 6 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
#include <asm/kmap_size.h>

/* task_struct member predeclarations (sorted alphabetically): */
struct audit_context;
struct backing_dev_info;
struct bio_list;
struct blk_plug;
Expand Down Expand Up @@ -994,11 +993,7 @@ struct task_struct {
struct callback_head *task_works;

#ifdef CONFIG_AUDIT
#ifdef CONFIG_AUDITSYSCALL
struct audit_context *audit_context;
#endif
kuid_t loginuid;
unsigned int sessionid;
void *audit;
#endif
struct seccomp seccomp;
struct syscall_user_dispatch syscall_dispatch;
Expand Down
3 changes: 1 addition & 2 deletions init/init_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ struct task_struct init_task
.thread_group = LIST_HEAD_INIT(init_task.thread_group),
.thread_node = LIST_HEAD_INIT(init_signals.thread_head),
#ifdef CONFIG_AUDIT
.loginuid = INVALID_UID,
.sessionid = AUDIT_SID_UNSET,
.audit = NULL,
#endif
#ifdef CONFIG_PERF_EVENTS
.perf_event_mutex = __MUTEX_INITIALIZER(init_task.perf_event_mutex),
Expand Down
2 changes: 2 additions & 0 deletions init/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
#include <linux/mem_encrypt.h>
#include <linux/kcsan.h>
#include <linux/init_syscalls.h>
#include <linux/audit.h>

#include <asm/io.h>
#include <asm/bugs.h>
Expand Down Expand Up @@ -1046,6 +1047,7 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
nsfs_init();
cpuset_init();
cgroup_init();
audit_task_init();
taskstats_init_early();
delayacct_init();

Expand Down
154 changes: 152 additions & 2 deletions kernel/audit.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,148 @@ struct audit_reply {
struct sk_buff *skb;
};

struct audit_task_info {
kuid_t loginuid;
unsigned int sessionid;
#ifdef CONFIG_AUDITSYSCALL
struct audit_context *ctx;
#endif
};

static struct kmem_cache *audit_task_cache;

void __init audit_task_init(void)
{
audit_task_cache = kmem_cache_create("audit_task",
sizeof(struct audit_task_info),
0, SLAB_PANIC, NULL);
}

inline kuid_t audit_get_loginuid(struct task_struct *tsk)
{
struct audit_task_info *info = tsk->audit;

if (!info)
return INVALID_UID;
return info->loginuid;
}

inline void audit_set_loginuid_iouring(kuid_t loginuid)
{
struct audit_task_info *info = current->audit;

if (!info)
return;
info->loginuid = loginuid;
}

inline unsigned int audit_get_sessionid(struct task_struct *tsk)
{
struct audit_task_info *info = tsk->audit;

if (!info)
return AUDIT_SID_UNSET;
return info->sessionid;
}

inline void audit_set_sessionid_iouring(unsigned int sessionid)
{
struct audit_task_info *info = current->audit;

if (!info)
return;
info->sessionid = sessionid;
}

inline struct audit_context *_audit_context(struct task_struct *tsk)
{
struct audit_task_info *info = tsk->audit;

if (!info)
return NULL;
return info->ctx;
}

struct audit_context *audit_context(void)
{
return _audit_context(current);
}
EXPORT_SYMBOL(audit_context);

static void audit_alloc_task(struct task_struct *tsk)
{
struct audit_task_info *info = tsk->audit;

if (info && !IS_ERR(info))
return;
info = kmem_cache_alloc(audit_task_cache, GFP_KERNEL);
if (!info) {
tsk->audit = ERR_PTR(-ENOMEM);
return;
}
info->loginuid = audit_get_loginuid(current);
info->sessionid = audit_get_sessionid(current);
tsk->audit = info;
}

void audit_set_context(struct task_struct *tsk, struct audit_context *ctx)
{
struct audit_task_info *info;

audit_alloc_task(tsk);
info = tsk->audit;
if (!IS_ERR(info))
info->ctx = ctx;
else
tsk->audit = NULL;
}

/**
* audit_alloc - allocate an audit info block for a task
* @tsk: task
*
* Call audit_alloc_syscall to filter on the task information and
* allocate a per-task audit context if necessary. This is called from
* copy_process, so no lock is needed.
*/
int audit_alloc(struct task_struct *tsk)
{
int ret = 0;

tsk->audit = NULL;
audit_alloc_task(tsk);
if (IS_ERR(tsk->audit)) {
ret = PTR_ERR(tsk->audit);
tsk->audit = NULL;
goto out;
}
ret = audit_alloc_syscall(tsk);
if (ret) {
kmem_cache_free(audit_task_cache, tsk->audit);
tsk->audit = NULL;
}
out:
return ret;
}

/**
* audit_free - free per-task audit info
* @tsk: task whose audit info block to free
*
* Called from copy_process and do_exit
*/
void audit_free(struct task_struct *tsk)
{
struct audit_task_info *info = tsk->audit;

audit_free_syscall(tsk);
/* Freeing the audit_task_info struct must be performed after
* audit_log_exit() due to need for loginuid and sessionid.
*/
tsk->audit = NULL;
kmem_cache_free(audit_task_cache, info);
}

/**
* auditd_test_task - Check to see if a given task is an audit daemon
* @task: the task to check
Expand Down Expand Up @@ -2310,13 +2452,20 @@ int audit_set_loginuid(kuid_t loginuid)
unsigned int oldsessionid, sessionid = AUDIT_SID_UNSET;
kuid_t oldloginuid;
int rc;
struct audit_task_info *info;

oldloginuid = audit_get_loginuid(current);
oldsessionid = audit_get_sessionid(current);

rc = audit_set_loginuid_perm(loginuid);
if (rc)
goto out;
audit_alloc_task(current);
if (IS_ERR(current->audit)) {
rc = PTR_ERR(current->audit);
current->audit = NULL;
goto out;
}

/* are we setting or clearing? */
if (uid_valid(loginuid)) {
Expand All @@ -2325,8 +2474,9 @@ int audit_set_loginuid(kuid_t loginuid)
sessionid = (unsigned int)atomic_inc_return(&session_id);
}

current->sessionid = sessionid;
current->loginuid = loginuid;
info = current->audit;
info->sessionid = sessionid;
info->loginuid = loginuid;
out:
audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc);
return rc;
Expand Down
Loading

0 comments on commit 4cedf1c

Please sign in to comment.