mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-04-14 20:47:34 +07: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
10
fs/exec.c
10
fs/exec.c
@ -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);
|
||||||
|
|
||||||
|
143
fs/namei.c
143
fs/namei.c
@ -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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
final_putname(result);
|
putname(result);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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,
|
|||||||
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
|
|||||||
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
|
|||||||
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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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,
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
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,
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
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 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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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 {
|
|||||||
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);
|
|||||||
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);
|
|||||||
|
|
||||||
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 @@
|
|||||||
#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 {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 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 {
|
|||||||
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 {
|
|||||||
};
|
};
|
||||||
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;
|
||||||
|
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;
|
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,
|
|||||||
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,8 +1708,10 @@ __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)
|
|||||||
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)
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
/* 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,
|
|||||||
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,
|
|||||||
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
|
||||||
|
Loading…
Reference in New Issue
Block a user