aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2012-10-10 15:25:23 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-12 00:32:01 -0400
commitbfcec7087458812f575d9022b2d151641f34ee84 (patch)
tree6c0f7dd3b016992da8d113ceeaae404c6abc03a1
parent78e2e802a8519031e5858595070b39713e26340d (diff)
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.c14
-rw-r--r--fs/open.c4
-rw-r--r--fs/xattr.c8
-rw-r--r--include/linux/audit.h15
-rw-r--r--ipc/mqueue.c8
-rw-r--r--kernel/audit.h1
-rw-r--r--kernel/auditfilter.c30
-rw-r--r--kernel/auditsc.c41
8 files changed, 87 insertions, 34 deletions
diff --git a/fs/namei.c b/fs/namei.c
index a7ad35c66807..6a92d988573f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1973,7 +1973,7 @@ static int do_path_lookup(int dfd, const char *name,
1973 retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd); 1973 retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);
1974 1974
1975 if (likely(!retval)) 1975 if (likely(!retval))
1976 audit_inode(name, nd->path.dentry); 1976 audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
1977 return retval; 1977 return retval;
1978} 1978}
1979 1979
@@ -2648,7 +2648,7 @@ static int do_last(struct nameidata *nd, struct path *path,
2648 error = complete_walk(nd); 2648 error = complete_walk(nd);
2649 if (error) 2649 if (error)
2650 return error; 2650 return error;
2651 audit_inode(pathname, nd->path.dentry); 2651 audit_inode(pathname, nd->path.dentry, 0);
2652 if (open_flag & O_CREAT) { 2652 if (open_flag & O_CREAT) {
2653 error = -EISDIR; 2653 error = -EISDIR;
2654 goto out; 2654 goto out;
@@ -2658,7 +2658,7 @@ static int do_last(struct nameidata *nd, struct path *path,
2658 error = complete_walk(nd); 2658 error = complete_walk(nd);
2659 if (error) 2659 if (error)
2660 return error; 2660 return error;
2661 audit_inode(pathname, dir); 2661 audit_inode(pathname, dir, 0);
2662 goto finish_open; 2662 goto finish_open;
2663 } 2663 }
2664 2664
@@ -2687,7 +2687,7 @@ static int do_last(struct nameidata *nd, struct path *path,
2687 if (error) 2687 if (error)
2688 return error; 2688 return error;
2689 2689
2690 audit_inode(pathname, dir); 2690 audit_inode(pathname, dir, 0);
2691 error = -EISDIR; 2691 error = -EISDIR;
2692 /* trailing slashes? */ 2692 /* trailing slashes? */
2693 if (nd->last.name[nd->last.len]) 2693 if (nd->last.name[nd->last.len])
@@ -2717,7 +2717,7 @@ retry_lookup:
2717 !S_ISREG(file->f_path.dentry->d_inode->i_mode)) 2717 !S_ISREG(file->f_path.dentry->d_inode->i_mode))
2718 will_truncate = false; 2718 will_truncate = false;
2719 2719
2720 audit_inode(pathname, file->f_path.dentry); 2720 audit_inode(pathname, file->f_path.dentry, 0);
2721 goto opened; 2721 goto opened;
2722 } 2722 }
2723 2723
@@ -2734,7 +2734,7 @@ retry_lookup:
2734 * create/update audit record if it already exists. 2734 * create/update audit record if it already exists.
2735 */ 2735 */
2736 if (path->dentry->d_inode) 2736 if (path->dentry->d_inode)
2737 audit_inode(pathname, path->dentry); 2737 audit_inode(pathname, path->dentry, 0);
2738 2738
2739 /* 2739 /*
2740 * If atomic_open() acquired write access it is dropped now due to 2740 * If atomic_open() acquired write access it is dropped now due to
@@ -2799,7 +2799,7 @@ finish_lookup:
2799 error = -ENOTDIR; 2799 error = -ENOTDIR;
2800 if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup) 2800 if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
2801 goto out; 2801 goto out;
2802 audit_inode(pathname, nd->path.dentry); 2802 audit_inode(pathname, nd->path.dentry, 0);
2803finish_open: 2803finish_open:
2804 if (!S_ISREG(nd->inode->i_mode)) 2804 if (!S_ISREG(nd->inode->i_mode))
2805 will_truncate = false; 2805 will_truncate = false;
diff --git a/fs/open.c b/fs/open.c
index 44da0feeca2c..a015437e1535 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -478,7 +478,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode)
478 478
479 file = fget(fd); 479 file = fget(fd);
480 if (file) { 480 if (file) {
481 audit_inode(NULL, file->f_path.dentry); 481 audit_inode(NULL, file->f_path.dentry, 0);
482 err = chmod_common(&file->f_path, mode); 482 err = chmod_common(&file->f_path, mode);
483 fput(file); 483 fput(file);
484 } 484 }
@@ -588,7 +588,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
588 error = mnt_want_write_file(f.file); 588 error = mnt_want_write_file(f.file);
589 if (error) 589 if (error)
590 goto out_fput; 590 goto out_fput;
591 audit_inode(NULL, f.file->f_path.dentry); 591 audit_inode(NULL, f.file->f_path.dentry, 0);
592 error = chown_common(&f.file->f_path, user, group); 592 error = chown_common(&f.file->f_path, user, group);
593 mnt_drop_write_file(f.file); 593 mnt_drop_write_file(f.file);
594out_fput: 594out_fput:
diff --git a/fs/xattr.c b/fs/xattr.c
index 1780f062dbaf..e164dddb8e96 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -412,7 +412,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
412 if (!f.file) 412 if (!f.file)
413 return error; 413 return error;
414 dentry = f.file->f_path.dentry; 414 dentry = f.file->f_path.dentry;
415 audit_inode(NULL, dentry); 415 audit_inode(NULL, dentry, 0);
416 error = mnt_want_write_file(f.file); 416 error = mnt_want_write_file(f.file);
417 if (!error) { 417 if (!error) {
418 error = setxattr(dentry, name, value, size, flags); 418 error = setxattr(dentry, name, value, size, flags);
@@ -507,7 +507,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
507 507
508 if (!f.file) 508 if (!f.file)
509 return error; 509 return error;
510 audit_inode(NULL, f.file->f_path.dentry); 510 audit_inode(NULL, f.file->f_path.dentry, 0);
511 error = getxattr(f.file->f_path.dentry, name, value, size); 511 error = getxattr(f.file->f_path.dentry, name, value, size);
512 fdput(f); 512 fdput(f);
513 return error; 513 return error;
@@ -586,7 +586,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
586 586
587 if (!f.file) 587 if (!f.file)
588 return error; 588 return error;
589 audit_inode(NULL, f.file->f_path.dentry); 589 audit_inode(NULL, f.file->f_path.dentry, 0);
590 error = listxattr(f.file->f_path.dentry, list, size); 590 error = listxattr(f.file->f_path.dentry, list, size);
591 fdput(f); 591 fdput(f);
592 return error; 592 return error;
@@ -655,7 +655,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
655 if (!f.file) 655 if (!f.file)
656 return error; 656 return error;
657 dentry = f.file->f_path.dentry; 657 dentry = f.file->f_path.dentry;
658 audit_inode(NULL, dentry); 658 audit_inode(NULL, dentry, 0);
659 error = mnt_want_write_file(f.file); 659 error = mnt_want_write_file(f.file);
660 if (!error) { 660 if (!error) {
661 error = removexattr(dentry, name); 661 error = removexattr(dentry, name);
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 26408934ef2d..b11f517dce04 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -456,6 +456,7 @@ extern int audit_classify_arch(int arch);
456/* audit_names->type values */ 456/* audit_names->type values */
457#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ 457#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
458#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */ 458#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
459#define AUDIT_TYPE_PARENT 2 /* a parent audit record */
459 460
460#ifdef CONFIG_AUDITSYSCALL 461#ifdef CONFIG_AUDITSYSCALL
461/* These are defined in auditsc.c */ 462/* These are defined in auditsc.c */
@@ -468,7 +469,8 @@ extern void __audit_syscall_entry(int arch,
468extern void __audit_syscall_exit(int ret_success, long ret_value); 469extern void __audit_syscall_exit(int ret_success, long ret_value);
469extern void __audit_getname(const char *name); 470extern void __audit_getname(const char *name);
470extern void audit_putname(const char *name); 471extern void audit_putname(const char *name);
471extern void __audit_inode(const char *name, const struct dentry *dentry); 472extern void __audit_inode(const char *name, const struct dentry *dentry,
473 unsigned int parent);
472extern void __audit_inode_child(const struct inode *parent, 474extern void __audit_inode_child(const struct inode *parent,
473 const struct dentry *dentry); 475 const struct dentry *dentry);
474extern void __audit_seccomp(unsigned long syscall, long signr, int code); 476extern void __audit_seccomp(unsigned long syscall, long signr, int code);
@@ -505,9 +507,10 @@ static inline void audit_getname(const char *name)
505 if (unlikely(!audit_dummy_context())) 507 if (unlikely(!audit_dummy_context()))
506 __audit_getname(name); 508 __audit_getname(name);
507} 509}
508static inline void audit_inode(const char *name, const struct dentry *dentry) { 510static inline void audit_inode(const char *name, const struct dentry *dentry,
511 unsigned int parent) {
509 if (unlikely(!audit_dummy_context())) 512 if (unlikely(!audit_dummy_context()))
510 __audit_inode(name, dentry); 513 __audit_inode(name, dentry, parent);
511} 514}
512static inline void audit_inode_child(const struct inode *parent, 515static inline void audit_inode_child(const struct inode *parent,
513 const struct dentry *dentry) { 516 const struct dentry *dentry) {
@@ -660,12 +663,14 @@ static inline void audit_getname(const char *name)
660{ } 663{ }
661static inline void audit_putname(const char *name) 664static inline void audit_putname(const char *name)
662{ } 665{ }
663static inline void __audit_inode(const char *name, const struct dentry *dentry) 666static inline void __audit_inode(const char *name, const struct dentry *dentry,
667 unsigned int parent)
664{ } 668{ }
665static inline void __audit_inode_child(const struct inode *parent, 669static inline void __audit_inode_child(const struct inode *parent,
666 const struct dentry *dentry) 670 const struct dentry *dentry)
667{ } 671{ }
668static inline void audit_inode(const char *name, const struct dentry *dentry) 672static inline void audit_inode(const char *name, const struct dentry *dentry,
673 unsigned int parent)
669{ } 674{ }
670static inline void audit_inode_child(const struct inode *parent, 675static inline void audit_inode_child(const struct inode *parent,
671 const struct dentry *dentry) 676 const struct dentry *dentry)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 6b97e2466fad..9553ed006042 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,
804 804
805 if (oflag & O_CREAT) { 805 if (oflag & O_CREAT) {
806 if (path.dentry->d_inode) { /* entry already exists */ 806 if (path.dentry->d_inode) { /* entry already exists */
807 audit_inode(name, path.dentry); 807 audit_inode(name, path.dentry, 0);
808 if (oflag & O_EXCL) { 808 if (oflag & O_EXCL) {
809 error = -EEXIST; 809 error = -EEXIST;
810 goto out; 810 goto out;
@@ -824,7 +824,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
824 error = -ENOENT; 824 error = -ENOENT;
825 goto out; 825 goto out;
826 } 826 }
827 audit_inode(name, path.dentry); 827 audit_inode(name, path.dentry, 0);
828 filp = do_open(&path, oflag); 828 filp = do_open(&path, oflag);
829 } 829 }
830 830
@@ -978,7 +978,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
978 goto out_fput; 978 goto out_fput;
979 } 979 }
980 info = MQUEUE_I(inode); 980 info = MQUEUE_I(inode);
981 audit_inode(NULL, f.file->f_path.dentry); 981 audit_inode(NULL, f.file->f_path.dentry, 0);
982 982
983 if (unlikely(!(f.file->f_mode & FMODE_WRITE))) { 983 if (unlikely(!(f.file->f_mode & FMODE_WRITE))) {
984 ret = -EBADF; 984 ret = -EBADF;
@@ -1094,7 +1094,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
1094 goto out_fput; 1094 goto out_fput;
1095 } 1095 }
1096 info = MQUEUE_I(inode); 1096 info = MQUEUE_I(inode);
1097 audit_inode(NULL, f.file->f_path.dentry); 1097 audit_inode(NULL, f.file->f_path.dentry, 0);
1098 1098
1099 if (unlikely(!(f.file->f_mode & FMODE_READ))) { 1099 if (unlikely(!(f.file->f_mode & FMODE_READ))) {
1100 ret = -EBADF; 1100 ret = -EBADF;
diff --git a/kernel/audit.h b/kernel/audit.h
index 9eb3d79482b6..163b9a5d9441 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -78,6 +78,7 @@ extern int audit_match_class(int class, unsigned syscall);
78extern int audit_comparator(const u32 left, const u32 op, const u32 right); 78extern int audit_comparator(const u32 left, const u32 op, const u32 right);
79extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); 79extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right);
80extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); 80extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right);
81extern int parent_len(const char *path);
81extern int audit_compare_dname_path(const char *dname, const char *path, 82extern int audit_compare_dname_path(const char *dname, const char *path,
82 int *dirlen); 83 int *dirlen);
83extern struct sk_buff * audit_make_reply(int pid, int seq, int type, 84extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index c4bcdbaf4d4d..71bb13598df3 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)
1298 } 1298 }
1299} 1299}
1300 1300
1301/**
1302 * parent_len - find the length of the parent portion of a pathname
1303 * @path: pathname of which to determine length
1304 */
1305int parent_len(const char *path)
1306{
1307 int plen;
1308 const char *p;
1309
1310 plen = strlen(path);
1311
1312 if (plen == 0)
1313 return plen;
1314
1315 /* disregard trailing slashes */
1316 p = path + plen - 1;
1317 while ((*p == '/') && (p > path))
1318 p--;
1319
1320 /* walk backward until we find the next slash or hit beginning */
1321 while ((*p != '/') && (p > path))
1322 p--;
1323
1324 /* did we find a slash? Then increment to include it in path */
1325 if (*p == '/')
1326 p++;
1327
1328 return p - path;
1329}
1330
1301/* Compare given dentry name with last component in given path, 1331/* Compare given dentry name with last component in given path,
1302 * return of 0 indicates a match. */ 1332 * return of 0 indicates a match. */
1303int audit_compare_dname_path(const char *dname, const char *path, 1333int audit_compare_dname_path(const char *dname, const char *path,
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 19b232f86d70..b87b28947acc 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
2135} 2135}
2136 2136
2137/** 2137/**
2138 * audit_inode - store the inode and device from a lookup 2138 * __audit_inode - store the inode and device from a lookup
2139 * @name: name being audited 2139 * @name: name being audited
2140 * @dentry: dentry being audited 2140 * @dentry: dentry being audited
2141 * 2141 * @parent: does this dentry represent the parent?
2142 * Called from fs/namei.c:path_lookup().
2143 */ 2142 */
2144void __audit_inode(const char *name, const struct dentry *dentry) 2143void __audit_inode(const char *name, const struct dentry *dentry,
2144 unsigned int parent)
2145{ 2145{
2146 struct audit_context *context = current->audit_context; 2146 struct audit_context *context = current->audit_context;
2147 const struct inode *inode = dentry->d_inode; 2147 const struct inode *inode = dentry->d_inode;
@@ -2154,19 +2154,38 @@ void __audit_inode(const char *name, const struct dentry *dentry)
2154 goto out_alloc; 2154 goto out_alloc;
2155 2155
2156 list_for_each_entry_reverse(n, &context->names_list, list) { 2156 list_for_each_entry_reverse(n, &context->names_list, list) {
2157 if (n->name == name) 2157 /* does the name pointer match? */
2158 goto out; 2158 if (n->name != name)
2159 continue;
2160
2161 /* match the correct record type */
2162 if (parent) {
2163 if (n->type == AUDIT_TYPE_PARENT ||
2164 n->type == AUDIT_TYPE_UNKNOWN)
2165 goto out;
2166 } else {
2167 if (n->type != AUDIT_TYPE_PARENT)
2168 goto out;
2169 }
2159 } 2170 }
2160 2171
2161out_alloc: 2172out_alloc:
2162 /* unable to find the name from a previous getname() */ 2173 /* unable to find the name from a previous getname(). Allocate a new
2174 * anonymous entry.
2175 */
2163 n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); 2176 n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
2164 if (!n) 2177 if (!n)
2165 return; 2178 return;
2166out: 2179out:
2180 if (parent) {
2181 n->name_len = n->name ? parent_len(n->name) : AUDIT_NAME_FULL;
2182 n->type = AUDIT_TYPE_PARENT;
2183 } else {
2184 n->name_len = AUDIT_NAME_FULL;
2185 n->type = AUDIT_TYPE_NORMAL;
2186 }
2167 handle_path(dentry); 2187 handle_path(dentry);
2168 audit_copy_inode(n, dentry, inode); 2188 audit_copy_inode(n, dentry, inode);
2169 n->type = AUDIT_TYPE_NORMAL;
2170} 2189}
2171 2190
2172/** 2191/**
@@ -2190,7 +2209,6 @@ void __audit_inode_child(const struct inode *parent,
2190 const struct inode *inode = dentry->d_inode; 2209 const struct inode *inode = dentry->d_inode;
2191 const char *dname = dentry->d_name.name; 2210 const char *dname = dentry->d_name.name;
2192 struct audit_names *n; 2211 struct audit_names *n;
2193 int dirlen = 0;
2194 2212
2195 if (!context->in_syscall) 2213 if (!context->in_syscall)
2196 return; 2214 return;
@@ -2204,8 +2222,7 @@ void __audit_inode_child(const struct inode *parent,
2204 continue; 2222 continue;
2205 2223
2206 if (n->ino == parent->i_ino && 2224 if (n->ino == parent->i_ino &&
2207 !audit_compare_dname_path(dname, n->name, &dirlen)) { 2225 !audit_compare_dname_path(dname, n->name, NULL)) {
2208 n->name_len = dirlen; /* update parent data in place */
2209 found_parent = n->name; 2226 found_parent = n->name;
2210 goto add_names; 2227 goto add_names;
2211 } 2228 }
@@ -2218,7 +2235,7 @@ void __audit_inode_child(const struct inode *parent,
2218 2235
2219 /* strcmp() is the more likely scenario */ 2236 /* strcmp() is the more likely scenario */
2220 if (!strcmp(dname, n->name) || 2237 if (!strcmp(dname, n->name) ||
2221 !audit_compare_dname_path(dname, n->name, &dirlen)) { 2238 !audit_compare_dname_path(dname, n->name, NULL)) {
2222 if (inode) 2239 if (inode)
2223 audit_copy_inode(n, dentry, inode); 2240 audit_copy_inode(n, dentry, inode);
2224 else 2241 else