diff options
author | Amy Griffis <amy.griffis@hp.com> | 2006-06-08 23:19:31 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2006-06-20 05:25:28 -0400 |
commit | 9c937dcc71021f2dbf78f904f03d962dd9bcc130 (patch) | |
tree | 6ab53c1cf1235515307d521cecc4f76afa34e137 | |
parent | 6a2bceec0ea7fdc47aef9a3f2f771c201eaabe5d (diff) |
[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>
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | fs/open.c | 4 | ||||
-rw-r--r-- | fs/xattr.c | 4 | ||||
-rw-r--r-- | include/linux/audit.h | 15 | ||||
-rw-r--r-- | include/linux/fsnotify.h | 3 | ||||
-rw-r--r-- | kernel/audit.c | 54 | ||||
-rw-r--r-- | kernel/audit.h | 3 | ||||
-rw-r--r-- | kernel/auditfilter.c | 8 | ||||
-rw-r--r-- | kernel/auditsc.c | 123 |
9 files changed, 142 insertions, 74 deletions
diff --git a/fs/namei.c b/fs/namei.c index d6e2ee251736..184fe4acf824 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1127,7 +1127,7 @@ out: | |||
1127 | if (likely(retval == 0)) { | 1127 | if (likely(retval == 0)) { |
1128 | if (unlikely(current->audit_context && nd && nd->dentry && | 1128 | if (unlikely(current->audit_context && nd && nd->dentry && |
1129 | nd->dentry->d_inode)) | 1129 | nd->dentry->d_inode)) |
1130 | audit_inode(name, nd->dentry->d_inode, flags); | 1130 | audit_inode(name, nd->dentry->d_inode); |
1131 | } | 1131 | } |
1132 | out_fail: | 1132 | out_fail: |
1133 | return retval; | 1133 | return retval; |
@@ -633,7 +633,7 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) | |||
633 | dentry = file->f_dentry; | 633 | dentry = file->f_dentry; |
634 | inode = dentry->d_inode; | 634 | inode = dentry->d_inode; |
635 | 635 | ||
636 | audit_inode(NULL, inode, 0); | 636 | audit_inode(NULL, inode); |
637 | 637 | ||
638 | err = -EROFS; | 638 | err = -EROFS; |
639 | if (IS_RDONLY(inode)) | 639 | if (IS_RDONLY(inode)) |
@@ -786,7 +786,7 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) | |||
786 | if (file) { | 786 | if (file) { |
787 | struct dentry * dentry; | 787 | struct dentry * dentry; |
788 | dentry = file->f_dentry; | 788 | dentry = file->f_dentry; |
789 | audit_inode(NULL, dentry->d_inode, 0); | 789 | audit_inode(NULL, dentry->d_inode); |
790 | error = chown_common(dentry, user, group); | 790 | error = chown_common(dentry, user, group); |
791 | fput(file); | 791 | fput(file); |
792 | } | 792 | } |
diff --git a/fs/xattr.c b/fs/xattr.c index e416190f5e9c..c32f15b5f60f 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -242,7 +242,7 @@ sys_fsetxattr(int fd, char __user *name, void __user *value, | |||
242 | if (!f) | 242 | if (!f) |
243 | return error; | 243 | return error; |
244 | dentry = f->f_dentry; | 244 | dentry = f->f_dentry; |
245 | audit_inode(NULL, dentry->d_inode, 0); | 245 | audit_inode(NULL, dentry->d_inode); |
246 | error = setxattr(dentry, name, value, size, flags); | 246 | error = setxattr(dentry, name, value, size, flags); |
247 | fput(f); | 247 | fput(f); |
248 | return error; | 248 | return error; |
@@ -469,7 +469,7 @@ sys_fremovexattr(int fd, char __user *name) | |||
469 | if (!f) | 469 | if (!f) |
470 | return error; | 470 | return error; |
471 | dentry = f->f_dentry; | 471 | dentry = f->f_dentry; |
472 | audit_inode(NULL, dentry->d_inode, 0); | 472 | audit_inode(NULL, dentry->d_inode); |
473 | error = removexattr(dentry, name); | 473 | error = removexattr(dentry, name); |
474 | fput(f); | 474 | fput(f); |
475 | return error; | 475 | return error; |
diff --git a/include/linux/audit.h b/include/linux/audit.h index c78327507f4e..e1c1dbdf9efb 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -310,7 +310,7 @@ extern void audit_syscall_entry(int arch, | |||
310 | extern void audit_syscall_exit(int failed, long return_code); | 310 | extern void audit_syscall_exit(int failed, long return_code); |
311 | extern void __audit_getname(const char *name); | 311 | extern void __audit_getname(const char *name); |
312 | extern void audit_putname(const char *name); | 312 | extern void audit_putname(const char *name); |
313 | extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags); | 313 | extern void __audit_inode(const char *name, const struct inode *inode); |
314 | extern void __audit_inode_child(const char *dname, const struct inode *inode, | 314 | extern void __audit_inode_child(const char *dname, const struct inode *inode, |
315 | unsigned long pino); | 315 | unsigned long pino); |
316 | static inline void audit_getname(const char *name) | 316 | static inline void audit_getname(const char *name) |
@@ -318,10 +318,9 @@ static inline void audit_getname(const char *name) | |||
318 | if (unlikely(current->audit_context)) | 318 | if (unlikely(current->audit_context)) |
319 | __audit_getname(name); | 319 | __audit_getname(name); |
320 | } | 320 | } |
321 | static inline void audit_inode(const char *name, const struct inode *inode, | 321 | static inline void audit_inode(const char *name, const struct inode *inode) { |
322 | unsigned flags) { | ||
323 | if (unlikely(current->audit_context)) | 322 | if (unlikely(current->audit_context)) |
324 | __audit_inode(name, inode, flags); | 323 | __audit_inode(name, inode); |
325 | } | 324 | } |
326 | static inline void audit_inode_child(const char *dname, | 325 | static inline void audit_inode_child(const char *dname, |
327 | const struct inode *inode, | 326 | const struct inode *inode, |
@@ -398,9 +397,9 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) | |||
398 | #define audit_syscall_exit(f,r) do { ; } while (0) | 397 | #define audit_syscall_exit(f,r) do { ; } while (0) |
399 | #define audit_getname(n) do { ; } while (0) | 398 | #define audit_getname(n) do { ; } while (0) |
400 | #define audit_putname(n) do { ; } while (0) | 399 | #define audit_putname(n) do { ; } while (0) |
401 | #define __audit_inode(n,i,f) do { ; } while (0) | 400 | #define __audit_inode(n,i) do { ; } while (0) |
402 | #define __audit_inode_child(d,i,p) do { ; } while (0) | 401 | #define __audit_inode_child(d,i,p) do { ; } while (0) |
403 | #define audit_inode(n,i,f) do { ; } while (0) | 402 | #define audit_inode(n,i) do { ; } while (0) |
404 | #define audit_inode_child(d,i,p) do { ; } while (0) | 403 | #define audit_inode_child(d,i,p) do { ; } while (0) |
405 | #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) | 404 | #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) |
406 | #define audit_get_loginuid(c) ({ -1; }) | 405 | #define audit_get_loginuid(c) ({ -1; }) |
@@ -435,6 +434,9 @@ extern void audit_log_hex(struct audit_buffer *ab, | |||
435 | size_t len); | 434 | size_t len); |
436 | extern const char * audit_log_untrustedstring(struct audit_buffer *ab, | 435 | extern const char * audit_log_untrustedstring(struct audit_buffer *ab, |
437 | const char *string); | 436 | const char *string); |
437 | extern const char * audit_log_n_untrustedstring(struct audit_buffer *ab, | ||
438 | size_t n, | ||
439 | const char *string); | ||
438 | extern void audit_log_d_path(struct audit_buffer *ab, | 440 | extern void audit_log_d_path(struct audit_buffer *ab, |
439 | const char *prefix, | 441 | const char *prefix, |
440 | struct dentry *dentry, | 442 | struct dentry *dentry, |
@@ -452,6 +454,7 @@ extern int audit_receive_filter(int type, int pid, int uid, int seq, | |||
452 | #define audit_log_end(b) do { ; } while (0) | 454 | #define audit_log_end(b) do { ; } while (0) |
453 | #define audit_log_hex(a,b,l) do { ; } while (0) | 455 | #define audit_log_hex(a,b,l) do { ; } while (0) |
454 | #define audit_log_untrustedstring(a,s) do { ; } while (0) | 456 | #define audit_log_untrustedstring(a,s) do { ; } while (0) |
457 | #define audit_log_n_untrustedstring(a,n,s) do { ; } while (0) | ||
455 | #define audit_log_d_path(b,p,d,v) do { ; } while (0) | 458 | #define audit_log_d_path(b,p,d,v) do { ; } while (0) |
456 | #endif | 459 | #endif |
457 | #endif | 460 | #endif |
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index a9d30442448f..cc5dec70c32c 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h | |||
@@ -67,8 +67,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, | |||
67 | if (source) { | 67 | if (source) { |
68 | inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL); | 68 | inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL); |
69 | } | 69 | } |
70 | audit_inode_child(old_name, source, old_dir->i_ino); | 70 | audit_inode_child(new_name, source, new_dir->i_ino); |
71 | audit_inode_child(new_name, target, new_dir->i_ino); | ||
72 | } | 71 | } |
73 | 72 | ||
74 | /* | 73 | /* |
diff --git a/kernel/audit.c b/kernel/audit.c index 0fbf1c116363..7dfac7031bd7 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -1051,20 +1051,53 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, | |||
1051 | skb_put(skb, len << 1); /* new string is twice the old string */ | 1051 | skb_put(skb, len << 1); /* new string is twice the old string */ |
1052 | } | 1052 | } |
1053 | 1053 | ||
1054 | /* | ||
1055 | * Format a string of no more than slen characters into the audit buffer, | ||
1056 | * enclosed in quote marks. | ||
1057 | */ | ||
1058 | static void audit_log_n_string(struct audit_buffer *ab, size_t slen, | ||
1059 | const char *string) | ||
1060 | { | ||
1061 | int avail, new_len; | ||
1062 | unsigned char *ptr; | ||
1063 | struct sk_buff *skb; | ||
1064 | |||
1065 | BUG_ON(!ab->skb); | ||
1066 | skb = ab->skb; | ||
1067 | avail = skb_tailroom(skb); | ||
1068 | new_len = slen + 3; /* enclosing quotes + null terminator */ | ||
1069 | if (new_len > avail) { | ||
1070 | avail = audit_expand(ab, new_len); | ||
1071 | if (!avail) | ||
1072 | return; | ||
1073 | } | ||
1074 | ptr = skb->tail; | ||
1075 | *ptr++ = '"'; | ||
1076 | memcpy(ptr, string, slen); | ||
1077 | ptr += slen; | ||
1078 | *ptr++ = '"'; | ||
1079 | *ptr = 0; | ||
1080 | skb_put(skb, slen + 2); /* don't include null terminator */ | ||
1081 | } | ||
1082 | |||
1054 | /** | 1083 | /** |
1055 | * audit_log_unstrustedstring - log a string that may contain random characters | 1084 | * audit_log_n_unstrustedstring - log a string that may contain random characters |
1056 | * @ab: audit_buffer | 1085 | * @ab: audit_buffer |
1086 | * @len: lenth of string (not including trailing null) | ||
1057 | * @string: string to be logged | 1087 | * @string: string to be logged |
1058 | * | 1088 | * |
1059 | * This code will escape a string that is passed to it if the string | 1089 | * This code will escape a string that is passed to it if the string |
1060 | * contains a control character, unprintable character, double quote mark, | 1090 | * contains a control character, unprintable character, double quote mark, |
1061 | * or a space. Unescaped strings will start and end with a double quote mark. | 1091 | * or a space. Unescaped strings will start and end with a double quote mark. |
1062 | * Strings that are escaped are printed in hex (2 digits per char). | 1092 | * Strings that are escaped are printed in hex (2 digits per char). |
1093 | * | ||
1094 | * The caller specifies the number of characters in the string to log, which may | ||
1095 | * or may not be the entire string. | ||
1063 | */ | 1096 | */ |
1064 | const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string) | 1097 | const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len, |
1098 | const char *string) | ||
1065 | { | 1099 | { |
1066 | const unsigned char *p = string; | 1100 | const unsigned char *p = string; |
1067 | size_t len = strlen(string); | ||
1068 | 1101 | ||
1069 | while (*p) { | 1102 | while (*p) { |
1070 | if (*p == '"' || *p < 0x21 || *p > 0x7f) { | 1103 | if (*p == '"' || *p < 0x21 || *p > 0x7f) { |
@@ -1073,10 +1106,23 @@ const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *strin | |||
1073 | } | 1106 | } |
1074 | p++; | 1107 | p++; |
1075 | } | 1108 | } |
1076 | audit_log_format(ab, "\"%s\"", string); | 1109 | audit_log_n_string(ab, len, string); |
1077 | return p + 1; | 1110 | return p + 1; |
1078 | } | 1111 | } |
1079 | 1112 | ||
1113 | /** | ||
1114 | * audit_log_unstrustedstring - log a string that may contain random characters | ||
1115 | * @ab: audit_buffer | ||
1116 | * @string: string to be logged | ||
1117 | * | ||
1118 | * Same as audit_log_n_unstrustedstring(), except that strlen is used to | ||
1119 | * determine string length. | ||
1120 | */ | ||
1121 | const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string) | ||
1122 | { | ||
1123 | return audit_log_n_untrustedstring(ab, strlen(string), string); | ||
1124 | } | ||
1125 | |||
1080 | /* This is a helper-function to print the escaped d_path */ | 1126 | /* This is a helper-function to print the escaped d_path */ |
1081 | void audit_log_d_path(struct audit_buffer *ab, const char *prefix, | 1127 | void audit_log_d_path(struct audit_buffer *ab, const char *prefix, |
1082 | struct dentry *dentry, struct vfsmount *vfsmnt) | 1128 | struct dentry *dentry, struct vfsmount *vfsmnt) |
diff --git a/kernel/audit.h b/kernel/audit.h index 58fa44cb8d01..8323e4132a33 100644 --- a/kernel/audit.h +++ b/kernel/audit.h | |||
@@ -104,7 +104,8 @@ static inline int audit_hash_ino(u32 ino) | |||
104 | } | 104 | } |
105 | 105 | ||
106 | extern int audit_comparator(const u32 left, const u32 op, const u32 right); | 106 | extern int audit_comparator(const u32 left, const u32 op, const u32 right); |
107 | extern int audit_compare_dname_path(const char *dname, const char *path); | 107 | extern int audit_compare_dname_path(const char *dname, const char *path, |
108 | int *dirlen); | ||
108 | extern struct sk_buff * audit_make_reply(int pid, int seq, int type, | 109 | extern struct sk_buff * audit_make_reply(int pid, int seq, int type, |
109 | int done, int multi, | 110 | int done, int multi, |
110 | void *payload, int size); | 111 | void *payload, int size); |
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index a536f7148bcd..4c99d2c586ed 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
@@ -787,7 +787,7 @@ static void audit_update_watch(struct audit_parent *parent, | |||
787 | 787 | ||
788 | mutex_lock(&audit_filter_mutex); | 788 | mutex_lock(&audit_filter_mutex); |
789 | list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { | 789 | list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { |
790 | if (audit_compare_dname_path(dname, owatch->path)) | 790 | if (audit_compare_dname_path(dname, owatch->path, NULL)) |
791 | continue; | 791 | continue; |
792 | 792 | ||
793 | /* If the update involves invalidating rules, do the inode-based | 793 | /* 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) | |||
1387 | 1387 | ||
1388 | /* Compare given dentry name with last component in given path, | 1388 | /* Compare given dentry name with last component in given path, |
1389 | * return of 0 indicates a match. */ | 1389 | * return of 0 indicates a match. */ |
1390 | int audit_compare_dname_path(const char *dname, const char *path) | 1390 | int audit_compare_dname_path(const char *dname, const char *path, |
1391 | int *dirlen) | ||
1391 | { | 1392 | { |
1392 | int dlen, plen; | 1393 | int dlen, plen; |
1393 | const char *p; | 1394 | const char *p; |
@@ -1416,6 +1417,9 @@ int audit_compare_dname_path(const char *dname, const char *path) | |||
1416 | p++; | 1417 | p++; |
1417 | } | 1418 | } |
1418 | 1419 | ||
1420 | /* return length of path's directory component */ | ||
1421 | if (dirlen) | ||
1422 | *dirlen = p - path; | ||
1419 | return strncmp(p, dname, dlen); | 1423 | return strncmp(p, dname, dlen); |
1420 | } | 1424 | } |
1421 | 1425 | ||
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 174a3f624892..851ae0217e4b 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -82,6 +82,9 @@ extern int audit_enabled; | |||
82 | * path_lookup. */ | 82 | * path_lookup. */ |
83 | #define AUDIT_NAMES_RESERVED 7 | 83 | #define AUDIT_NAMES_RESERVED 7 |
84 | 84 | ||
85 | /* Indicates that audit should log the full pathname. */ | ||
86 | #define AUDIT_NAME_FULL -1 | ||
87 | |||
85 | /* When fs/namei.c:getname() is called, we store the pointer in name and | 88 | /* When fs/namei.c:getname() is called, we store the pointer in name and |
86 | * we don't let putname() free it (instead we free all of the saved | 89 | * we don't let putname() free it (instead we free all of the saved |
87 | * pointers at syscall exit time). | 90 | * pointers at syscall exit time). |
@@ -89,8 +92,9 @@ extern int audit_enabled; | |||
89 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ | 92 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ |
90 | struct audit_names { | 93 | struct audit_names { |
91 | const char *name; | 94 | const char *name; |
95 | int name_len; /* number of name's characters to log */ | ||
96 | unsigned name_put; /* call __putname() for this name */ | ||
92 | unsigned long ino; | 97 | unsigned long ino; |
93 | unsigned long pino; | ||
94 | dev_t dev; | 98 | dev_t dev; |
95 | umode_t mode; | 99 | umode_t mode; |
96 | uid_t uid; | 100 | uid_t uid; |
@@ -296,12 +300,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
296 | break; | 300 | break; |
297 | case AUDIT_INODE: | 301 | case AUDIT_INODE: |
298 | if (name) | 302 | if (name) |
299 | result = (name->ino == f->val || | 303 | result = (name->ino == f->val); |
300 | name->pino == f->val); | ||
301 | else if (ctx) { | 304 | else if (ctx) { |
302 | for (j = 0; j < ctx->name_count; j++) { | 305 | for (j = 0; j < ctx->name_count; j++) { |
303 | if (audit_comparator(ctx->names[j].ino, f->op, f->val) || | 306 | if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { |
304 | audit_comparator(ctx->names[j].pino, f->op, f->val)) { | ||
305 | ++result; | 307 | ++result; |
306 | break; | 308 | break; |
307 | } | 309 | } |
@@ -311,8 +313,7 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
311 | case AUDIT_WATCH: | 313 | case AUDIT_WATCH: |
312 | if (name && rule->watch->ino != (unsigned long)-1) | 314 | if (name && rule->watch->ino != (unsigned long)-1) |
313 | result = (name->dev == rule->watch->dev && | 315 | result = (name->dev == rule->watch->dev && |
314 | (name->ino == rule->watch->ino || | 316 | name->ino == rule->watch->ino); |
315 | name->pino == rule->watch->ino)); | ||
316 | break; | 317 | break; |
317 | case AUDIT_LOGINUID: | 318 | case AUDIT_LOGINUID: |
318 | result = 0; | 319 | result = 0; |
@@ -526,7 +527,7 @@ static inline void audit_free_names(struct audit_context *context) | |||
526 | #endif | 527 | #endif |
527 | 528 | ||
528 | for (i = 0; i < context->name_count; i++) { | 529 | for (i = 0; i < context->name_count; i++) { |
529 | if (context->names[i].name) | 530 | if (context->names[i].name && context->names[i].name_put) |
530 | __putname(context->names[i].name); | 531 | __putname(context->names[i].name); |
531 | } | 532 | } |
532 | context->name_count = 0; | 533 | context->name_count = 0; |
@@ -850,8 +851,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
850 | } | 851 | } |
851 | } | 852 | } |
852 | for (i = 0; i < context->name_count; i++) { | 853 | for (i = 0; i < context->name_count; i++) { |
853 | unsigned long ino = context->names[i].ino; | 854 | struct audit_names *n = &context->names[i]; |
854 | unsigned long pino = context->names[i].pino; | ||
855 | 855 | ||
856 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | 856 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); |
857 | if (!ab) | 857 | if (!ab) |
@@ -859,33 +859,47 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
859 | 859 | ||
860 | audit_log_format(ab, "item=%d", i); | 860 | audit_log_format(ab, "item=%d", i); |
861 | 861 | ||
862 | audit_log_format(ab, " name="); | 862 | if (n->name) { |
863 | if (context->names[i].name) | 863 | switch(n->name_len) { |
864 | audit_log_untrustedstring(ab, context->names[i].name); | 864 | case AUDIT_NAME_FULL: |
865 | else | 865 | /* log the full path */ |
866 | audit_log_format(ab, "(null)"); | 866 | audit_log_format(ab, " name="); |
867 | 867 | audit_log_untrustedstring(ab, n->name); | |
868 | if (pino != (unsigned long)-1) | 868 | break; |
869 | audit_log_format(ab, " parent=%lu", pino); | 869 | case 0: |
870 | if (ino != (unsigned long)-1) | 870 | /* name was specified as a relative path and the |
871 | audit_log_format(ab, " inode=%lu", ino); | 871 | * directory component is the cwd */ |
872 | if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1)) | 872 | audit_log_d_path(ab, " name=", context->pwd, |
873 | audit_log_format(ab, " dev=%02x:%02x mode=%#o" | 873 | context->pwdmnt); |
874 | " ouid=%u ogid=%u rdev=%02x:%02x", | 874 | break; |
875 | MAJOR(context->names[i].dev), | 875 | default: |
876 | MINOR(context->names[i].dev), | 876 | /* log the name's directory component */ |
877 | context->names[i].mode, | 877 | audit_log_format(ab, " name="); |
878 | context->names[i].uid, | 878 | audit_log_n_untrustedstring(ab, n->name_len, |
879 | context->names[i].gid, | 879 | n->name); |
880 | MAJOR(context->names[i].rdev), | 880 | } |
881 | MINOR(context->names[i].rdev)); | 881 | } else |
882 | if (context->names[i].osid != 0) { | 882 | audit_log_format(ab, " name=(null)"); |
883 | |||
884 | if (n->ino != (unsigned long)-1) { | ||
885 | audit_log_format(ab, " inode=%lu" | ||
886 | " dev=%02x:%02x mode=%#o" | ||
887 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
888 | n->ino, | ||
889 | MAJOR(n->dev), | ||
890 | MINOR(n->dev), | ||
891 | n->mode, | ||
892 | n->uid, | ||
893 | n->gid, | ||
894 | MAJOR(n->rdev), | ||
895 | MINOR(n->rdev)); | ||
896 | } | ||
897 | if (n->osid != 0) { | ||
883 | char *ctx = NULL; | 898 | char *ctx = NULL; |
884 | u32 len; | 899 | u32 len; |
885 | if (selinux_ctxid_to_string( | 900 | if (selinux_ctxid_to_string( |
886 | context->names[i].osid, &ctx, &len)) { | 901 | n->osid, &ctx, &len)) { |
887 | audit_log_format(ab, " osid=%u", | 902 | audit_log_format(ab, " osid=%u", n->osid); |
888 | context->names[i].osid); | ||
889 | call_panic = 2; | 903 | call_panic = 2; |
890 | } else | 904 | } else |
891 | audit_log_format(ab, " obj=%s", ctx); | 905 | audit_log_format(ab, " obj=%s", ctx); |
@@ -1075,6 +1089,8 @@ void __audit_getname(const char *name) | |||
1075 | } | 1089 | } |
1076 | BUG_ON(context->name_count >= AUDIT_NAMES); | 1090 | BUG_ON(context->name_count >= AUDIT_NAMES); |
1077 | context->names[context->name_count].name = name; | 1091 | context->names[context->name_count].name = name; |
1092 | context->names[context->name_count].name_len = AUDIT_NAME_FULL; | ||
1093 | context->names[context->name_count].name_put = 1; | ||
1078 | context->names[context->name_count].ino = (unsigned long)-1; | 1094 | context->names[context->name_count].ino = (unsigned long)-1; |
1079 | ++context->name_count; | 1095 | ++context->name_count; |
1080 | if (!context->pwd) { | 1096 | if (!context->pwd) { |
@@ -1141,11 +1157,10 @@ static void audit_inode_context(int idx, const struct inode *inode) | |||
1141 | * audit_inode - store the inode and device from a lookup | 1157 | * audit_inode - store the inode and device from a lookup |
1142 | * @name: name being audited | 1158 | * @name: name being audited |
1143 | * @inode: inode being audited | 1159 | * @inode: inode being audited |
1144 | * @flags: lookup flags (as used in path_lookup()) | ||
1145 | * | 1160 | * |
1146 | * Called from fs/namei.c:path_lookup(). | 1161 | * Called from fs/namei.c:path_lookup(). |
1147 | */ | 1162 | */ |
1148 | void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | 1163 | void __audit_inode(const char *name, const struct inode *inode) |
1149 | { | 1164 | { |
1150 | int idx; | 1165 | int idx; |
1151 | struct audit_context *context = current->audit_context; | 1166 | struct audit_context *context = current->audit_context; |
@@ -1171,20 +1186,13 @@ void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | |||
1171 | ++context->ino_count; | 1186 | ++context->ino_count; |
1172 | #endif | 1187 | #endif |
1173 | } | 1188 | } |
1189 | context->names[idx].ino = inode->i_ino; | ||
1174 | context->names[idx].dev = inode->i_sb->s_dev; | 1190 | context->names[idx].dev = inode->i_sb->s_dev; |
1175 | context->names[idx].mode = inode->i_mode; | 1191 | context->names[idx].mode = inode->i_mode; |
1176 | context->names[idx].uid = inode->i_uid; | 1192 | context->names[idx].uid = inode->i_uid; |
1177 | context->names[idx].gid = inode->i_gid; | 1193 | context->names[idx].gid = inode->i_gid; |
1178 | context->names[idx].rdev = inode->i_rdev; | 1194 | context->names[idx].rdev = inode->i_rdev; |
1179 | audit_inode_context(idx, inode); | 1195 | audit_inode_context(idx, inode); |
1180 | if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && | ||
1181 | (strcmp(name, ".") != 0)) { | ||
1182 | context->names[idx].ino = (unsigned long)-1; | ||
1183 | context->names[idx].pino = inode->i_ino; | ||
1184 | } else { | ||
1185 | context->names[idx].ino = inode->i_ino; | ||
1186 | context->names[idx].pino = (unsigned long)-1; | ||
1187 | } | ||
1188 | } | 1196 | } |
1189 | 1197 | ||
1190 | /** | 1198 | /** |
@@ -1206,34 +1214,40 @@ void __audit_inode_child(const char *dname, const struct inode *inode, | |||
1206 | { | 1214 | { |
1207 | int idx; | 1215 | int idx; |
1208 | struct audit_context *context = current->audit_context; | 1216 | struct audit_context *context = current->audit_context; |
1217 | const char *found_name = NULL; | ||
1218 | int dirlen = 0; | ||
1209 | 1219 | ||
1210 | if (!context->in_syscall) | 1220 | if (!context->in_syscall) |
1211 | return; | 1221 | return; |
1212 | 1222 | ||
1213 | /* determine matching parent */ | 1223 | /* determine matching parent */ |
1214 | if (!dname) | 1224 | if (!dname) |
1215 | goto no_match; | 1225 | goto update_context; |
1216 | for (idx = 0; idx < context->name_count; idx++) | 1226 | for (idx = 0; idx < context->name_count; idx++) |
1217 | if (context->names[idx].pino == pino) { | 1227 | if (context->names[idx].ino == pino) { |
1218 | const char *name = context->names[idx].name; | 1228 | const char *name = context->names[idx].name; |
1219 | 1229 | ||
1220 | if (!name) | 1230 | if (!name) |
1221 | continue; | 1231 | continue; |
1222 | 1232 | ||
1223 | if (audit_compare_dname_path(dname, name) == 0) | 1233 | if (audit_compare_dname_path(dname, name, &dirlen) == 0) { |
1224 | goto update_context; | 1234 | context->names[idx].name_len = dirlen; |
1235 | found_name = name; | ||
1236 | break; | ||
1237 | } | ||
1225 | } | 1238 | } |
1226 | 1239 | ||
1227 | no_match: | 1240 | update_context: |
1228 | /* catch-all in case match not found */ | ||
1229 | idx = context->name_count++; | 1241 | idx = context->name_count++; |
1230 | context->names[idx].name = NULL; | ||
1231 | context->names[idx].pino = pino; | ||
1232 | #if AUDIT_DEBUG | 1242 | #if AUDIT_DEBUG |
1233 | context->ino_count++; | 1243 | context->ino_count++; |
1234 | #endif | 1244 | #endif |
1245 | /* Re-use the name belonging to the slot for a matching parent directory. | ||
1246 | * All names for this context are relinquished in audit_free_names() */ | ||
1247 | context->names[idx].name = found_name; | ||
1248 | context->names[idx].name_len = AUDIT_NAME_FULL; | ||
1249 | context->names[idx].name_put = 0; /* don't call __putname() */ | ||
1235 | 1250 | ||
1236 | update_context: | ||
1237 | if (inode) { | 1251 | if (inode) { |
1238 | context->names[idx].ino = inode->i_ino; | 1252 | context->names[idx].ino = inode->i_ino; |
1239 | context->names[idx].dev = inode->i_sb->s_dev; | 1253 | context->names[idx].dev = inode->i_sb->s_dev; |
@@ -1242,7 +1256,8 @@ update_context: | |||
1242 | context->names[idx].gid = inode->i_gid; | 1256 | context->names[idx].gid = inode->i_gid; |
1243 | context->names[idx].rdev = inode->i_rdev; | 1257 | context->names[idx].rdev = inode->i_rdev; |
1244 | audit_inode_context(idx, inode); | 1258 | audit_inode_context(idx, inode); |
1245 | } | 1259 | } else |
1260 | context->names[idx].ino = (unsigned long)-1; | ||
1246 | } | 1261 | } |
1247 | 1262 | ||
1248 | /** | 1263 | /** |