Commit 05016b0f authored by Linus Torvalds's avatar Linus Torvalds

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
parents c6b1de1b 55422d0b
...@@ -794,8 +794,14 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags) ...@@ -794,8 +794,14 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
struct file *open_exec(const char *name) struct file *open_exec(const char *name)
{ {
struct filename tmp = { .name = name }; struct filename *filename = getname_kernel(name);
return do_open_execat(AT_FDCWD, &tmp, 0); 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); EXPORT_SYMBOL(open_exec);
......
...@@ -118,15 +118,6 @@ ...@@ -118,15 +118,6 @@
* POSIX.1 2.4: an empty pathname is invalid (ENOENT). * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
* PATH_MAX includes the nul terminator --RR. * 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)) #define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename))
...@@ -145,6 +136,7 @@ getname_flags(const char __user *filename, int flags, int *empty) ...@@ -145,6 +136,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
result = __getname(); result = __getname();
if (unlikely(!result)) if (unlikely(!result))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
result->refcnt = 1;
/* /*
* First, try to embed the struct filename inside the names_cache * First, try to embed the struct filename inside the names_cache
...@@ -179,6 +171,7 @@ getname_flags(const char __user *filename, int flags, int *empty) ...@@ -179,6 +171,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
} }
result->name = kname; result->name = kname;
result->separate = true; result->separate = true;
result->refcnt = 1;
max = PATH_MAX; max = PATH_MAX;
goto recopy; goto recopy;
} }
...@@ -202,7 +195,7 @@ getname_flags(const char __user *filename, int flags, int *empty) ...@@ -202,7 +195,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
return result; return result;
error: error:
final_putname(result); putname(result);
return err; return err;
} }
...@@ -212,43 +205,56 @@ getname(const char __user * filename) ...@@ -212,43 +205,56 @@ getname(const char __user * filename)
return getname_flags(filename, 0, NULL); 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 * struct filename *
getname_kernel(const char * filename) getname_kernel(const char * filename)
{ {
struct filename *result; struct filename *result;
char *kname; int len = strlen(filename) + 1;
int len;
len = strlen(filename);
if (len >= EMBEDDED_NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
result = __getname(); result = __getname();
if (unlikely(!result)) if (unlikely(!result))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
kname = (char *)result + sizeof(*result); if (len <= EMBEDDED_NAME_MAX) {
result->name = kname; 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->uptr = NULL;
result->aname = NULL; result->aname = NULL;
result->separate = false; result->refcnt = 1;
audit_getname(result);
strlcpy(kname, filename, EMBEDDED_NAME_MAX);
return result; return result;
} }
#ifdef CONFIG_AUDITSYSCALL
void putname(struct filename *name) void putname(struct filename *name)
{ {
if (unlikely(!audit_dummy_context())) BUG_ON(name->refcnt <= 0);
return audit_putname(name);
final_putname(name); 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) static int check_acl(struct inode *inode, int mask)
{ {
...@@ -2036,31 +2042,47 @@ static int filename_lookup(int dfd, struct filename *name, ...@@ -2036,31 +2042,47 @@ static int filename_lookup(int dfd, struct filename *name,
static int do_path_lookup(int dfd, const char *name, static int do_path_lookup(int dfd, const char *name,
unsigned int flags, struct nameidata *nd) 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 */ /* does lookup, returns the object with parent locked */
struct dentry *kern_path_locked(const char *name, struct path *path) struct dentry *kern_path_locked(const char *name, struct path *path)
{ {
struct filename *filename = getname_kernel(name);
struct nameidata nd; struct nameidata nd;
struct dentry *d; struct dentry *d;
int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd); int err;
if (err)
return ERR_PTR(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) { if (nd.last_type != LAST_NORM) {
path_put(&nd.path); 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); mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
d = __lookup_hash(&nd.last, nd.path.dentry, 0); d = __lookup_hash(&nd.last, nd.path.dentry, 0);
if (IS_ERR(d)) { if (IS_ERR(d)) {
mutex_unlock(&nd.path.dentry->d_inode->i_mutex); mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path); path_put(&nd.path);
return d; goto out;
} }
*path = nd.path; *path = nd.path;
out:
putname(filename);
return d; return d;
} }
...@@ -2351,13 +2373,17 @@ static int ...@@ -2351,13 +2373,17 @@ static int
filename_mountpoint(int dfd, struct filename *s, struct path *path, filename_mountpoint(int dfd, struct filename *s, struct path *path,
unsigned int flags) 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)) if (unlikely(error == -ECHILD))
error = path_mountpoint(dfd, s->name, path, flags); error = path_mountpoint(dfd, s->name, path, flags);
if (unlikely(error == -ESTALE)) if (unlikely(error == -ESTALE))
error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL); error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL);
if (likely(!error)) if (likely(!error))
audit_inode(s, path->dentry, 0); audit_inode(s, path->dentry, 0);
putname(s);
return error; return error;
} }
...@@ -2379,21 +2405,14 @@ int ...@@ -2379,21 +2405,14 @@ int
user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags, user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags,
struct path *path) struct path *path)
{ {
struct filename *s = getname(name); return filename_mountpoint(dfd, getname(name), path, flags);
int error;
if (IS_ERR(s))
return PTR_ERR(s);
error = filename_mountpoint(dfd, s, path, flags);
putname(s);
return error;
} }
int int
kern_path_mountpoint(int dfd, const char *name, struct path *path, kern_path_mountpoint(int dfd, const char *name, struct path *path,
unsigned int flags) unsigned int flags)
{ {
struct filename s = {.name = name}; return filename_mountpoint(dfd, getname_kernel(name), path, flags);
return filename_mountpoint(dfd, &s, path, flags);
} }
EXPORT_SYMBOL(kern_path_mountpoint); EXPORT_SYMBOL(kern_path_mountpoint);
...@@ -3273,7 +3292,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, ...@@ -3273,7 +3292,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
{ {
struct nameidata nd; struct nameidata nd;
struct file *file; struct file *file;
struct filename filename = { .name = name }; struct filename *filename;
int flags = op->lookup_flags | LOOKUP_ROOT; int flags = op->lookup_flags | LOOKUP_ROOT;
nd.root.mnt = mnt; nd.root.mnt = mnt;
...@@ -3282,15 +3301,20 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *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) if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN)
return ERR_PTR(-ELOOP); 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))) 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))) 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; 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 path *path, unsigned int lookup_flags)
{ {
struct dentry *dentry = ERR_PTR(-EEXIST); struct dentry *dentry = ERR_PTR(-EEXIST);
...@@ -3305,7 +3329,7 @@ struct dentry *kern_path_create(int dfd, const char *pathname, ...@@ -3305,7 +3329,7 @@ struct dentry *kern_path_create(int dfd, const char *pathname,
*/ */
lookup_flags &= LOOKUP_REVAL; 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) if (error)
return ERR_PTR(error); return ERR_PTR(error);
...@@ -3359,6 +3383,19 @@ struct dentry *kern_path_create(int dfd, const char *pathname, ...@@ -3359,6 +3383,19 @@ struct dentry *kern_path_create(int dfd, const char *pathname,
path_put(&nd.path); path_put(&nd.path);
return dentry; 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); EXPORT_SYMBOL(kern_path_create);
void done_path_create(struct path *path, struct dentry *dentry) 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, ...@@ -3377,7 +3414,7 @@ struct dentry *user_path_create(int dfd, const char __user *pathname,
struct dentry *res; struct dentry *res;
if (IS_ERR(tmp)) if (IS_ERR(tmp))
return ERR_CAST(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); putname(tmp);
return res; return res;
} }
......
...@@ -968,8 +968,14 @@ struct file *file_open_name(struct filename *name, int flags, umode_t mode) ...@@ -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 file *filp_open(const char *filename, int flags, umode_t mode)
{ {
struct filename name = {.name = filename}; struct filename *name = getname_kernel(filename);
return file_open_name(&name, flags, mode); 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); EXPORT_SYMBOL(filp_open);
......
...@@ -127,7 +127,6 @@ extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1, ...@@ -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 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);
extern void __audit_getname(struct filename *name); 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_PARENT 1 /* dentry represents the parent */
#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */ #define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */
...@@ -352,8 +351,6 @@ static inline struct filename *audit_reusename(const __user char *name) ...@@ -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_getname(struct filename *name)
{ } { }
static inline void audit_putname(struct filename *name)
{ }
static inline void __audit_inode(struct filename *name, static inline void __audit_inode(struct filename *name,
const struct dentry *dentry, const struct dentry *dentry,
unsigned int flags) unsigned int flags)
......
...@@ -2141,6 +2141,7 @@ struct filename { ...@@ -2141,6 +2141,7 @@ struct filename {
const char *name; /* pointer to actual string */ const char *name; /* pointer to actual string */
const __user char *uptr; /* original userland pointer */ const __user char *uptr; /* original userland pointer */
struct audit_names *aname; struct audit_names *aname;
int refcnt;
bool separate; /* should "name" be freed? */ bool separate; /* should "name" be freed? */
}; };
...@@ -2162,6 +2163,7 @@ extern int filp_close(struct file *, fl_owner_t id); ...@@ -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_flags(const char __user *, int, int *);
extern struct filename *getname(const char __user *); extern struct filename *getname(const char __user *);
extern struct filename *getname_kernel(const char *); extern struct filename *getname_kernel(const char *);
extern void putname(struct filename *name);
enum { enum {
FILE_CREATED = 1, FILE_CREATED = 1,
...@@ -2182,15 +2184,8 @@ extern void __init vfs_caches_init(unsigned long); ...@@ -2182,15 +2184,8 @@ extern void __init vfs_caches_init(unsigned long);
extern struct kmem_cache *names_cachep; extern struct kmem_cache *names_cachep;
extern void final_putname(struct filename *name);
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL) #define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
#define __putname(name) kmem_cache_free(names_cachep, (void *)(name)) #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 #ifdef CONFIG_BLOCK
extern int register_blkdev(unsigned int, const char *); extern int register_blkdev(unsigned int, const char *);
......
...@@ -24,12 +24,6 @@ ...@@ -24,12 +24,6 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <uapi/linux/mqueue.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 /* 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 * 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. */ * a name dynamically and also add those to the list anchored by names_list. */
...@@ -74,9 +68,8 @@ struct audit_cap_data { ...@@ -74,9 +68,8 @@ struct audit_cap_data {
}; };
}; };
/* When fs/namei.c:getname() is called, we store the pointer in name and /* When fs/namei.c:getname() is called, we store the pointer in name and bump
* we don't let putname() free it (instead we free all of the saved * the refcnt in the associated filename struct.
* pointers at syscall exit time).
* *
* Further, in fs/namei.c:path_lookup() we store the inode and device. * Further, in fs/namei.c:path_lookup() we store the inode and device.
*/ */
...@@ -86,7 +79,6 @@ struct audit_names { ...@@ -86,7 +79,6 @@ struct audit_names {
struct filename *name; struct filename *name;
int name_len; /* number of chars to log */ int name_len; /* number of chars to log */
bool hidden; /* don't log this record */ bool hidden; /* don't log this record */
bool name_put; /* call __putname()? */
unsigned long ino; unsigned long ino;
dev_t dev; dev_t dev;
...@@ -208,11 +200,6 @@ struct audit_context { ...@@ -208,11 +200,6 @@ struct audit_context {
}; };
int fds[2]; int fds[2];
struct audit_proctitle proctitle; struct audit_proctitle proctitle;
#if AUDIT_DEBUG
int put_count;
int ino_count;
#endif
}; };
extern u32 audit_ever_enabled; extern u32 audit_ever_enabled;
......
...@@ -866,33 +866,10 @@ static inline void audit_free_names(struct audit_context *context) ...@@ -866,33 +866,10 @@ static inline void audit_free_names(struct audit_context *context)
{ {
struct audit_names *n, *next; 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_for_each_entry_safe(n, next, &context->names_list, list) {
list_del(&n->list); list_del(&n->list);
if (n->name && n->name_put) if (n->name)
final_putname(n->name); putname(n->name);
if (n->should_free) if (n->should_free)
kfree(n); kfree(n);
} }
...@@ -1711,9 +1688,6 @@ static struct audit_names *audit_alloc_name(struct audit_context *context, ...@@ -1711,9 +1688,6 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
list_add_tail(&aname->list, &context->names_list); list_add_tail(&aname->list, &context->names_list);
context->name_count++; context->name_count++;
#if AUDIT_DEBUG
context->ino_count++;
#endif
return aname; return aname;
} }
...@@ -1734,9 +1708,11 @@ __audit_reusename(const __user char *uptr) ...@@ -1734,9 +1708,11 @@ __audit_reusename(const __user char *uptr)
list_for_each_entry(n, &context->names_list, list) { list_for_each_entry(n, &context->names_list, list) {
if (!n->name) if (!n->name)
continue; continue;
if (n->name->uptr == uptr) if (n->name->uptr == uptr) {
n->name->refcnt++;
return n->name; return n->name;
} }
}
return NULL; return NULL;
} }
...@@ -1752,19 +1728,8 @@ void __audit_getname(struct filename *name) ...@@ -1752,19 +1728,8 @@ void __audit_getname(struct filename *name)
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
struct audit_names *n; struct audit_names *n;
if (!context->in_syscall) { 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
return; return;
}
#if AUDIT_DEBUG
/* The filename _must_ have a populated ->name */
BUG_ON(!name->name);
#endif
n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
if (!n) if (!n)
...@@ -1772,56 +1737,13 @@ void __audit_getname(struct filename *name) ...@@ -1772,56 +1737,13 @@ void __audit_getname(struct filename *name)
n->name = name; n->name = name;
n->name_len = AUDIT_NAME_FULL; n->name_len = AUDIT_NAME_FULL;
n->name_put = true;
name->aname = n; name->aname = n;
name->refcnt++;
if (!context->pwd.dentry) if (!context->pwd.dentry)
get_fs_pwd(current->fs, &context->pwd); 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 * __audit_inode - store the inode and device from a lookup
* @name: name being audited * @name: name being audited
...@@ -1842,10 +1764,6 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, ...@@ -1842,10 +1764,6 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
if (!name) if (!name)
goto out_alloc; 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 * If we have a pointer to an audit_names entry already, then we can
* just use it directly if the type is correct. * just use it directly if the type is correct.
...@@ -1863,7 +1781,17 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, ...@@ -1863,7 +1781,17 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
} }
list_for_each_entry_reverse(n, &context->names_list, list) { 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; continue;
/* match the correct record type */ /* match the correct record type */
...@@ -1882,44 +1810,11 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, ...@@ -1882,44 +1810,11 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
if (!n) if (!n)
return; 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) { if (name) {
/* we can't use getname_kernel() due to size limits */ n->name = name;
size_t len = strlen(name->name) + 1; name->refcnt++;
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;
} }
out: out:
if (parent) { if (parent) {
n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; 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, ...@@ -1970,11 +1865,16 @@ void __audit_inode_child(const struct inode *parent,
/* look for a parent entry first */ /* look for a parent entry first */
list_for_each_entry(n, &context->names_list, list) { 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; continue;
if (n->ino == parent->i_ino && if (n->ino == parent->i_ino && n->dev == parent->i_sb->s_dev &&
!audit_compare_dname_path(dname, n->name->name, n->name_len)) { !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; found_parent = n;
break; break;
} }
...@@ -1983,11 +1883,8 @@ void __audit_inode_child(const struct inode *parent, ...@@ -1983,11 +1883,8 @@ void __audit_inode_child(const struct inode *parent,
/* is there a matching child entry? */ /* is there a matching child entry? */
list_for_each_entry(n, &context->names_list, list) { list_for_each_entry(n, &context->names_list, list) {
/* can only match entries that have a name */ /* can only match entries that have a name */
if (!n->name || n->type != type) if (!n->name ||
continue; (n->type != type && n->type != AUDIT_TYPE_UNKNOWN))
/* if we found a parent, make sure this one is a child of it */
if (found_parent && (n->name != found_parent->name))
continue; continue;
if (!strcmp(dname, n->name->name) || if (!strcmp(dname, n->name->name) ||
...@@ -1995,6 +1892,8 @@ void __audit_inode_child(const struct inode *parent, ...@@ -1995,6 +1892,8 @@ void __audit_inode_child(const struct inode *parent,
found_parent ? found_parent ?
found_parent->name_len : found_parent->name_len :
AUDIT_NAME_FULL)) { AUDIT_NAME_FULL)) {
if (n->type == AUDIT_TYPE_UNKNOWN)
n->type = type;
found_child = n; found_child = n;
break; break;
} }
...@@ -2019,10 +1918,10 @@ void __audit_inode_child(const struct inode *parent, ...@@ -2019,10 +1918,10 @@ void __audit_inode_child(const struct inode *parent,
if (found_parent) { if (found_parent) {
found_child->name = found_parent->name; found_child->name = found_parent->name;
found_child->name_len = AUDIT_NAME_FULL; found_child->name_len = AUDIT_NAME_FULL;
/* don't call __putname() */ found_child->name->refcnt++;
found_child->name_put = false;
} }
} }
if (inode) if (inode)
audit_copy_inode(found_child, dentry, inode); audit_copy_inode(found_child, dentry, inode);
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment