diff options
| author | Jeff Layton <jlayton@redhat.com> | 2012-10-10 15:25:23 -0400 | 
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-12 00:32:01 -0400 | 
| commit | bfcec7087458812f575d9022b2d151641f34ee84 (patch) | |
| tree | 6c0f7dd3b016992da8d113ceeaae404c6abc03a1 | |
| parent | 78e2e802a8519031e5858595070b39713e26340d (diff) | |
| download | olio-linux-3.10-bfcec7087458812f575d9022b2d151641f34ee84.tar.xz olio-linux-3.10-bfcec7087458812f575d9022b2d151641f34ee84.zip | |
audit: set the name_len in audit_inode for parent lookups
Currently, this gets set mostly by happenstance when we call into
audit_inode_child. While that might be a little more efficient, it seems
wrong. If the syscall ends up failing before audit_inode_child ever gets
called, then you'll have an audit_names record that shows the full path
but has the parent inode info attached.
Fix this by passing in a parent flag when we call audit_inode that gets
set to the value of LOOKUP_PARENT. We can then fix up the pathname for
the audit entry correctly from the get-go.
While we're at it, clean up the no-op macro for audit_inode in the
!CONFIG_AUDITSYSCALL case.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/namei.c | 14 | ||||
| -rw-r--r-- | fs/open.c | 4 | ||||
| -rw-r--r-- | fs/xattr.c | 8 | ||||
| -rw-r--r-- | include/linux/audit.h | 15 | ||||
| -rw-r--r-- | ipc/mqueue.c | 8 | ||||
| -rw-r--r-- | kernel/audit.h | 1 | ||||
| -rw-r--r-- | kernel/auditfilter.c | 30 | ||||
| -rw-r--r-- | kernel/auditsc.c | 41 | 
8 files changed, 87 insertions, 34 deletions
| diff --git a/fs/namei.c b/fs/namei.c index a7ad35c6680..6a92d988573 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1973,7 +1973,7 @@ static int do_path_lookup(int dfd, const char *name,  		retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);  	if (likely(!retval)) -		audit_inode(name, nd->path.dentry); +		audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);  	return retval;  } @@ -2648,7 +2648,7 @@ static int do_last(struct nameidata *nd, struct path *path,  		error = complete_walk(nd);  		if (error)  			return error; -		audit_inode(pathname, nd->path.dentry); +		audit_inode(pathname, nd->path.dentry, 0);  		if (open_flag & O_CREAT) {  			error = -EISDIR;  			goto out; @@ -2658,7 +2658,7 @@ static int do_last(struct nameidata *nd, struct path *path,  		error = complete_walk(nd);  		if (error)  			return error; -		audit_inode(pathname, dir); +		audit_inode(pathname, dir, 0);  		goto finish_open;  	} @@ -2687,7 +2687,7 @@ static int do_last(struct nameidata *nd, struct path *path,  		if (error)  			return error; -		audit_inode(pathname, dir); +		audit_inode(pathname, dir, 0);  		error = -EISDIR;  		/* trailing slashes? */  		if (nd->last.name[nd->last.len]) @@ -2717,7 +2717,7 @@ retry_lookup:  		    !S_ISREG(file->f_path.dentry->d_inode->i_mode))  			will_truncate = false; -		audit_inode(pathname, file->f_path.dentry); +		audit_inode(pathname, file->f_path.dentry, 0);  		goto opened;  	} @@ -2734,7 +2734,7 @@ retry_lookup:  	 * create/update audit record if it already exists.  	 */  	if (path->dentry->d_inode) -		audit_inode(pathname, path->dentry); +		audit_inode(pathname, path->dentry, 0);  	/*  	 * If atomic_open() acquired write access it is dropped now due to @@ -2799,7 +2799,7 @@ finish_lookup:  	error = -ENOTDIR;  	if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)  		goto out; -	audit_inode(pathname, nd->path.dentry); +	audit_inode(pathname, nd->path.dentry, 0);  finish_open:  	if (!S_ISREG(nd->inode->i_mode))  		will_truncate = false; diff --git a/fs/open.c b/fs/open.c index 44da0feeca2..a015437e153 100644 --- a/fs/open.c +++ b/fs/open.c @@ -478,7 +478,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode)  	file = fget(fd);  	if (file) { -		audit_inode(NULL, file->f_path.dentry); +		audit_inode(NULL, file->f_path.dentry, 0);  		err = chmod_common(&file->f_path, mode);  		fput(file);  	} @@ -588,7 +588,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)  	error = mnt_want_write_file(f.file);  	if (error)  		goto out_fput; -	audit_inode(NULL, f.file->f_path.dentry); +	audit_inode(NULL, f.file->f_path.dentry, 0);  	error = chown_common(&f.file->f_path, user, group);  	mnt_drop_write_file(f.file);  out_fput: diff --git a/fs/xattr.c b/fs/xattr.c index 1780f062dba..e164dddb8e9 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -412,7 +412,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,  	if (!f.file)  		return error;  	dentry = f.file->f_path.dentry; -	audit_inode(NULL, dentry); +	audit_inode(NULL, dentry, 0);  	error = mnt_want_write_file(f.file);  	if (!error) {  		error = setxattr(dentry, name, value, size, flags); @@ -507,7 +507,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,  	if (!f.file)  		return error; -	audit_inode(NULL, f.file->f_path.dentry); +	audit_inode(NULL, f.file->f_path.dentry, 0);  	error = getxattr(f.file->f_path.dentry, name, value, size);  	fdput(f);  	return error; @@ -586,7 +586,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)  	if (!f.file)  		return error; -	audit_inode(NULL, f.file->f_path.dentry); +	audit_inode(NULL, f.file->f_path.dentry, 0);  	error = listxattr(f.file->f_path.dentry, list, size);  	fdput(f);  	return error; @@ -655,7 +655,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)  	if (!f.file)  		return error;  	dentry = f.file->f_path.dentry; -	audit_inode(NULL, dentry); +	audit_inode(NULL, dentry, 0);  	error = mnt_want_write_file(f.file);  	if (!error) {  		error = removexattr(dentry, name); diff --git a/include/linux/audit.h b/include/linux/audit.h index 26408934ef2..b11f517dce0 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -456,6 +456,7 @@ extern int audit_classify_arch(int arch);  /* audit_names->type values */  #define	AUDIT_TYPE_UNKNOWN	0	/* we don't know yet */  #define	AUDIT_TYPE_NORMAL	1	/* a "normal" audit record */ +#define	AUDIT_TYPE_PARENT	2	/* a parent audit record */  #ifdef CONFIG_AUDITSYSCALL  /* These are defined in auditsc.c */ @@ -468,7 +469,8 @@ extern void __audit_syscall_entry(int arch,  extern void __audit_syscall_exit(int ret_success, long ret_value);  extern void __audit_getname(const char *name);  extern void audit_putname(const char *name); -extern void __audit_inode(const char *name, const struct dentry *dentry); +extern void __audit_inode(const char *name, const struct dentry *dentry, +				unsigned int parent);  extern void __audit_inode_child(const struct inode *parent,  				const struct dentry *dentry);  extern void __audit_seccomp(unsigned long syscall, long signr, int code); @@ -505,9 +507,10 @@ static inline void audit_getname(const char *name)  	if (unlikely(!audit_dummy_context()))  		__audit_getname(name);  } -static inline void audit_inode(const char *name, const struct dentry *dentry) { +static inline void audit_inode(const char *name, const struct dentry *dentry, +				unsigned int parent) {  	if (unlikely(!audit_dummy_context())) -		__audit_inode(name, dentry); +		__audit_inode(name, dentry, parent);  }  static inline void audit_inode_child(const struct inode *parent,  				     const struct dentry *dentry) { @@ -660,12 +663,14 @@ static inline void audit_getname(const char *name)  { }  static inline void audit_putname(const char *name)  { } -static inline void __audit_inode(const char *name, const struct dentry *dentry) +static inline void __audit_inode(const char *name, const struct dentry *dentry, +					unsigned int parent)  { }  static inline void __audit_inode_child(const struct inode *parent,  					const struct dentry *dentry)  { } -static inline void audit_inode(const char *name, const struct dentry *dentry) +static inline void audit_inode(const char *name, const struct dentry *dentry, +				unsigned int parent)  { }  static inline void audit_inode_child(const struct inode *parent,  				     const struct dentry *dentry) diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 6b97e2466fa..9553ed00604 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -804,7 +804,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,  	if (oflag & O_CREAT) {  		if (path.dentry->d_inode) {	/* entry already exists */ -			audit_inode(name, path.dentry); +			audit_inode(name, path.dentry, 0);  			if (oflag & O_EXCL) {  				error = -EEXIST;  				goto out; @@ -824,7 +824,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,  			error = -ENOENT;  			goto out;  		} -		audit_inode(name, path.dentry); +		audit_inode(name, path.dentry, 0);  		filp = do_open(&path, oflag);  	} @@ -978,7 +978,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,  		goto out_fput;  	}  	info = MQUEUE_I(inode); -	audit_inode(NULL, f.file->f_path.dentry); +	audit_inode(NULL, f.file->f_path.dentry, 0);  	if (unlikely(!(f.file->f_mode & FMODE_WRITE))) {  		ret = -EBADF; @@ -1094,7 +1094,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,  		goto out_fput;  	}  	info = MQUEUE_I(inode); -	audit_inode(NULL, f.file->f_path.dentry); +	audit_inode(NULL, f.file->f_path.dentry, 0);  	if (unlikely(!(f.file->f_mode & FMODE_READ))) {  		ret = -EBADF; diff --git a/kernel/audit.h b/kernel/audit.h index 9eb3d79482b..163b9a5d944 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -78,6 +78,7 @@ extern int audit_match_class(int class, unsigned syscall);  extern int audit_comparator(const u32 left, const u32 op, const u32 right);  extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right);  extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); +extern int parent_len(const char *path);  extern int audit_compare_dname_path(const char *dname, const char *path,  				    int *dirlen);  extern struct sk_buff *	    audit_make_reply(int pid, int seq, int type, diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index c4bcdbaf4d4..71bb13598df 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1298,6 +1298,36 @@ int audit_gid_comparator(kgid_t left, u32 op, kgid_t right)  	}  } +/** + * parent_len - find the length of the parent portion of a pathname + * @path: pathname of which to determine length + */ +int parent_len(const char *path) +{ +	int plen; +	const char *p; + +	plen = strlen(path); + +	if (plen == 0) +		return plen; + +	/* disregard trailing slashes */ +	p = path + plen - 1; +	while ((*p == '/') && (p > path)) +		p--; + +	/* walk backward until we find the next slash or hit beginning */ +	while ((*p != '/') && (p > path)) +		p--; + +	/* did we find a slash? Then increment to include it in path */ +	if (*p == '/') +		p++; + +	return p - path; +} +  /* Compare given dentry name with last component in given path,   * return of 0 indicates a match. */  int audit_compare_dname_path(const char *dname, const char *path, diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 19b232f86d7..b87b28947ac 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2135,13 +2135,13 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent  }  /** - * audit_inode - store the inode and device from a lookup + * __audit_inode - store the inode and device from a lookup   * @name: name being audited   * @dentry: dentry being audited - * - * Called from fs/namei.c:path_lookup(). + * @parent: does this dentry represent the parent?   */ -void __audit_inode(const char *name, const struct dentry *dentry) +void __audit_inode(const char *name, const struct dentry *dentry, +		   unsigned int parent)  {  	struct audit_context *context = current->audit_context;  	const struct inode *inode = dentry->d_inode; @@ -2154,19 +2154,38 @@ void __audit_inode(const char *name, const struct dentry *dentry)  		goto out_alloc;  	list_for_each_entry_reverse(n, &context->names_list, list) { -		if (n->name == name) -			goto out; +		/* does the name pointer match? */ +		if (n->name != name) +			continue; + +		/* match the correct record type */ +		if (parent) { +			if (n->type == AUDIT_TYPE_PARENT || +			    n->type == AUDIT_TYPE_UNKNOWN) +				goto out; +		} else { +			if (n->type != AUDIT_TYPE_PARENT) +				goto out; +		}  	}  out_alloc: -	/* unable to find the name from a previous getname() */ +	/* unable to find the name from a previous getname(). Allocate a new +	 * anonymous entry. +	 */  	n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);  	if (!n)  		return;  out: +	if (parent) { +		n->name_len = n->name ? parent_len(n->name) : AUDIT_NAME_FULL; +		n->type = AUDIT_TYPE_PARENT; +	} else { +		n->name_len = AUDIT_NAME_FULL; +		n->type = AUDIT_TYPE_NORMAL; +	}  	handle_path(dentry);  	audit_copy_inode(n, dentry, inode); -	n->type = AUDIT_TYPE_NORMAL;  }  /** @@ -2190,7 +2209,6 @@ void __audit_inode_child(const struct inode *parent,  	const struct inode *inode = dentry->d_inode;  	const char *dname = dentry->d_name.name;  	struct audit_names *n; -	int dirlen = 0;  	if (!context->in_syscall)  		return; @@ -2204,8 +2222,7 @@ void __audit_inode_child(const struct inode *parent,  			continue;  		if (n->ino == parent->i_ino && -		    !audit_compare_dname_path(dname, n->name, &dirlen)) { -			n->name_len = dirlen; /* update parent data in place */ +		    !audit_compare_dname_path(dname, n->name, NULL)) {  			found_parent = n->name;  			goto add_names;  		} @@ -2218,7 +2235,7 @@ void __audit_inode_child(const struct inode *parent,  		/* strcmp() is the more likely scenario */  		if (!strcmp(dname, n->name) || -		     !audit_compare_dname_path(dname, n->name, &dirlen)) { +		     !audit_compare_dname_path(dname, n->name, NULL)) {  			if (inode)  				audit_copy_inode(n, dentry, inode);  			else |