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:
Linus Torvalds 2015-02-17 15:27:47 -08:00
commit 05016b0f0a
7 changed files with 145 additions and 218 deletions

View file

@ -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