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.
Add kname into audit_reusename function to check file names
from the audit_names list.
Signed-off-by: Yiwen Gu <guyiwen(a)huawei.com>
---
fs/namei.c | 11 +++++++----
include/linux/audit.h | 11 +++++++----
kernel/auditsc.c | 7 ++++---
3 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index db6565c99825..c5623858f3e2 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,12 @@ getname_flags(const char __user *filename, int flags, int *empty)
}
}
+ result_audit = audit_reusename(filename, kname);
+ if (result_audit) {
+ putname(result);
+ 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