On Fri, Mar 15, 2019 at 02:29:49PM -0400, Richard Guy Briggs wrote:
> The audit-related parameters in struct task_struct should ideally be
> collected together and accessed through a standard audit API.
> 
> Collect the existing loginuid, sessionid and audit_context together in a
> new 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 issue
> https://github.com/linux-audit/audit-kernel/issues/81
> but that issue has been closed with this patch included with
> https://github.com/linux-audit/audit-kernel/issues/90
> 
> Signed-off-by: Richard Guy Briggs <[email protected]>
> ---
>  include/linux/audit.h | 49 +++++++++++++++++++++++------------
>  include/linux/sched.h |  7 +----
>  init/init_task.c      |  3 +--
>  init/main.c           |  2 ++
>  kernel/audit.c        | 71 
> +++++++++++++++++++++++++++++++++++++++++++++++++--
>  kernel/audit.h        |  5 ++++
>  kernel/auditsc.c      | 26 ++++++++++---------
>  kernel/fork.c         |  1 -
>  8 files changed, 124 insertions(+), 40 deletions(-)
> 
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index 1e69d9fe16da..bde346e73f0c 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -86,6 +86,16 @@ struct audit_field {
>       u32                             op;
>  };
>  
> +struct audit_task_info {
> +     kuid_t                  loginuid;
> +     unsigned int            sessionid;
> +#ifdef CONFIG_AUDITSYSCALL
> +     struct audit_context    *ctx;
> +#endif
> +};
> +
> +extern struct audit_task_info init_struct_audit;
> +
>  extern int is_audit_feature_set(int which);
>  
>  extern int __init audit_register_class(int class, unsigned *list);
> @@ -122,6 +132,9 @@ struct audit_field {
>  #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, ...);
> @@ -164,16 +177,28 @@ extern void                 audit_log_key(struct 
> audit_buffer *ab,
>  
>  static inline kuid_t audit_get_loginuid(struct task_struct *tsk)
>  {
> -     return tsk->loginuid;
> +     if (!tsk->audit)
> +             return INVALID_UID;
> +     return tsk->audit->loginuid;
>  }
>  
>  static inline unsigned int audit_get_sessionid(struct task_struct *tsk)
>  {
> -     return tsk->sessionid;
> +     if (!tsk->audit)
> +             return AUDIT_SID_UNSET;
> +     return tsk->audit->sessionid;
>  }
>  
>  extern u32 audit_enabled;
>  #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, ...)
> @@ -239,8 +264,6 @@ static inline unsigned int audit_get_sessionid(struct 
> task_struct *tsk)
>  
>  /* 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);
> @@ -263,12 +286,14 @@ extern void audit_seccomp_actions_logged(const char 
> *names,
>  
>  static inline void audit_set_context(struct task_struct *task, struct 
> audit_context *ctx)
>  {
> -     task->audit_context = ctx;
> +     task->audit->ctx = ctx;
>  }
>  
>  static inline struct audit_context *audit_context(void)
>  {
> -     return current->audit_context;
> +     if (!current->audit)
> +             return NULL;
> +     return current->audit->ctx;
>  }
>  
>  static inline bool audit_dummy_context(void)
> @@ -276,11 +301,7 @@ 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)
> @@ -470,12 +491,6 @@ static inline void audit_fanotify(unsigned int response)
>  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)
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 765119df759a..6850d1e48ace 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -31,7 +31,6 @@
>  #include <linux/rseq.h>
>  
>  /* task_struct member predeclarations (sorted alphabetically): */
> -struct audit_context;
>  struct backing_dev_info;
>  struct bio_list;
>  struct blk_plug;
> @@ -886,11 +885,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;
> +     struct audit_task_info          *audit;
>  #endif
>       struct seccomp                  seccomp;
>  
> diff --git a/init/init_task.c b/init/init_task.c
> index 39c3109acc1a..f9685e1edda1 100644
> --- a/init/init_task.c
> +++ b/init/init_task.c
> @@ -122,8 +122,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          = &init_struct_audit,
>  #endif
>  #ifdef CONFIG_PERF_EVENTS
>       .perf_event_mutex = __MUTEX_INITIALIZER(init_task.perf_event_mutex),
> diff --git a/init/main.c b/init/main.c
> index e2e80ca3165a..8a1c36625d12 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -92,6 +92,7 @@
>  #include <linux/rodata_test.h>
>  #include <linux/jump_label.h>
>  #include <linux/mem_encrypt.h>
> +#include <linux/audit.h>
>  
>  #include <asm/io.h>
>  #include <asm/bugs.h>
> @@ -727,6 +728,7 @@ asmlinkage __visible void __init start_kernel(void)
>       nsfs_init();
>       cpuset_init();
>       cgroup_init();
> +     audit_task_init();
>       taskstats_init_early();
>       delayacct_init();
>  
> diff --git a/kernel/audit.c b/kernel/audit.c
> index c89ea48c70a6..67498c5690bb 100644
> --- a/kernel/audit.c
> +++ b/kernel/audit.c
> @@ -215,6 +215,73 @@ struct audit_reply {
>       struct sk_buff *skb;
>  };
>  
> +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);
> +}
> +
> +/**
> + * 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;
> +     struct audit_task_info *info;
> +
> +     info = kmem_cache_alloc(audit_task_cache, GFP_KERNEL);
> +     if (!info) {
> +             ret = -ENOMEM;
> +             goto out;
> +     }
> +     info->loginuid = audit_get_loginuid(current);
> +     info->sessionid = audit_get_sessionid(current);
> +     tsk->audit = info;
> +
> +     ret = audit_alloc_syscall(tsk);
> +     if (ret) {
> +             tsk->audit = NULL;
> +             kmem_cache_free(audit_task_cache, info);
> +     }
> +out:
> +     return ret;
> +}
> +
> +struct audit_task_info init_struct_audit = {
> +     .loginuid = INVALID_UID,
> +     .sessionid = AUDIT_SID_UNSET,
> +#ifdef CONFIG_AUDITSYSCALL
> +     .ctx = NULL,
> +#endif
> +};
> +
> +/**
> + * 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.
> +      */
> +     info = tsk->audit;
> +     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
> @@ -2266,8 +2333,8 @@ int audit_set_loginuid(kuid_t loginuid)
>                       sessionid = (unsigned 
> int)atomic_inc_return(&session_id);
>       }
>  
> -     current->sessionid = sessionid;
> -     current->loginuid = loginuid;
> +     current->audit->sessionid = sessionid;
> +     current->audit->loginuid = loginuid;
>  out:
>       audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, 
> rc);
>       return rc;
> diff --git a/kernel/audit.h b/kernel/audit.h
> index 958d5b8fc1b3..c00e2ee3c6b3 100644
> --- a/kernel/audit.h
> +++ b/kernel/audit.h
> @@ -264,6 +264,8 @@ extern void audit_log_d_path_exe(struct audit_buffer *ab,
>  extern unsigned int audit_serial(void);
>  extern int auditsc_get_stamp(struct audit_context *ctx,
>                             struct timespec64 *t, unsigned int *serial);
> +extern int audit_alloc_syscall(struct task_struct *tsk);
> +extern void audit_free_syscall(struct task_struct *tsk);
>  
>  extern void audit_put_watch(struct audit_watch *watch);
>  extern void audit_get_watch(struct audit_watch *watch);
> @@ -305,6 +307,9 @@ extern void audit_filter_inodes(struct task_struct *tsk,
>  extern struct list_head *audit_killed_trees(void);
>  #else /* CONFIG_AUDITSYSCALL */
>  #define auditsc_get_stamp(c, t, s) 0
> +#define audit_alloc_syscall(t) 0
> +#define audit_free_syscall(t) {}
> +
>  #define audit_put_watch(w) {}
>  #define audit_get_watch(w) {}
>  #define audit_to_watch(k, p, l, o) (-EINVAL)
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index d1eab1d4a930..8090eff7868d 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -885,23 +885,25 @@ static inline struct audit_context 
> *audit_alloc_context(enum audit_state state)
>       return context;
>  }
>  
> -/**
> - * audit_alloc - allocate an audit context block for a task
> +/*
> + * audit_alloc_syscall - allocate an audit context block for a task
>   * @tsk: task
>   *
>   * Filter on the task information and allocate a per-task audit context
>   * if necessary.  Doing so turns on system call auditing for the
> - * specified task.  This is called from copy_process, so no lock is
> - * needed.
> + * specified task.  This is called from copy_process via audit_alloc, so
> + * no lock is needed.
>   */
> -int audit_alloc(struct task_struct *tsk)
> +int audit_alloc_syscall(struct task_struct *tsk)
>  {
>       struct audit_context *context;
>       enum audit_state     state;
>       char *key = NULL;
>  
> -     if (likely(!audit_ever_enabled))
> +     if (likely(!audit_ever_enabled)) {
> +             audit_set_context(tsk, NULL);
>               return 0; /* Return if not auditing. */
> +     }
>  
>       state = audit_filter_task(tsk, &key);
>       if (state == AUDIT_DISABLED) {
> @@ -911,7 +913,7 @@ int audit_alloc(struct task_struct *tsk)
>  
>       if (!(context = audit_alloc_context(state))) {
>               kfree(key);
> -             audit_log_lost("out of memory in audit_alloc");
> +             audit_log_lost("out of memory in audit_alloc_syscall");
>               return -ENOMEM;
>       }
>       context->filterkey = key;
> @@ -1555,14 +1557,15 @@ static void audit_log_exit(void)
>  }
>  
>  /**
> - * __audit_free - free a per-task audit context
> + * audit_free_syscall - free per-task audit context info
>   * @tsk: task whose audit context block to free
>   *
> - * Called from copy_process and do_exit
> + * Called from audit_free
>   */
> -void __audit_free(struct task_struct *tsk)
> +void audit_free_syscall(struct task_struct *tsk)
>  {
> -     struct audit_context *context = tsk->audit_context;
> +     struct audit_task_info *info = tsk->audit;
> +     struct audit_context *context = info->ctx;
>  
>       if (!context)
>               return;
> @@ -1585,7 +1588,6 @@ void __audit_free(struct task_struct *tsk)
>               if (context->current_state == AUDIT_RECORD_CONTEXT)
>                       audit_log_exit();
>       }
> -
>       audit_set_context(tsk, NULL);
>       audit_free_context(context);
>  }
> diff --git a/kernel/fork.c b/kernel/fork.c
> index a60459947f18..1107bd8b8ad8 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -1836,7 +1836,6 @@ static __latent_entropy struct task_struct 
> *copy_process(
>       p->start_time = ktime_get_ns();
>       p->real_start_time = ktime_get_boot_ns();
>       p->io_context = NULL;
> -     audit_set_context(p, NULL);
>       cgroup_fork(p);
>  #ifdef CONFIG_NUMA
>       p->mempolicy = mpol_dup(p->mempolicy);
> -- 
> 1.8.3.1
> 
> 
Acked-by: Neil Horman <[email protected]>

--
Linux-audit mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-audit

Reply via email to