On 2020-04-22 14:28, Yiwen Gu wrote:
> Currently, audit_reusename check file path only by comparing
> userspace pointer "uptr", without checking the situation where
> the file name is different with the same uptr.

Has this been found to actually be a problem?  If so, is there a
reproducer to demonstrate this?

The reason it was originally set up like this was to make the check as
efficient as possible, comparing only a pointer, rather than needing to
compare the entire string.

> Add kname into audit_reusename function to check file names
> from the audit_names list.
> 
> Signed-off-by: Yiwen Gu <[email protected]>
> ---
>  fs/namei.c            |  9 +++++----
>  include/linux/audit.h | 11 +++++++----
>  kernel/auditsc.c      |  7 ++++---
>  3 files changed, 16 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/namei.c b/fs/namei.c
> index db6565c99825..d5fb4bd12aec 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -128,13 +128,10 @@ struct filename *
>  getname_flags(const char __user *filename, int flags, int *empty)
>  {
>       struct filename *result;
> +     struct filename *result_audit;
>       char *kname;
>       int len;
>  
> -     result = audit_reusename(filename);
> -     if (result)
> -             return result;
> -
>       result = __getname();
>       if (unlikely(!result))
>               return ERR_PTR(-ENOMEM);
> @@ -197,6 +194,10 @@ getname_flags(const char __user *filename, int flags, 
> int *empty)
>               }
>       }
>  
> +     result_audit = audit_reusename(filename, kname);
> +     if (result_audit)
> +             return result_audit;
> +
>       result->uptr = filename;
>       result->aname = NULL;
>       audit_getname(result);
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index f9ceae57ca8d..71fb783f14c4 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -266,7 +266,8 @@ 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);
> -extern struct filename *__audit_reusename(const __user char *uptr);
> +extern struct filename *__audit_reusename(const __user char *uptr,
> +                             const char *kname);
>  extern void __audit_getname(struct filename *name);
>  
>  extern void __audit_inode(struct filename *name, const struct dentry *dentry,
> @@ -316,10 +317,11 @@ static inline void audit_syscall_exit(void *pt_regs)
>               __audit_syscall_exit(success, return_code);
>       }
>  }
> -static inline struct filename *audit_reusename(const __user char *name)
> +static inline struct filename *audit_reusename(const __user char *name,
> +                                             const char *kname)
>  {
>       if (unlikely(!audit_dummy_context()))
> -             return __audit_reusename(name);
> +             return __audit_reusename(name, kname);
>       return NULL;
>  }
>  static inline void audit_getname(struct filename *name)
> @@ -539,7 +541,8 @@ static inline struct audit_context *audit_context(void)
>  {
>       return NULL;
>  }
> -static inline struct filename *audit_reusename(const __user char *name)
> +static inline struct filename *audit_reusename(const __user char *name,
> +                                             const char *kname)
>  {
>       return NULL;
>  }
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 4effe01ebbe2..62ffc02abb98 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -1843,13 +1843,14 @@ static struct audit_names *audit_alloc_name(struct 
> audit_context *context,
>  /**
>   * __audit_reusename - fill out filename with info from existing entry
>   * @uptr: userland ptr to pathname
> + * @kname: kernel pathname string
>   *
>   * Search the audit_names list for the current audit context. If there is an
> - * existing entry with a matching "uptr" then return the filename
> + * existing entry with matching "uptr" and "kname" then return the filename
>   * associated with that audit_name. If not, return NULL.
>   */
>  struct filename *
> -__audit_reusename(const __user char *uptr)
> +__audit_reusename(const __user char *uptr, const char *kname)
>  {
>       struct audit_context *context = audit_context();
>       struct audit_names *n;
> @@ -1857,7 +1858,7 @@ __audit_reusename(const __user char *uptr)
>       list_for_each_entry(n, &context->names_list, list) {
>               if (!n->name)
>                       continue;
> -             if (n->name->uptr == uptr) {
> +             if (n->name->uptr == uptr && !strcmp(kname, n->name->name)) {
>                       n->name->refcnt++;
>                       return n->name;
>               }
> -- 
> 2.17.1
> 
> 
> 
> --
> Linux-audit mailing list
> [email protected]
> https://www.redhat.com/mailman/listinfo/linux-audit

- RGB

--
Richard Guy Briggs <[email protected]>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
IRC: rgb, SunRaycer
Voice: +1.647.777.2635, Internal: (81) 32635

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

Reply via email to