Merge branch 'getname2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull getname/putname updates from Al Viro: "Rework of getname/getname_kernel/etc., mostly from Paul Moore. Gets rid of quite a pile of kludges between namei and audit..." * 'getname2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: audit: replace getname()/putname() hacks with reference counters audit: fix filename matching in __audit_inode() and __audit_inode_child() audit: enable filename recording via getname_kernel() simpler calling conventions for filename_mountpoint() fs: create proper filename objects using getname_kernel() fs: rework getname_kernel to handle up to PATH_MAX sized filenames cut down the number of do_path_lookup() callers
This commit is contained in:
commit
05016b0f0a
10
fs/exec.c
10
fs/exec.c
|
@ -794,8 +794,14 @@ exit:
|
|||
|
||||
struct file *open_exec(const char *name)
|
||||
{
|
||||
struct filename tmp = { .name = name };
|
||||
return do_open_execat(AT_FDCWD, &tmp, 0);
|
||||
struct filename *filename = getname_kernel(name);
|
||||
struct file *f = ERR_CAST(filename);
|
||||
|
||||
if (!IS_ERR(filename)) {
|
||||
f = do_open_execat(AT_FDCWD, filename, 0);
|
||||
putname(filename);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
EXPORT_SYMBOL(open_exec);
|
||||
|
||||
|
|
143
fs/namei.c
143
fs/namei.c
|
@ -118,15 +118,6 @@
|
|||
* POSIX.1 2.4: an empty pathname is invalid (ENOENT).
|
||||
* PATH_MAX includes the nul terminator --RR.
|
||||
*/
|
||||
void final_putname(struct filename *name)
|
||||
{
|
||||
if (name->separate) {
|
||||
__putname(name->name);
|
||||
kfree(name);
|
||||
} else {
|
||||
__putname(name);
|
||||
}
|
||||
}
|
||||
|
||||
#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename))
|
||||
|
||||
|
@ -145,6 +136,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
|
|||
result = __getname();
|
||||
if (unlikely(!result))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
result->refcnt = 1;
|
||||
|
||||
/*
|
||||
* First, try to embed the struct filename inside the names_cache
|
||||
|
@ -179,6 +171,7 @@ recopy:
|
|||
}
|
||||
result->name = kname;
|
||||
result->separate = true;
|
||||
result->refcnt = 1;
|
||||
max = PATH_MAX;
|
||||
goto recopy;
|
||||
}
|
||||
|
@ -202,7 +195,7 @@ recopy:
|
|||
return result;
|
||||
|
||||
error:
|
||||
final_putname(result);
|
||||
putname(result);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -212,43 +205,56 @@ getname(const char __user * filename)
|
|||
return getname_flags(filename, 0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* The "getname_kernel()" interface doesn't do pathnames longer
|
||||
* than EMBEDDED_NAME_MAX. Deal with it - you're a kernel user.
|
||||
*/
|
||||
struct filename *
|
||||
getname_kernel(const char * filename)
|
||||
{
|
||||
struct filename *result;
|
||||
char *kname;
|
||||
int len;
|
||||
|
||||
len = strlen(filename);
|
||||
if (len >= EMBEDDED_NAME_MAX)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
int len = strlen(filename) + 1;
|
||||
|
||||
result = __getname();
|
||||
if (unlikely(!result))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
kname = (char *)result + sizeof(*result);
|
||||
result->name = kname;
|
||||
if (len <= EMBEDDED_NAME_MAX) {
|
||||
result->name = (char *)(result) + sizeof(*result);
|
||||
result->separate = false;
|
||||
} else if (len <= PATH_MAX) {
|
||||
struct filename *tmp;
|
||||
|
||||
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
|
||||
if (unlikely(!tmp)) {
|
||||
__putname(result);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
tmp->name = (char *)result;
|
||||
tmp->separate = true;
|
||||
result = tmp;
|
||||
} else {
|
||||
__putname(result);
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
}
|
||||
memcpy((char *)result->name, filename, len);
|
||||
result->uptr = NULL;
|
||||
result->aname = NULL;
|
||||
result->separate = false;
|
||||
result->refcnt = 1;
|
||||
audit_getname(result);
|
||||
|
||||
strlcpy(kname, filename, EMBEDDED_NAME_MAX);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
void putname(struct filename *name)
|
||||
{
|
||||
if (unlikely(!audit_dummy_context()))
|
||||
return audit_putname(name);
|
||||
final_putname(name);
|
||||
BUG_ON(name->refcnt <= 0);
|
||||
|
||||
if (--name->refcnt > 0)
|
||||
return;
|
||||
|
||||
if (name->separate) {
|
||||
__putname(name->name);
|
||||
kfree(name);
|
||||
} else
|
||||
__putname(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int check_acl(struct inode *inode, int mask)
|
||||
{
|
||||
|
@ -2036,31 +2042,47 @@ static int filename_lookup(int dfd, struct filename *name,
|
|||
static int do_path_lookup(int dfd, const char *name,
|
||||
unsigned int flags, struct nameidata *nd)
|
||||
{
|
||||
struct filename filename = { .name = name };
|
||||
struct filename *filename = getname_kernel(name);
|
||||
int retval = PTR_ERR(filename);
|
||||
|
||||
return filename_lookup(dfd, &filename, flags, nd);
|
||||
if (!IS_ERR(filename)) {
|
||||
retval = filename_lookup(dfd, filename, flags, nd);
|
||||
putname(filename);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* does lookup, returns the object with parent locked */
|
||||
struct dentry *kern_path_locked(const char *name, struct path *path)
|
||||
{
|
||||
struct filename *filename = getname_kernel(name);
|
||||
struct nameidata nd;
|
||||
struct dentry *d;
|
||||
int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
int err;
|
||||
|
||||
if (IS_ERR(filename))
|
||||
return ERR_CAST(filename);
|
||||
|
||||
err = filename_lookup(AT_FDCWD, filename, LOOKUP_PARENT, &nd);
|
||||
if (err) {
|
||||
d = ERR_PTR(err);
|
||||
goto out;
|
||||
}
|
||||
if (nd.last_type != LAST_NORM) {
|
||||
path_put(&nd.path);
|
||||
return ERR_PTR(-EINVAL);
|
||||
d = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
}
|
||||
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
d = __lookup_hash(&nd.last, nd.path.dentry, 0);
|
||||
if (IS_ERR(d)) {
|
||||
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
||||
path_put(&nd.path);
|
||||
return d;
|
||||
goto out;
|
||||
}
|
||||
*path = nd.path;
|
||||
out:
|
||||
putname(filename);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -2351,13 +2373,17 @@ static int
|
|||
filename_mountpoint(int dfd, struct filename *s, struct path *path,
|
||||
unsigned int flags)
|
||||
{
|
||||
int error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU);
|
||||
int error;
|
||||
if (IS_ERR(s))
|
||||
return PTR_ERR(s);
|
||||
error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU);
|
||||
if (unlikely(error == -ECHILD))
|
||||
error = path_mountpoint(dfd, s->name, path, flags);
|
||||
if (unlikely(error == -ESTALE))
|
||||
error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL);
|
||||
if (likely(!error))
|
||||
audit_inode(s, path->dentry, 0);
|
||||
putname(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -2379,21 +2405,14 @@ int
|
|||
user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags,
|
||||
struct path *path)
|
||||
{
|
||||
struct filename *s = getname(name);
|
||||
int error;
|
||||
if (IS_ERR(s))
|
||||
return PTR_ERR(s);
|
||||
error = filename_mountpoint(dfd, s, path, flags);
|
||||
putname(s);
|
||||
return error;
|
||||
return filename_mountpoint(dfd, getname(name), path, flags);
|
||||
}
|
||||
|
||||
int
|
||||
kern_path_mountpoint(int dfd, const char *name, struct path *path,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct filename s = {.name = name};
|
||||
return filename_mountpoint(dfd, &s, path, flags);
|
||||
return filename_mountpoint(dfd, getname_kernel(name), path, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(kern_path_mountpoint);
|
||||
|
||||
|
@ -3273,7 +3292,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
|||
{
|
||||
struct nameidata nd;
|
||||
struct file *file;
|
||||
struct filename filename = { .name = name };
|
||||
struct filename *filename;
|
||||
int flags = op->lookup_flags | LOOKUP_ROOT;
|
||||
|
||||
nd.root.mnt = mnt;
|
||||
|
@ -3282,15 +3301,20 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
|||
if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN)
|
||||
return ERR_PTR(-ELOOP);
|
||||
|
||||
file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU);
|
||||
filename = getname_kernel(name);
|
||||
if (unlikely(IS_ERR(filename)))
|
||||
return ERR_CAST(filename);
|
||||
|
||||
file = path_openat(-1, filename, &nd, op, flags | LOOKUP_RCU);
|
||||
if (unlikely(file == ERR_PTR(-ECHILD)))
|
||||
file = path_openat(-1, &filename, &nd, op, flags);
|
||||
file = path_openat(-1, filename, &nd, op, flags);
|
||||
if (unlikely(file == ERR_PTR(-ESTALE)))
|
||||
file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_REVAL);
|
||||
file = path_openat(-1, filename, &nd, op, flags | LOOKUP_REVAL);
|
||||
putname(filename);
|
||||
return file;
|
||||
}
|
||||
|
||||
struct dentry *kern_path_create(int dfd, const char *pathname,
|
||||
static struct dentry *filename_create(int dfd, struct filename *name,
|
||||
struct path *path, unsigned int lookup_flags)
|
||||
{
|
||||
struct dentry *dentry = ERR_PTR(-EEXIST);
|
||||
|
@ -3305,7 +3329,7 @@ struct dentry *kern_path_create(int dfd, const char *pathname,
|
|||
*/
|
||||
lookup_flags &= LOOKUP_REVAL;
|
||||
|
||||
error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd);
|
||||
error = filename_lookup(dfd, name, LOOKUP_PARENT|lookup_flags, &nd);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
|
||||
|
@ -3359,6 +3383,19 @@ out:
|
|||
path_put(&nd.path);
|
||||
return dentry;
|
||||
}
|
||||
|
||||
struct dentry *kern_path_create(int dfd, const char *pathname,
|
||||
struct path *path, unsigned int lookup_flags)
|
||||
{
|
||||
struct filename *filename = getname_kernel(pathname);
|
||||
struct dentry *res;
|
||||
|
||||
if (IS_ERR(filename))
|
||||
return ERR_CAST(filename);
|
||||
res = filename_create(dfd, filename, path, lookup_flags);
|
||||
putname(filename);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(kern_path_create);
|
||||
|
||||
void done_path_create(struct path *path, struct dentry *dentry)
|
||||
|
@ -3377,7 +3414,7 @@ struct dentry *user_path_create(int dfd, const char __user *pathname,
|
|||
struct dentry *res;
|
||||
if (IS_ERR(tmp))
|
||||
return ERR_CAST(tmp);
|
||||
res = kern_path_create(dfd, tmp->name, path, lookup_flags);
|
||||
res = filename_create(dfd, tmp, path, lookup_flags);
|
||||
putname(tmp);
|
||||
return res;
|
||||
}
|
||||
|
|
10
fs/open.c
10
fs/open.c
|
@ -968,8 +968,14 @@ struct file *file_open_name(struct filename *name, int flags, umode_t mode)
|
|||
*/
|
||||
struct file *filp_open(const char *filename, int flags, umode_t mode)
|
||||
{
|
||||
struct filename name = {.name = filename};
|
||||
return file_open_name(&name, flags, mode);
|
||||
struct filename *name = getname_kernel(filename);
|
||||
struct file *file = ERR_CAST(name);
|
||||
|
||||
if (!IS_ERR(name)) {
|
||||
file = file_open_name(name, flags, mode);
|
||||
putname(name);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
EXPORT_SYMBOL(filp_open);
|
||||
|
||||
|
|
|
@ -127,7 +127,6 @@ extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
|
|||
extern void __audit_syscall_exit(int ret_success, long ret_value);
|
||||
extern struct filename *__audit_reusename(const __user char *uptr);
|
||||
extern void __audit_getname(struct filename *name);
|
||||
extern void audit_putname(struct filename *name);
|
||||
|
||||
#define AUDIT_INODE_PARENT 1 /* dentry represents the parent */
|
||||
#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */
|
||||
|
@ -352,8 +351,6 @@ static inline struct filename *audit_reusename(const __user char *name)
|
|||
}
|
||||
static inline void audit_getname(struct filename *name)
|
||||
{ }
|
||||
static inline void audit_putname(struct filename *name)
|
||||
{ }
|
||||
static inline void __audit_inode(struct filename *name,
|
||||
const struct dentry *dentry,
|
||||
unsigned int flags)
|
||||
|
|
|
@ -2141,6 +2141,7 @@ struct filename {
|
|||
const char *name; /* pointer to actual string */
|
||||
const __user char *uptr; /* original userland pointer */
|
||||
struct audit_names *aname;
|
||||
int refcnt;
|
||||
bool separate; /* should "name" be freed? */
|
||||
};
|
||||
|
||||
|
@ -2162,6 +2163,7 @@ extern int filp_close(struct file *, fl_owner_t id);
|
|||
extern struct filename *getname_flags(const char __user *, int, int *);
|
||||
extern struct filename *getname(const char __user *);
|
||||
extern struct filename *getname_kernel(const char *);
|
||||
extern void putname(struct filename *name);
|
||||
|
||||
enum {
|
||||
FILE_CREATED = 1,
|
||||
|
@ -2182,15 +2184,8 @@ extern void __init vfs_caches_init(unsigned long);
|
|||
|
||||
extern struct kmem_cache *names_cachep;
|
||||
|
||||
extern void final_putname(struct filename *name);
|
||||
|
||||
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
|
||||
#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
|
||||
#ifndef CONFIG_AUDITSYSCALL
|
||||
#define putname(name) final_putname(name)
|
||||
#else
|
||||
extern void putname(struct filename *name);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
extern int register_blkdev(unsigned int, const char *);
|
||||
|
|
|
@ -24,12 +24,6 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <uapi/linux/mqueue.h>
|
||||
|
||||
/* 0 = no checking
|
||||
1 = put_count checking
|
||||
2 = verbose put_count checking
|
||||
*/
|
||||
#define AUDIT_DEBUG 0
|
||||
|
||||
/* AUDIT_NAMES is the number of slots we reserve in the audit_context
|
||||
* for saving names from getname(). If we get more names we will allocate
|
||||
* a name dynamically and also add those to the list anchored by names_list. */
|
||||
|
@ -74,9 +68,8 @@ struct audit_cap_data {
|
|||
};
|
||||
};
|
||||
|
||||
/* When fs/namei.c:getname() is called, we store the pointer in name and
|
||||
* we don't let putname() free it (instead we free all of the saved
|
||||
* pointers at syscall exit time).
|
||||
/* When fs/namei.c:getname() is called, we store the pointer in name and bump
|
||||
* the refcnt in the associated filename struct.
|
||||
*
|
||||
* Further, in fs/namei.c:path_lookup() we store the inode and device.
|
||||
*/
|
||||
|
@ -86,7 +79,6 @@ struct audit_names {
|
|||
struct filename *name;
|
||||
int name_len; /* number of chars to log */
|
||||
bool hidden; /* don't log this record */
|
||||
bool name_put; /* call __putname()? */
|
||||
|
||||
unsigned long ino;
|
||||
dev_t dev;
|
||||
|
@ -208,11 +200,6 @@ struct audit_context {
|
|||
};
|
||||
int fds[2];
|
||||
struct audit_proctitle proctitle;
|
||||
|
||||
#if AUDIT_DEBUG
|
||||
int put_count;
|
||||
int ino_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern u32 audit_ever_enabled;
|
||||
|
|
171
kernel/auditsc.c
171
kernel/auditsc.c
|
@ -866,33 +866,10 @@ static inline void audit_free_names(struct audit_context *context)
|
|||
{
|
||||
struct audit_names *n, *next;
|
||||
|
||||
#if AUDIT_DEBUG == 2
|
||||
if (context->put_count + context->ino_count != context->name_count) {
|
||||
int i = 0;
|
||||
|
||||
pr_err("%s:%d(:%d): major=%d in_syscall=%d"
|
||||
" name_count=%d put_count=%d ino_count=%d"
|
||||
" [NOT freeing]\n", __FILE__, __LINE__,
|
||||
context->serial, context->major, context->in_syscall,
|
||||
context->name_count, context->put_count,
|
||||
context->ino_count);
|
||||
list_for_each_entry(n, &context->names_list, list) {
|
||||
pr_err("names[%d] = %p = %s\n", i++, n->name,
|
||||
n->name->name ?: "(null)");
|
||||
}
|
||||
dump_stack();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if AUDIT_DEBUG
|
||||
context->put_count = 0;
|
||||
context->ino_count = 0;
|
||||
#endif
|
||||
|
||||
list_for_each_entry_safe(n, next, &context->names_list, list) {
|
||||
list_del(&n->list);
|
||||
if (n->name && n->name_put)
|
||||
final_putname(n->name);
|
||||
if (n->name)
|
||||
putname(n->name);
|
||||
if (n->should_free)
|
||||
kfree(n);
|
||||
}
|
||||
|
@ -1711,9 +1688,6 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
|
|||
list_add_tail(&aname->list, &context->names_list);
|
||||
|
||||
context->name_count++;
|
||||
#if AUDIT_DEBUG
|
||||
context->ino_count++;
|
||||
#endif
|
||||
return aname;
|
||||
}
|
||||
|
||||
|
@ -1734,8 +1708,10 @@ __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) {
|
||||
n->name->refcnt++;
|
||||
return n->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1752,19 +1728,8 @@ void __audit_getname(struct filename *name)
|
|||
struct audit_context *context = current->audit_context;
|
||||
struct audit_names *n;
|
||||
|
||||
if (!context->in_syscall) {
|
||||
#if AUDIT_DEBUG == 2
|
||||
pr_err("%s:%d(:%d): ignoring getname(%p)\n",
|
||||
__FILE__, __LINE__, context->serial, name);
|
||||
dump_stack();
|
||||
#endif
|
||||
if (!context->in_syscall)
|
||||
return;
|
||||
}
|
||||
|
||||
#if AUDIT_DEBUG
|
||||
/* The filename _must_ have a populated ->name */
|
||||
BUG_ON(!name->name);
|
||||
#endif
|
||||
|
||||
n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
|
||||
if (!n)
|
||||
|
@ -1772,56 +1737,13 @@ void __audit_getname(struct filename *name)
|
|||
|
||||
n->name = name;
|
||||
n->name_len = AUDIT_NAME_FULL;
|
||||
n->name_put = true;
|
||||
name->aname = n;
|
||||
name->refcnt++;
|
||||
|
||||
if (!context->pwd.dentry)
|
||||
get_fs_pwd(current->fs, &context->pwd);
|
||||
}
|
||||
|
||||
/* audit_putname - intercept a putname request
|
||||
* @name: name to intercept and delay for putname
|
||||
*
|
||||
* If we have stored the name from getname in the audit context,
|
||||
* then we delay the putname until syscall exit.
|
||||
* Called from include/linux/fs.h:putname().
|
||||
*/
|
||||
void audit_putname(struct filename *name)
|
||||
{
|
||||
struct audit_context *context = current->audit_context;
|
||||
|
||||
BUG_ON(!context);
|
||||
if (!name->aname || !context->in_syscall) {
|
||||
#if AUDIT_DEBUG == 2
|
||||
pr_err("%s:%d(:%d): final_putname(%p)\n",
|
||||
__FILE__, __LINE__, context->serial, name);
|
||||
if (context->name_count) {
|
||||
struct audit_names *n;
|
||||
int i = 0;
|
||||
|
||||
list_for_each_entry(n, &context->names_list, list)
|
||||
pr_err("name[%d] = %p = %s\n", i++, n->name,
|
||||
n->name->name ?: "(null)");
|
||||
}
|
||||
#endif
|
||||
final_putname(name);
|
||||
}
|
||||
#if AUDIT_DEBUG
|
||||
else {
|
||||
++context->put_count;
|
||||
if (context->put_count > context->name_count) {
|
||||
pr_err("%s:%d(:%d): major=%d in_syscall=%d putname(%p)"
|
||||
" name_count=%d put_count=%d\n",
|
||||
__FILE__, __LINE__,
|
||||
context->serial, context->major,
|
||||
context->in_syscall, name->name,
|
||||
context->name_count, context->put_count);
|
||||
dump_stack();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* __audit_inode - store the inode and device from a lookup
|
||||
* @name: name being audited
|
||||
|
@ -1842,10 +1764,6 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
|
|||
if (!name)
|
||||
goto out_alloc;
|
||||
|
||||
#if AUDIT_DEBUG
|
||||
/* The struct filename _must_ have a populated ->name */
|
||||
BUG_ON(!name->name);
|
||||
#endif
|
||||
/*
|
||||
* If we have a pointer to an audit_names entry already, then we can
|
||||
* just use it directly if the type is correct.
|
||||
|
@ -1863,7 +1781,17 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
|
|||
}
|
||||
|
||||
list_for_each_entry_reverse(n, &context->names_list, list) {
|
||||
if (!n->name || strcmp(n->name->name, name->name))
|
||||
if (n->ino) {
|
||||
/* valid inode number, use that for the comparison */
|
||||
if (n->ino != inode->i_ino ||
|
||||
n->dev != inode->i_sb->s_dev)
|
||||
continue;
|
||||
} else if (n->name) {
|
||||
/* inode number has not been set, check the name */
|
||||
if (strcmp(n->name->name, name->name))
|
||||
continue;
|
||||
} else
|
||||
/* no inode and no name (?!) ... this is odd ... */
|
||||
continue;
|
||||
|
||||
/* match the correct record type */
|
||||
|
@ -1882,44 +1810,11 @@ out_alloc:
|
|||
n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
|
||||
if (!n)
|
||||
return;
|
||||
/* unfortunately, while we may have a path name to record with the
|
||||
* inode, we can't always rely on the string lasting until the end of
|
||||
* the syscall so we need to create our own copy, it may fail due to
|
||||
* memory allocation issues, but we do our best */
|
||||
if (name) {
|
||||
/* we can't use getname_kernel() due to size limits */
|
||||
size_t len = strlen(name->name) + 1;
|
||||
struct filename *new = __getname();
|
||||
|
||||
if (unlikely(!new))
|
||||
goto out;
|
||||
|
||||
if (len <= (PATH_MAX - sizeof(*new))) {
|
||||
new->name = (char *)(new) + sizeof(*new);
|
||||
new->separate = false;
|
||||
} else if (len <= PATH_MAX) {
|
||||
/* this looks odd, but is due to final_putname() */
|
||||
struct filename *new2;
|
||||
|
||||
new2 = kmalloc(sizeof(*new2), GFP_KERNEL);
|
||||
if (unlikely(!new2)) {
|
||||
__putname(new);
|
||||
goto out;
|
||||
}
|
||||
new2->name = (char *)new;
|
||||
new2->separate = true;
|
||||
new = new2;
|
||||
} else {
|
||||
/* we should never get here, but let's be safe */
|
||||
__putname(new);
|
||||
goto out;
|
||||
}
|
||||
strlcpy((char *)new->name, name->name, len);
|
||||
new->uptr = NULL;
|
||||
new->aname = n;
|
||||
n->name = new;
|
||||
n->name_put = true;
|
||||
n->name = name;
|
||||
name->refcnt++;
|
||||
}
|
||||
|
||||
out:
|
||||
if (parent) {
|
||||
n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;
|
||||
|
@ -1970,11 +1865,16 @@ void __audit_inode_child(const struct inode *parent,
|
|||
|
||||
/* look for a parent entry first */
|
||||
list_for_each_entry(n, &context->names_list, list) {
|
||||
if (!n->name || n->type != AUDIT_TYPE_PARENT)
|
||||
if (!n->name ||
|
||||
(n->type != AUDIT_TYPE_PARENT &&
|
||||
n->type != AUDIT_TYPE_UNKNOWN))
|
||||
continue;
|
||||
|
||||
if (n->ino == parent->i_ino &&
|
||||
!audit_compare_dname_path(dname, n->name->name, n->name_len)) {
|
||||
if (n->ino == parent->i_ino && n->dev == parent->i_sb->s_dev &&
|
||||
!audit_compare_dname_path(dname,
|
||||
n->name->name, n->name_len)) {
|
||||
if (n->type == AUDIT_TYPE_UNKNOWN)
|
||||
n->type = AUDIT_TYPE_PARENT;
|
||||
found_parent = n;
|
||||
break;
|
||||
}
|
||||
|
@ -1983,11 +1883,8 @@ void __audit_inode_child(const struct inode *parent,
|
|||
/* is there a matching child entry? */
|
||||
list_for_each_entry(n, &context->names_list, list) {
|
||||
/* can only match entries that have a name */
|
||||
if (!n->name || n->type != type)
|
||||
continue;
|
||||
|
||||
/* if we found a parent, make sure this one is a child of it */
|
||||
if (found_parent && (n->name != found_parent->name))
|
||||
if (!n->name ||
|
||||
(n->type != type && n->type != AUDIT_TYPE_UNKNOWN))
|
||||
continue;
|
||||
|
||||
if (!strcmp(dname, n->name->name) ||
|
||||
|
@ -1995,6 +1892,8 @@ void __audit_inode_child(const struct inode *parent,
|
|||
found_parent ?
|
||||
found_parent->name_len :
|
||||
AUDIT_NAME_FULL)) {
|
||||
if (n->type == AUDIT_TYPE_UNKNOWN)
|
||||
n->type = type;
|
||||
found_child = n;
|
||||
break;
|
||||
}
|
||||
|
@ -2019,10 +1918,10 @@ void __audit_inode_child(const struct inode *parent,
|
|||
if (found_parent) {
|
||||
found_child->name = found_parent->name;
|
||||
found_child->name_len = AUDIT_NAME_FULL;
|
||||
/* don't call __putname() */
|
||||
found_child->name_put = false;
|
||||
found_child->name->refcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (inode)
|
||||
audit_copy_inode(found_child, dentry, inode);
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue