Commit 9c937dcc71021f2dbf78f904f03d962dd9bcc130
Committed by
Al Viro
1 parent
6a2bceec0e
Exists in
master
and in
4 other branches
[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>
Showing 9 changed files with 142 additions and 74 deletions Side-by-side Diff
fs/namei.c
... | ... | @@ -1127,7 +1127,7 @@ |
1127 | 1127 | if (likely(retval == 0)) { |
1128 | 1128 | if (unlikely(current->audit_context && nd && nd->dentry && |
1129 | 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 | 1132 | out_fail: |
1133 | 1133 | return retval; |
fs/open.c
... | ... | @@ -633,7 +633,7 @@ |
633 | 633 | dentry = file->f_dentry; |
634 | 634 | inode = dentry->d_inode; |
635 | 635 | |
636 | - audit_inode(NULL, inode, 0); | |
636 | + audit_inode(NULL, inode); | |
637 | 637 | |
638 | 638 | err = -EROFS; |
639 | 639 | if (IS_RDONLY(inode)) |
... | ... | @@ -786,7 +786,7 @@ |
786 | 786 | if (file) { |
787 | 787 | struct dentry * dentry; |
788 | 788 | dentry = file->f_dentry; |
789 | - audit_inode(NULL, dentry->d_inode, 0); | |
789 | + audit_inode(NULL, dentry->d_inode); | |
790 | 790 | error = chown_common(dentry, user, group); |
791 | 791 | fput(file); |
792 | 792 | } |
fs/xattr.c
... | ... | @@ -242,7 +242,7 @@ |
242 | 242 | if (!f) |
243 | 243 | return error; |
244 | 244 | dentry = f->f_dentry; |
245 | - audit_inode(NULL, dentry->d_inode, 0); | |
245 | + audit_inode(NULL, dentry->d_inode); | |
246 | 246 | error = setxattr(dentry, name, value, size, flags); |
247 | 247 | fput(f); |
248 | 248 | return error; |
... | ... | @@ -469,7 +469,7 @@ |
469 | 469 | if (!f) |
470 | 470 | return error; |
471 | 471 | dentry = f->f_dentry; |
472 | - audit_inode(NULL, dentry->d_inode, 0); | |
472 | + audit_inode(NULL, dentry->d_inode); | |
473 | 473 | error = removexattr(dentry, name); |
474 | 474 | fput(f); |
475 | 475 | return error; |
include/linux/audit.h
... | ... | @@ -310,7 +310,7 @@ |
310 | 310 | extern void audit_syscall_exit(int failed, long return_code); |
311 | 311 | extern void __audit_getname(const char *name); |
312 | 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 | 314 | extern void __audit_inode_child(const char *dname, const struct inode *inode, |
315 | 315 | unsigned long pino); |
316 | 316 | static inline void audit_getname(const char *name) |
317 | 317 | |
... | ... | @@ -318,10 +318,9 @@ |
318 | 318 | if (unlikely(current->audit_context)) |
319 | 319 | __audit_getname(name); |
320 | 320 | } |
321 | -static inline void audit_inode(const char *name, const struct inode *inode, | |
322 | - unsigned flags) { | |
321 | +static inline void audit_inode(const char *name, const struct inode *inode) { | |
323 | 322 | if (unlikely(current->audit_context)) |
324 | - __audit_inode(name, inode, flags); | |
323 | + __audit_inode(name, inode); | |
325 | 324 | } |
326 | 325 | static inline void audit_inode_child(const char *dname, |
327 | 326 | const struct inode *inode, |
328 | 327 | |
... | ... | @@ -398,9 +397,9 @@ |
398 | 397 | #define audit_syscall_exit(f,r) do { ; } while (0) |
399 | 398 | #define audit_getname(n) do { ; } while (0) |
400 | 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 | 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 | 403 | #define audit_inode_child(d,i,p) do { ; } while (0) |
405 | 404 | #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) |
406 | 405 | #define audit_get_loginuid(c) ({ -1; }) |
... | ... | @@ -435,6 +434,9 @@ |
435 | 434 | size_t len); |
436 | 435 | extern const char * audit_log_untrustedstring(struct audit_buffer *ab, |
437 | 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 | 440 | extern void audit_log_d_path(struct audit_buffer *ab, |
439 | 441 | const char *prefix, |
440 | 442 | struct dentry *dentry, |
... | ... | @@ -452,6 +454,7 @@ |
452 | 454 | #define audit_log_end(b) do { ; } while (0) |
453 | 455 | #define audit_log_hex(a,b,l) do { ; } while (0) |
454 | 456 | #define audit_log_untrustedstring(a,s) do { ; } while (0) |
457 | +#define audit_log_n_untrustedstring(a,n,s) do { ; } while (0) | |
455 | 458 | #define audit_log_d_path(b,p,d,v) do { ; } while (0) |
456 | 459 | #endif |
457 | 460 | #endif |
include/linux/fsnotify.h
... | ... | @@ -67,8 +67,7 @@ |
67 | 67 | if (source) { |
68 | 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); | |
71 | - audit_inode_child(new_name, target, new_dir->i_ino); | |
70 | + audit_inode_child(new_name, source, new_dir->i_ino); | |
72 | 71 | } |
73 | 72 | |
74 | 73 | /* |
kernel/audit.c
... | ... | @@ -1051,20 +1051,53 @@ |
1051 | 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 | 1085 | * @ab: audit_buffer |
1086 | + * @len: lenth of string (not including trailing null) | |
1057 | 1087 | * @string: string to be logged |
1058 | 1088 | * |
1059 | 1089 | * This code will escape a string that is passed to it if the string |
1060 | 1090 | * contains a control character, unprintable character, double quote mark, |
1061 | 1091 | * or a space. Unescaped strings will start and end with a double quote mark. |
1062 | 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 | 1100 | const unsigned char *p = string; |
1067 | - size_t len = strlen(string); | |
1068 | 1101 | |
1069 | 1102 | while (*p) { |
1070 | 1103 | if (*p == '"' || *p < 0x21 || *p > 0x7f) { |
1071 | 1104 | |
... | ... | @@ -1073,8 +1106,21 @@ |
1073 | 1106 | } |
1074 | 1107 | p++; |
1075 | 1108 | } |
1076 | - audit_log_format(ab, "\"%s\"", string); | |
1109 | + audit_log_n_string(ab, len, string); | |
1077 | 1110 | return p + 1; |
1111 | +} | |
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); | |
1078 | 1124 | } |
1079 | 1125 | |
1080 | 1126 | /* This is a helper-function to print the escaped d_path */ |
kernel/audit.h
... | ... | @@ -104,7 +104,8 @@ |
104 | 104 | } |
105 | 105 | |
106 | 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 | 109 | extern struct sk_buff * audit_make_reply(int pid, int seq, int type, |
109 | 110 | int done, int multi, |
110 | 111 | void *payload, int size); |
kernel/auditfilter.c
... | ... | @@ -787,7 +787,7 @@ |
787 | 787 | |
788 | 788 | mutex_lock(&audit_filter_mutex); |
789 | 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 | 791 | continue; |
792 | 792 | |
793 | 793 | /* If the update involves invalidating rules, do the inode-based |
... | ... | @@ -1387,7 +1387,8 @@ |
1387 | 1387 | |
1388 | 1388 | /* Compare given dentry name with last component in given path, |
1389 | 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 | 1393 | int dlen, plen; |
1393 | 1394 | const char *p; |
... | ... | @@ -1416,6 +1417,9 @@ |
1416 | 1417 | p++; |
1417 | 1418 | } |
1418 | 1419 | |
1420 | + /* return length of path's directory component */ | |
1421 | + if (dirlen) | |
1422 | + *dirlen = p - path; | |
1419 | 1423 | return strncmp(p, dname, dlen); |
1420 | 1424 | } |
1421 | 1425 |
kernel/auditsc.c
... | ... | @@ -82,6 +82,9 @@ |
82 | 82 | * path_lookup. */ |
83 | 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 | 88 | /* When fs/namei.c:getname() is called, we store the pointer in name and |
86 | 89 | * we don't let putname() free it (instead we free all of the saved |
87 | 90 | * pointers at syscall exit time). |
88 | 91 | |
... | ... | @@ -89,8 +92,9 @@ |
89 | 92 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ |
90 | 93 | struct audit_names { |
91 | 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 | 97 | unsigned long ino; |
93 | - unsigned long pino; | |
94 | 98 | dev_t dev; |
95 | 99 | umode_t mode; |
96 | 100 | uid_t uid; |
97 | 101 | |
... | ... | @@ -296,12 +300,10 @@ |
296 | 300 | break; |
297 | 301 | case AUDIT_INODE: |
298 | 302 | if (name) |
299 | - result = (name->ino == f->val || | |
300 | - name->pino == f->val); | |
303 | + result = (name->ino == f->val); | |
301 | 304 | else if (ctx) { |
302 | 305 | for (j = 0; j < ctx->name_count; j++) { |
303 | - if (audit_comparator(ctx->names[j].ino, f->op, f->val) || | |
304 | - audit_comparator(ctx->names[j].pino, f->op, f->val)) { | |
306 | + if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { | |
305 | 307 | ++result; |
306 | 308 | break; |
307 | 309 | } |
... | ... | @@ -311,8 +313,7 @@ |
311 | 313 | case AUDIT_WATCH: |
312 | 314 | if (name && rule->watch->ino != (unsigned long)-1) |
313 | 315 | result = (name->dev == rule->watch->dev && |
314 | - (name->ino == rule->watch->ino || | |
315 | - name->pino == rule->watch->ino)); | |
316 | + name->ino == rule->watch->ino); | |
316 | 317 | break; |
317 | 318 | case AUDIT_LOGINUID: |
318 | 319 | result = 0; |
... | ... | @@ -526,7 +527,7 @@ |
526 | 527 | #endif |
527 | 528 | |
528 | 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 | 531 | __putname(context->names[i].name); |
531 | 532 | } |
532 | 533 | context->name_count = 0; |
... | ... | @@ -850,8 +851,7 @@ |
850 | 851 | } |
851 | 852 | } |
852 | 853 | for (i = 0; i < context->name_count; i++) { |
853 | - unsigned long ino = context->names[i].ino; | |
854 | - unsigned long pino = context->names[i].pino; | |
854 | + struct audit_names *n = &context->names[i]; | |
855 | 855 | |
856 | 856 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); |
857 | 857 | if (!ab) |
858 | 858 | |
859 | 859 | |
... | ... | @@ -859,33 +859,47 @@ |
859 | 859 | |
860 | 860 | audit_log_format(ab, "item=%d", i); |
861 | 861 | |
862 | - audit_log_format(ab, " name="); | |
863 | - if (context->names[i].name) | |
864 | - audit_log_untrustedstring(ab, context->names[i].name); | |
865 | - else | |
866 | - audit_log_format(ab, "(null)"); | |
862 | + if (n->name) { | |
863 | + switch(n->name_len) { | |
864 | + case AUDIT_NAME_FULL: | |
865 | + /* log the full path */ | |
866 | + audit_log_format(ab, " name="); | |
867 | + audit_log_untrustedstring(ab, n->name); | |
868 | + break; | |
869 | + case 0: | |
870 | + /* name was specified as a relative path and the | |
871 | + * directory component is the cwd */ | |
872 | + audit_log_d_path(ab, " name=", context->pwd, | |
873 | + context->pwdmnt); | |
874 | + break; | |
875 | + default: | |
876 | + /* log the name's directory component */ | |
877 | + audit_log_format(ab, " name="); | |
878 | + audit_log_n_untrustedstring(ab, n->name_len, | |
879 | + n->name); | |
880 | + } | |
881 | + } else | |
882 | + audit_log_format(ab, " name=(null)"); | |
867 | 883 | |
868 | - if (pino != (unsigned long)-1) | |
869 | - audit_log_format(ab, " parent=%lu", pino); | |
870 | - if (ino != (unsigned long)-1) | |
871 | - audit_log_format(ab, " inode=%lu", ino); | |
872 | - if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1)) | |
873 | - audit_log_format(ab, " dev=%02x:%02x mode=%#o" | |
874 | - " ouid=%u ogid=%u rdev=%02x:%02x", | |
875 | - MAJOR(context->names[i].dev), | |
876 | - MINOR(context->names[i].dev), | |
877 | - context->names[i].mode, | |
878 | - context->names[i].uid, | |
879 | - context->names[i].gid, | |
880 | - MAJOR(context->names[i].rdev), | |
881 | - MINOR(context->names[i].rdev)); | |
882 | - if (context->names[i].osid != 0) { | |
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 | 898 | char *ctx = NULL; |
884 | 899 | u32 len; |
885 | 900 | if (selinux_ctxid_to_string( |
886 | - context->names[i].osid, &ctx, &len)) { | |
887 | - audit_log_format(ab, " osid=%u", | |
888 | - context->names[i].osid); | |
901 | + n->osid, &ctx, &len)) { | |
902 | + audit_log_format(ab, " osid=%u", n->osid); | |
889 | 903 | call_panic = 2; |
890 | 904 | } else |
891 | 905 | audit_log_format(ab, " obj=%s", ctx); |
... | ... | @@ -1075,6 +1089,8 @@ |
1075 | 1089 | } |
1076 | 1090 | BUG_ON(context->name_count >= AUDIT_NAMES); |
1077 | 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 | 1094 | context->names[context->name_count].ino = (unsigned long)-1; |
1079 | 1095 | ++context->name_count; |
1080 | 1096 | if (!context->pwd) { |
1081 | 1097 | |
... | ... | @@ -1141,11 +1157,10 @@ |
1141 | 1157 | * audit_inode - store the inode and device from a lookup |
1142 | 1158 | * @name: name being audited |
1143 | 1159 | * @inode: inode being audited |
1144 | - * @flags: lookup flags (as used in path_lookup()) | |
1145 | 1160 | * |
1146 | 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 | 1165 | int idx; |
1151 | 1166 | struct audit_context *context = current->audit_context; |
1152 | 1167 | |
... | ... | @@ -1171,20 +1186,13 @@ |
1171 | 1186 | ++context->ino_count; |
1172 | 1187 | #endif |
1173 | 1188 | } |
1189 | + context->names[idx].ino = inode->i_ino; | |
1174 | 1190 | context->names[idx].dev = inode->i_sb->s_dev; |
1175 | 1191 | context->names[idx].mode = inode->i_mode; |
1176 | 1192 | context->names[idx].uid = inode->i_uid; |
1177 | 1193 | context->names[idx].gid = inode->i_gid; |
1178 | 1194 | context->names[idx].rdev = inode->i_rdev; |
1179 | 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 | /** |
1191 | 1199 | |
1192 | 1200 | |
1193 | 1201 | |
1194 | 1202 | |
1195 | 1203 | |
1196 | 1204 | |
1197 | 1205 | |
... | ... | @@ -1206,34 +1214,40 @@ |
1206 | 1214 | { |
1207 | 1215 | int idx; |
1208 | 1216 | struct audit_context *context = current->audit_context; |
1217 | + const char *found_name = NULL; | |
1218 | + int dirlen = 0; | |
1209 | 1219 | |
1210 | 1220 | if (!context->in_syscall) |
1211 | 1221 | return; |
1212 | 1222 | |
1213 | 1223 | /* determine matching parent */ |
1214 | 1224 | if (!dname) |
1215 | - goto no_match; | |
1225 | + goto update_context; | |
1216 | 1226 | for (idx = 0; idx < context->name_count; idx++) |
1217 | - if (context->names[idx].pino == pino) { | |
1227 | + if (context->names[idx].ino == pino) { | |
1218 | 1228 | const char *name = context->names[idx].name; |
1219 | 1229 | |
1220 | 1230 | if (!name) |
1221 | 1231 | continue; |
1222 | 1232 | |
1223 | - if (audit_compare_dname_path(dname, name) == 0) | |
1224 | - goto update_context; | |
1233 | + if (audit_compare_dname_path(dname, name, &dirlen) == 0) { | |
1234 | + context->names[idx].name_len = dirlen; | |
1235 | + found_name = name; | |
1236 | + break; | |
1237 | + } | |
1225 | 1238 | } |
1226 | 1239 | |
1227 | -no_match: | |
1228 | - /* catch-all in case match not found */ | |
1240 | +update_context: | |
1229 | 1241 | idx = context->name_count++; |
1230 | - context->names[idx].name = NULL; | |
1231 | - context->names[idx].pino = pino; | |
1232 | 1242 | #if AUDIT_DEBUG |
1233 | 1243 | context->ino_count++; |
1234 | 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 | 1251 | if (inode) { |
1238 | 1252 | context->names[idx].ino = inode->i_ino; |
1239 | 1253 | context->names[idx].dev = inode->i_sb->s_dev; |
... | ... | @@ -1242,7 +1256,8 @@ |
1242 | 1256 | context->names[idx].gid = inode->i_gid; |
1243 | 1257 | context->names[idx].rdev = inode->i_rdev; |
1244 | 1258 | audit_inode_context(idx, inode); |
1245 | - } | |
1259 | + } else | |
1260 | + context->names[idx].ino = (unsigned long)-1; | |
1246 | 1261 | } |
1247 | 1262 | |
1248 | 1263 | /** |