mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-19 13:11:14 +00:00
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
7 changed files with 145 additions and 218 deletions
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…
Add table
Add a link
Reference in a new issue