mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	[PATCH] log more info for directory entry change events
When an audit event involves changes to a directory entry, include
a PATH record for the directory itself.  A few other notable changes:
    - fixed audit_inode_child() hooks in fsnotify_move()
    - removed unused flags arg from audit_inode()
    - added audit log routines for logging a portion of a string
Here's some sample output.
before patch:
type=SYSCALL msg=audit(1149821605.320:26): arch=40000003 syscall=39 success=yes exit=0 a0=bf8d3c7c a1=1ff a2=804e1b8 a3=bf8d3c7c items=1 ppid=739 pid=800 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=ttyS0 comm="mkdir" exe="/bin/mkdir" subj=root:system_r:unconfined_t:s0-s0:c0.c255
type=CWD msg=audit(1149821605.320:26):  cwd="/root"
type=PATH msg=audit(1149821605.320:26): item=0 name="foo" parent=164068 inode=164010 dev=03:00 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=root:object_r:user_home_t:s0
after patch:
type=SYSCALL msg=audit(1149822032.332:24): arch=40000003 syscall=39 success=yes exit=0 a0=bfdd9c7c a1=1ff a2=804e1b8 a3=bfdd9c7c items=2 ppid=714 pid=777 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=ttyS0 comm="mkdir" exe="/bin/mkdir" subj=root:system_r:unconfined_t:s0-s0:c0.c255
type=CWD msg=audit(1149822032.332:24):  cwd="/root"
type=PATH msg=audit(1149822032.332:24): item=0 name="/root" inode=164068 dev=03:00 mode=040750 ouid=0 ogid=0 rdev=00:00 obj=root:object_r:user_home_dir_t:s0
type=PATH msg=audit(1149822032.332:24): item=1 name="foo" inode=164010 dev=03:00 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=root:object_r:user_home_t:s0
Signed-off-by: Amy Griffis <amy.griffis@hp.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
			
			
This commit is contained in:
		
							parent
							
								
									6a2bceec0e
								
							
						
					
					
						commit
						9c937dcc71
					
				
					 9 changed files with 141 additions and 73 deletions
				
			
		| 
						 | 
					@ -1127,7 +1127,7 @@ static int fastcall do_path_lookup(int dfd, const char *name,
 | 
				
			||||||
	if (likely(retval == 0)) {
 | 
						if (likely(retval == 0)) {
 | 
				
			||||||
		if (unlikely(current->audit_context && nd && nd->dentry &&
 | 
							if (unlikely(current->audit_context && nd && nd->dentry &&
 | 
				
			||||||
				nd->dentry->d_inode))
 | 
									nd->dentry->d_inode))
 | 
				
			||||||
		audit_inode(name, nd->dentry->d_inode, flags);
 | 
							audit_inode(name, nd->dentry->d_inode);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
out_fail:
 | 
					out_fail:
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -633,7 +633,7 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
 | 
				
			||||||
	dentry = file->f_dentry;
 | 
						dentry = file->f_dentry;
 | 
				
			||||||
	inode = dentry->d_inode;
 | 
						inode = dentry->d_inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audit_inode(NULL, inode, 0);
 | 
						audit_inode(NULL, inode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = -EROFS;
 | 
						err = -EROFS;
 | 
				
			||||||
	if (IS_RDONLY(inode))
 | 
						if (IS_RDONLY(inode))
 | 
				
			||||||
| 
						 | 
					@ -786,7 +786,7 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
 | 
				
			||||||
	if (file) {
 | 
						if (file) {
 | 
				
			||||||
		struct dentry * dentry;
 | 
							struct dentry * dentry;
 | 
				
			||||||
		dentry = file->f_dentry;
 | 
							dentry = file->f_dentry;
 | 
				
			||||||
		audit_inode(NULL, dentry->d_inode, 0);
 | 
							audit_inode(NULL, dentry->d_inode);
 | 
				
			||||||
		error = chown_common(dentry, user, group);
 | 
							error = chown_common(dentry, user, group);
 | 
				
			||||||
		fput(file);
 | 
							fput(file);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -242,7 +242,7 @@ sys_fsetxattr(int fd, char __user *name, void __user *value,
 | 
				
			||||||
	if (!f)
 | 
						if (!f)
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	dentry = f->f_dentry;
 | 
						dentry = f->f_dentry;
 | 
				
			||||||
	audit_inode(NULL, dentry->d_inode, 0);
 | 
						audit_inode(NULL, dentry->d_inode);
 | 
				
			||||||
	error = setxattr(dentry, name, value, size, flags);
 | 
						error = setxattr(dentry, name, value, size, flags);
 | 
				
			||||||
	fput(f);
 | 
						fput(f);
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
| 
						 | 
					@ -469,7 +469,7 @@ sys_fremovexattr(int fd, char __user *name)
 | 
				
			||||||
	if (!f)
 | 
						if (!f)
 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
	dentry = f->f_dentry;
 | 
						dentry = f->f_dentry;
 | 
				
			||||||
	audit_inode(NULL, dentry->d_inode, 0);
 | 
						audit_inode(NULL, dentry->d_inode);
 | 
				
			||||||
	error = removexattr(dentry, name);
 | 
						error = removexattr(dentry, name);
 | 
				
			||||||
	fput(f);
 | 
						fput(f);
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -310,7 +310,7 @@ extern void audit_syscall_entry(int arch,
 | 
				
			||||||
extern void audit_syscall_exit(int failed, long return_code);
 | 
					extern void audit_syscall_exit(int failed, long return_code);
 | 
				
			||||||
extern void __audit_getname(const char *name);
 | 
					extern void __audit_getname(const char *name);
 | 
				
			||||||
extern void audit_putname(const char *name);
 | 
					extern void audit_putname(const char *name);
 | 
				
			||||||
extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags);
 | 
					extern void __audit_inode(const char *name, const struct inode *inode);
 | 
				
			||||||
extern void __audit_inode_child(const char *dname, const struct inode *inode,
 | 
					extern void __audit_inode_child(const char *dname, const struct inode *inode,
 | 
				
			||||||
				unsigned long pino);
 | 
									unsigned long pino);
 | 
				
			||||||
static inline void audit_getname(const char *name)
 | 
					static inline void audit_getname(const char *name)
 | 
				
			||||||
| 
						 | 
					@ -318,10 +318,9 @@ static inline void audit_getname(const char *name)
 | 
				
			||||||
	if (unlikely(current->audit_context))
 | 
						if (unlikely(current->audit_context))
 | 
				
			||||||
		__audit_getname(name);
 | 
							__audit_getname(name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline void audit_inode(const char *name, const struct inode *inode,
 | 
					static inline void audit_inode(const char *name, const struct inode *inode) {
 | 
				
			||||||
			       unsigned flags) {
 | 
					 | 
				
			||||||
	if (unlikely(current->audit_context))
 | 
						if (unlikely(current->audit_context))
 | 
				
			||||||
		__audit_inode(name, inode, flags);
 | 
							__audit_inode(name, inode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline void audit_inode_child(const char *dname, 
 | 
					static inline void audit_inode_child(const char *dname, 
 | 
				
			||||||
				     const struct inode *inode, 
 | 
									     const struct inode *inode, 
 | 
				
			||||||
| 
						 | 
					@ -398,9 +397,9 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
 | 
				
			||||||
#define audit_syscall_exit(f,r) do { ; } while (0)
 | 
					#define audit_syscall_exit(f,r) do { ; } while (0)
 | 
				
			||||||
#define audit_getname(n) do { ; } while (0)
 | 
					#define audit_getname(n) do { ; } while (0)
 | 
				
			||||||
#define audit_putname(n) do { ; } while (0)
 | 
					#define audit_putname(n) do { ; } while (0)
 | 
				
			||||||
#define __audit_inode(n,i,f) do { ; } while (0)
 | 
					#define __audit_inode(n,i) do { ; } while (0)
 | 
				
			||||||
#define __audit_inode_child(d,i,p) do { ; } while (0)
 | 
					#define __audit_inode_child(d,i,p) do { ; } while (0)
 | 
				
			||||||
#define audit_inode(n,i,f) do { ; } while (0)
 | 
					#define audit_inode(n,i) do { ; } while (0)
 | 
				
			||||||
#define audit_inode_child(d,i,p) do { ; } while (0)
 | 
					#define audit_inode_child(d,i,p) do { ; } while (0)
 | 
				
			||||||
#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
 | 
					#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
 | 
				
			||||||
#define audit_get_loginuid(c) ({ -1; })
 | 
					#define audit_get_loginuid(c) ({ -1; })
 | 
				
			||||||
| 
						 | 
					@ -435,6 +434,9 @@ extern void		    audit_log_hex(struct audit_buffer *ab,
 | 
				
			||||||
					  size_t len);
 | 
										  size_t len);
 | 
				
			||||||
extern const char *	    audit_log_untrustedstring(struct audit_buffer *ab,
 | 
					extern const char *	    audit_log_untrustedstring(struct audit_buffer *ab,
 | 
				
			||||||
						      const char *string);
 | 
											      const char *string);
 | 
				
			||||||
 | 
					extern const char *	    audit_log_n_untrustedstring(struct audit_buffer *ab,
 | 
				
			||||||
 | 
												size_t n,
 | 
				
			||||||
 | 
												const char *string);
 | 
				
			||||||
extern void		    audit_log_d_path(struct audit_buffer *ab,
 | 
					extern void		    audit_log_d_path(struct audit_buffer *ab,
 | 
				
			||||||
					     const char *prefix,
 | 
										     const char *prefix,
 | 
				
			||||||
					     struct dentry *dentry,
 | 
										     struct dentry *dentry,
 | 
				
			||||||
| 
						 | 
					@ -452,6 +454,7 @@ extern int  audit_receive_filter(int type, int pid, int uid, int seq,
 | 
				
			||||||
#define audit_log_end(b) do { ; } while (0)
 | 
					#define audit_log_end(b) do { ; } while (0)
 | 
				
			||||||
#define audit_log_hex(a,b,l) do { ; } while (0)
 | 
					#define audit_log_hex(a,b,l) do { ; } while (0)
 | 
				
			||||||
#define audit_log_untrustedstring(a,s) do { ; } while (0)
 | 
					#define audit_log_untrustedstring(a,s) do { ; } while (0)
 | 
				
			||||||
 | 
					#define audit_log_n_untrustedstring(a,n,s) do { ; } while (0)
 | 
				
			||||||
#define audit_log_d_path(b,p,d,v) do { ; } while (0)
 | 
					#define audit_log_d_path(b,p,d,v) do { ; } while (0)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,8 +67,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
 | 
				
			||||||
	if (source) {
 | 
						if (source) {
 | 
				
			||||||
		inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
 | 
							inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	audit_inode_child(old_name, source, old_dir->i_ino);
 | 
						audit_inode_child(new_name, source, new_dir->i_ino);
 | 
				
			||||||
	audit_inode_child(new_name, target, new_dir->i_ino);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1051,20 +1051,53 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
 | 
				
			||||||
	skb_put(skb, len << 1); /* new string is twice the old string */
 | 
						skb_put(skb, len << 1); /* new string is twice the old string */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Format a string of no more than slen characters into the audit buffer,
 | 
				
			||||||
 | 
					 * enclosed in quote marks.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
 | 
				
			||||||
 | 
								       const char *string)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int avail, new_len;
 | 
				
			||||||
 | 
						unsigned char *ptr;
 | 
				
			||||||
 | 
						struct sk_buff *skb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(!ab->skb);
 | 
				
			||||||
 | 
						skb = ab->skb;
 | 
				
			||||||
 | 
						avail = skb_tailroom(skb);
 | 
				
			||||||
 | 
						new_len = slen + 3;	/* enclosing quotes + null terminator */
 | 
				
			||||||
 | 
						if (new_len > avail) {
 | 
				
			||||||
 | 
							avail = audit_expand(ab, new_len);
 | 
				
			||||||
 | 
							if (!avail)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ptr = skb->tail;
 | 
				
			||||||
 | 
						*ptr++ = '"';
 | 
				
			||||||
 | 
						memcpy(ptr, string, slen);
 | 
				
			||||||
 | 
						ptr += slen;
 | 
				
			||||||
 | 
						*ptr++ = '"';
 | 
				
			||||||
 | 
						*ptr = 0;
 | 
				
			||||||
 | 
						skb_put(skb, slen + 2);	/* don't include null terminator */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * audit_log_unstrustedstring - log a string that may contain random characters
 | 
					 * audit_log_n_unstrustedstring - log a string that may contain random characters
 | 
				
			||||||
 * @ab: audit_buffer
 | 
					 * @ab: audit_buffer
 | 
				
			||||||
 | 
					 * @len: lenth of string (not including trailing null)
 | 
				
			||||||
 * @string: string to be logged
 | 
					 * @string: string to be logged
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This code will escape a string that is passed to it if the string
 | 
					 * This code will escape a string that is passed to it if the string
 | 
				
			||||||
 * contains a control character, unprintable character, double quote mark,
 | 
					 * contains a control character, unprintable character, double quote mark,
 | 
				
			||||||
 * or a space. Unescaped strings will start and end with a double quote mark.
 | 
					 * or a space. Unescaped strings will start and end with a double quote mark.
 | 
				
			||||||
 * Strings that are escaped are printed in hex (2 digits per char).
 | 
					 * Strings that are escaped are printed in hex (2 digits per char).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The caller specifies the number of characters in the string to log, which may
 | 
				
			||||||
 | 
					 * or may not be the entire string.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
 | 
					const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
 | 
				
			||||||
 | 
										const char *string)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const unsigned char *p = string;
 | 
						const unsigned char *p = string;
 | 
				
			||||||
	size_t len = strlen(string);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (*p) {
 | 
						while (*p) {
 | 
				
			||||||
		if (*p == '"' || *p < 0x21 || *p > 0x7f) {
 | 
							if (*p == '"' || *p < 0x21 || *p > 0x7f) {
 | 
				
			||||||
| 
						 | 
					@ -1073,10 +1106,23 @@ const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *strin
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		p++;
 | 
							p++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	audit_log_format(ab, "\"%s\"", string);
 | 
						audit_log_n_string(ab, len, string);
 | 
				
			||||||
	return p + 1;
 | 
						return p + 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * audit_log_unstrustedstring - log a string that may contain random characters
 | 
				
			||||||
 | 
					 * @ab: audit_buffer
 | 
				
			||||||
 | 
					 * @string: string to be logged
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Same as audit_log_n_unstrustedstring(), except that strlen is used to
 | 
				
			||||||
 | 
					 * determine string length.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return audit_log_n_untrustedstring(ab, strlen(string), string);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This is a helper-function to print the escaped d_path */
 | 
					/* This is a helper-function to print the escaped d_path */
 | 
				
			||||||
void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
 | 
					void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
 | 
				
			||||||
		      struct dentry *dentry, struct vfsmount *vfsmnt)
 | 
							      struct dentry *dentry, struct vfsmount *vfsmnt)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,7 +104,8 @@ static inline int audit_hash_ino(u32 ino)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
 | 
					extern int audit_comparator(const u32 left, const u32 op, const u32 right);
 | 
				
			||||||
extern int audit_compare_dname_path(const char *dname, 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,
 | 
					extern struct sk_buff *	    audit_make_reply(int pid, int seq, int type,
 | 
				
			||||||
					     int done, int multi,
 | 
										     int done, int multi,
 | 
				
			||||||
					     void *payload, int size);
 | 
										     void *payload, int size);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -787,7 +787,7 @@ static void audit_update_watch(struct audit_parent *parent,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&audit_filter_mutex);
 | 
						mutex_lock(&audit_filter_mutex);
 | 
				
			||||||
	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
 | 
						list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
 | 
				
			||||||
		if (audit_compare_dname_path(dname, owatch->path))
 | 
							if (audit_compare_dname_path(dname, owatch->path, NULL))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* If the update involves invalidating rules, do the inode-based
 | 
							/* If the update involves invalidating rules, do the inode-based
 | 
				
			||||||
| 
						 | 
					@ -1387,7 +1387,8 @@ int audit_comparator(const u32 left, const u32 op, const u32 right)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Compare given dentry name with last component in given path,
 | 
					/* Compare given dentry name with last component in given path,
 | 
				
			||||||
 * return of 0 indicates a match. */
 | 
					 * return of 0 indicates a match. */
 | 
				
			||||||
int audit_compare_dname_path(const char *dname, const char *path)
 | 
					int audit_compare_dname_path(const char *dname, const char *path,
 | 
				
			||||||
 | 
								     int *dirlen)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int dlen, plen;
 | 
						int dlen, plen;
 | 
				
			||||||
	const char *p;
 | 
						const char *p;
 | 
				
			||||||
| 
						 | 
					@ -1416,6 +1417,9 @@ int audit_compare_dname_path(const char *dname, const char *path)
 | 
				
			||||||
			p++;
 | 
								p++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* return length of path's directory component */
 | 
				
			||||||
 | 
						if (dirlen)
 | 
				
			||||||
 | 
							*dirlen = p - path;
 | 
				
			||||||
	return strncmp(p, dname, dlen);
 | 
						return strncmp(p, dname, dlen);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										121
									
								
								kernel/auditsc.c
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								kernel/auditsc.c
									
									
									
									
									
								
							| 
						 | 
					@ -82,6 +82,9 @@ extern int audit_enabled;
 | 
				
			||||||
 * path_lookup. */
 | 
					 * path_lookup. */
 | 
				
			||||||
#define AUDIT_NAMES_RESERVED 7
 | 
					#define AUDIT_NAMES_RESERVED 7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Indicates that audit should log the full pathname. */
 | 
				
			||||||
 | 
					#define AUDIT_NAME_FULL -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 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
 | 
				
			||||||
 * we don't let putname() free it (instead we free all of the saved
 | 
					 * we don't let putname() free it (instead we free all of the saved
 | 
				
			||||||
 * pointers at syscall exit time).
 | 
					 * pointers at syscall exit time).
 | 
				
			||||||
| 
						 | 
					@ -89,8 +92,9 @@ extern int audit_enabled;
 | 
				
			||||||
 * 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. */
 | 
				
			||||||
struct audit_names {
 | 
					struct audit_names {
 | 
				
			||||||
	const char	*name;
 | 
						const char	*name;
 | 
				
			||||||
 | 
						int		name_len;	/* number of name's characters to log */
 | 
				
			||||||
 | 
						unsigned	name_put;	/* call __putname() for this name */
 | 
				
			||||||
	unsigned long	ino;
 | 
						unsigned long	ino;
 | 
				
			||||||
	unsigned long	pino;
 | 
					 | 
				
			||||||
	dev_t		dev;
 | 
						dev_t		dev;
 | 
				
			||||||
	umode_t		mode;
 | 
						umode_t		mode;
 | 
				
			||||||
	uid_t		uid;
 | 
						uid_t		uid;
 | 
				
			||||||
| 
						 | 
					@ -296,12 +300,10 @@ static int audit_filter_rules(struct task_struct *tsk,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case AUDIT_INODE:
 | 
							case AUDIT_INODE:
 | 
				
			||||||
			if (name)
 | 
								if (name)
 | 
				
			||||||
				result = (name->ino == f->val ||
 | 
									result = (name->ino == f->val);
 | 
				
			||||||
					  name->pino == f->val);
 | 
					 | 
				
			||||||
			else if (ctx) {
 | 
								else if (ctx) {
 | 
				
			||||||
				for (j = 0; j < ctx->name_count; j++) {
 | 
									for (j = 0; j < ctx->name_count; j++) {
 | 
				
			||||||
					if (audit_comparator(ctx->names[j].ino, f->op, f->val) ||
 | 
										if (audit_comparator(ctx->names[j].ino, f->op, f->val)) {
 | 
				
			||||||
					    audit_comparator(ctx->names[j].pino, f->op, f->val)) {
 | 
					 | 
				
			||||||
						++result;
 | 
											++result;
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
| 
						 | 
					@ -311,8 +313,7 @@ static int audit_filter_rules(struct task_struct *tsk,
 | 
				
			||||||
		case AUDIT_WATCH:
 | 
							case AUDIT_WATCH:
 | 
				
			||||||
			if (name && rule->watch->ino != (unsigned long)-1)
 | 
								if (name && rule->watch->ino != (unsigned long)-1)
 | 
				
			||||||
				result = (name->dev == rule->watch->dev &&
 | 
									result = (name->dev == rule->watch->dev &&
 | 
				
			||||||
					  (name->ino == rule->watch->ino ||
 | 
										  name->ino == rule->watch->ino);
 | 
				
			||||||
					   name->pino == rule->watch->ino));
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case AUDIT_LOGINUID:
 | 
							case AUDIT_LOGINUID:
 | 
				
			||||||
			result = 0;
 | 
								result = 0;
 | 
				
			||||||
| 
						 | 
					@ -526,7 +527,7 @@ static inline void audit_free_names(struct audit_context *context)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < context->name_count; i++) {
 | 
						for (i = 0; i < context->name_count; i++) {
 | 
				
			||||||
		if (context->names[i].name)
 | 
							if (context->names[i].name && context->names[i].name_put)
 | 
				
			||||||
			__putname(context->names[i].name);
 | 
								__putname(context->names[i].name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	context->name_count = 0;
 | 
						context->name_count = 0;
 | 
				
			||||||
| 
						 | 
					@ -850,8 +851,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0; i < context->name_count; i++) {
 | 
						for (i = 0; i < context->name_count; i++) {
 | 
				
			||||||
		unsigned long ino  = context->names[i].ino;
 | 
							struct audit_names *n = &context->names[i];
 | 
				
			||||||
		unsigned long pino = context->names[i].pino;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
 | 
							ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
 | 
				
			||||||
		if (!ab)
 | 
							if (!ab)
 | 
				
			||||||
| 
						 | 
					@ -859,33 +859,47 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		audit_log_format(ab, "item=%d", i);
 | 
							audit_log_format(ab, "item=%d", i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		audit_log_format(ab, " name=");
 | 
							if (n->name) {
 | 
				
			||||||
		if (context->names[i].name)
 | 
								switch(n->name_len) {
 | 
				
			||||||
			audit_log_untrustedstring(ab, context->names[i].name);
 | 
								case AUDIT_NAME_FULL:
 | 
				
			||||||
		else
 | 
									/* log the full path */
 | 
				
			||||||
			audit_log_format(ab, "(null)");
 | 
									audit_log_format(ab, " name=");
 | 
				
			||||||
 | 
									audit_log_untrustedstring(ab, n->name);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 0:
 | 
				
			||||||
 | 
									/* name was specified as a relative path and the
 | 
				
			||||||
 | 
									 * directory component is the cwd */
 | 
				
			||||||
 | 
									audit_log_d_path(ab, " name=", context->pwd,
 | 
				
			||||||
 | 
											 context->pwdmnt);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									/* log the name's directory component */
 | 
				
			||||||
 | 
									audit_log_format(ab, " name=");
 | 
				
			||||||
 | 
									audit_log_n_untrustedstring(ab, n->name_len,
 | 
				
			||||||
 | 
												    n->name);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								audit_log_format(ab, " name=(null)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (pino != (unsigned long)-1)
 | 
							if (n->ino != (unsigned long)-1) {
 | 
				
			||||||
			audit_log_format(ab, " parent=%lu",  pino);
 | 
								audit_log_format(ab, " inode=%lu"
 | 
				
			||||||
		if (ino != (unsigned long)-1)
 | 
										 " dev=%02x:%02x mode=%#o"
 | 
				
			||||||
			audit_log_format(ab, " inode=%lu",  ino);
 | 
										 " ouid=%u ogid=%u rdev=%02x:%02x",
 | 
				
			||||||
		if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1))
 | 
										 n->ino,
 | 
				
			||||||
			audit_log_format(ab, " dev=%02x:%02x mode=%#o" 
 | 
										 MAJOR(n->dev),
 | 
				
			||||||
					 " ouid=%u ogid=%u rdev=%02x:%02x", 
 | 
										 MINOR(n->dev),
 | 
				
			||||||
					 MAJOR(context->names[i].dev), 
 | 
										 n->mode,
 | 
				
			||||||
					 MINOR(context->names[i].dev), 
 | 
										 n->uid,
 | 
				
			||||||
					 context->names[i].mode, 
 | 
										 n->gid,
 | 
				
			||||||
					 context->names[i].uid, 
 | 
										 MAJOR(n->rdev),
 | 
				
			||||||
					 context->names[i].gid, 
 | 
										 MINOR(n->rdev));
 | 
				
			||||||
					 MAJOR(context->names[i].rdev), 
 | 
							}
 | 
				
			||||||
					 MINOR(context->names[i].rdev));
 | 
							if (n->osid != 0) {
 | 
				
			||||||
		if (context->names[i].osid != 0) {
 | 
					 | 
				
			||||||
			char *ctx = NULL;
 | 
								char *ctx = NULL;
 | 
				
			||||||
			u32 len;
 | 
								u32 len;
 | 
				
			||||||
			if (selinux_ctxid_to_string(
 | 
								if (selinux_ctxid_to_string(
 | 
				
			||||||
				context->names[i].osid, &ctx, &len)) {
 | 
									n->osid, &ctx, &len)) {
 | 
				
			||||||
				audit_log_format(ab, " osid=%u",
 | 
									audit_log_format(ab, " osid=%u", n->osid);
 | 
				
			||||||
						context->names[i].osid);
 | 
					 | 
				
			||||||
				call_panic = 2;
 | 
									call_panic = 2;
 | 
				
			||||||
			} else
 | 
								} else
 | 
				
			||||||
				audit_log_format(ab, " obj=%s", ctx);
 | 
									audit_log_format(ab, " obj=%s", ctx);
 | 
				
			||||||
| 
						 | 
					@ -1075,6 +1089,8 @@ void __audit_getname(const char *name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	BUG_ON(context->name_count >= AUDIT_NAMES);
 | 
						BUG_ON(context->name_count >= AUDIT_NAMES);
 | 
				
			||||||
	context->names[context->name_count].name = name;
 | 
						context->names[context->name_count].name = name;
 | 
				
			||||||
 | 
						context->names[context->name_count].name_len = AUDIT_NAME_FULL;
 | 
				
			||||||
 | 
						context->names[context->name_count].name_put = 1;
 | 
				
			||||||
	context->names[context->name_count].ino  = (unsigned long)-1;
 | 
						context->names[context->name_count].ino  = (unsigned long)-1;
 | 
				
			||||||
	++context->name_count;
 | 
						++context->name_count;
 | 
				
			||||||
	if (!context->pwd) {
 | 
						if (!context->pwd) {
 | 
				
			||||||
| 
						 | 
					@ -1141,11 +1157,10 @@ static void audit_inode_context(int idx, const struct inode *inode)
 | 
				
			||||||
 * 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
 | 
				
			||||||
 * @inode: inode being audited
 | 
					 * @inode: inode being audited
 | 
				
			||||||
 * @flags: lookup flags (as used in path_lookup())
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Called from fs/namei.c:path_lookup().
 | 
					 * Called from fs/namei.c:path_lookup().
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void __audit_inode(const char *name, const struct inode *inode, unsigned flags)
 | 
					void __audit_inode(const char *name, const struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int idx;
 | 
						int idx;
 | 
				
			||||||
	struct audit_context *context = current->audit_context;
 | 
						struct audit_context *context = current->audit_context;
 | 
				
			||||||
| 
						 | 
					@ -1171,20 +1186,13 @@ void __audit_inode(const char *name, const struct inode *inode, unsigned flags)
 | 
				
			||||||
		++context->ino_count;
 | 
							++context->ino_count;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						context->names[idx].ino   = inode->i_ino;
 | 
				
			||||||
	context->names[idx].dev	  = inode->i_sb->s_dev;
 | 
						context->names[idx].dev	  = inode->i_sb->s_dev;
 | 
				
			||||||
	context->names[idx].mode  = inode->i_mode;
 | 
						context->names[idx].mode  = inode->i_mode;
 | 
				
			||||||
	context->names[idx].uid   = inode->i_uid;
 | 
						context->names[idx].uid   = inode->i_uid;
 | 
				
			||||||
	context->names[idx].gid   = inode->i_gid;
 | 
						context->names[idx].gid   = inode->i_gid;
 | 
				
			||||||
	context->names[idx].rdev  = inode->i_rdev;
 | 
						context->names[idx].rdev  = inode->i_rdev;
 | 
				
			||||||
	audit_inode_context(idx, inode);
 | 
						audit_inode_context(idx, inode);
 | 
				
			||||||
	if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && 
 | 
					 | 
				
			||||||
	    (strcmp(name, ".") != 0)) {
 | 
					 | 
				
			||||||
		context->names[idx].ino   = (unsigned long)-1;
 | 
					 | 
				
			||||||
		context->names[idx].pino  = inode->i_ino;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		context->names[idx].ino   = inode->i_ino;
 | 
					 | 
				
			||||||
		context->names[idx].pino  = (unsigned long)-1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -1206,34 +1214,40 @@ void __audit_inode_child(const char *dname, const struct inode *inode,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int idx;
 | 
						int idx;
 | 
				
			||||||
	struct audit_context *context = current->audit_context;
 | 
						struct audit_context *context = current->audit_context;
 | 
				
			||||||
 | 
						const char *found_name = NULL;
 | 
				
			||||||
 | 
						int dirlen = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!context->in_syscall)
 | 
						if (!context->in_syscall)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* determine matching parent */
 | 
						/* determine matching parent */
 | 
				
			||||||
	if (!dname)
 | 
						if (!dname)
 | 
				
			||||||
		goto no_match;
 | 
							goto update_context;
 | 
				
			||||||
	for (idx = 0; idx < context->name_count; idx++)
 | 
						for (idx = 0; idx < context->name_count; idx++)
 | 
				
			||||||
		if (context->names[idx].pino == pino) {
 | 
							if (context->names[idx].ino == pino) {
 | 
				
			||||||
			const char *name = context->names[idx].name;
 | 
								const char *name = context->names[idx].name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!name)
 | 
								if (!name)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (audit_compare_dname_path(dname, name) == 0)
 | 
								if (audit_compare_dname_path(dname, name, &dirlen) == 0) {
 | 
				
			||||||
				goto update_context;
 | 
									context->names[idx].name_len = dirlen;
 | 
				
			||||||
 | 
									found_name = name;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
no_match:
 | 
					update_context:
 | 
				
			||||||
	/* catch-all in case match not found */
 | 
					 | 
				
			||||||
	idx = context->name_count++;
 | 
						idx = context->name_count++;
 | 
				
			||||||
	context->names[idx].name  = NULL;
 | 
					 | 
				
			||||||
	context->names[idx].pino  = pino;
 | 
					 | 
				
			||||||
#if AUDIT_DEBUG
 | 
					#if AUDIT_DEBUG
 | 
				
			||||||
	context->ino_count++;
 | 
						context->ino_count++;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						/* Re-use the name belonging to the slot for a matching parent directory.
 | 
				
			||||||
 | 
						 * All names for this context are relinquished in audit_free_names() */
 | 
				
			||||||
 | 
						context->names[idx].name = found_name;
 | 
				
			||||||
 | 
						context->names[idx].name_len = AUDIT_NAME_FULL;
 | 
				
			||||||
 | 
						context->names[idx].name_put = 0;	/* don't call __putname() */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
update_context:
 | 
					 | 
				
			||||||
	if (inode) {
 | 
						if (inode) {
 | 
				
			||||||
		context->names[idx].ino   = inode->i_ino;
 | 
							context->names[idx].ino   = inode->i_ino;
 | 
				
			||||||
		context->names[idx].dev	  = inode->i_sb->s_dev;
 | 
							context->names[idx].dev	  = inode->i_sb->s_dev;
 | 
				
			||||||
| 
						 | 
					@ -1242,7 +1256,8 @@ void __audit_inode_child(const char *dname, const struct inode *inode,
 | 
				
			||||||
		context->names[idx].gid   = inode->i_gid;
 | 
							context->names[idx].gid   = inode->i_gid;
 | 
				
			||||||
		context->names[idx].rdev  = inode->i_rdev;
 | 
							context->names[idx].rdev  = inode->i_rdev;
 | 
				
			||||||
		audit_inode_context(idx, inode);
 | 
							audit_inode_context(idx, inode);
 | 
				
			||||||
	}
 | 
						} else
 | 
				
			||||||
 | 
							context->names[idx].ino   = (unsigned long)-1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue