diff options
-rw-r--r-- | fs/btrfs/ioctl.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | include/linux/audit.h | 16 | ||||
-rw-r--r-- | include/linux/fsnotify.h | 8 | ||||
-rw-r--r-- | kernel/auditsc.c | 57 |
5 files changed, 47 insertions, 38 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 49f4d59ac2c7..61168805f175 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -638,7 +638,7 @@ static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir) | |||
638 | return -ENOENT; | 638 | return -ENOENT; |
639 | 639 | ||
640 | BUG_ON(victim->d_parent->d_inode != dir); | 640 | BUG_ON(victim->d_parent->d_inode != dir); |
641 | audit_inode_child(dir, victim); | 641 | audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); |
642 | 642 | ||
643 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); | 643 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); |
644 | if (error) | 644 | if (error) |
diff --git a/fs/namei.c b/fs/namei.c index 6a92d988573f..ca14d8432d3d 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2176,7 +2176,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) | |||
2176 | return -ENOENT; | 2176 | return -ENOENT; |
2177 | 2177 | ||
2178 | BUG_ON(victim->d_parent->d_inode != dir); | 2178 | BUG_ON(victim->d_parent->d_inode != dir); |
2179 | audit_inode_child(dir, victim); | 2179 | audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); |
2180 | 2180 | ||
2181 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); | 2181 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); |
2182 | if (error) | 2182 | if (error) |
diff --git a/include/linux/audit.h b/include/linux/audit.h index b11f517dce04..3df643d1ac5b 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -457,6 +457,8 @@ extern int audit_classify_arch(int arch); | |||
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 | #define AUDIT_TYPE_PARENT 2 /* a parent audit record */ |
460 | #define AUDIT_TYPE_CHILD_DELETE 3 /* a child being deleted */ | ||
461 | #define AUDIT_TYPE_CHILD_CREATE 4 /* a child being created */ | ||
460 | 462 | ||
461 | #ifdef CONFIG_AUDITSYSCALL | 463 | #ifdef CONFIG_AUDITSYSCALL |
462 | /* These are defined in auditsc.c */ | 464 | /* These are defined in auditsc.c */ |
@@ -472,7 +474,8 @@ extern void audit_putname(const char *name); | |||
472 | extern void __audit_inode(const char *name, const struct dentry *dentry, | 474 | extern void __audit_inode(const char *name, const struct dentry *dentry, |
473 | unsigned int parent); | 475 | unsigned int parent); |
474 | extern void __audit_inode_child(const struct inode *parent, | 476 | extern void __audit_inode_child(const struct inode *parent, |
475 | const struct dentry *dentry); | 477 | const struct dentry *dentry, |
478 | const unsigned char type); | ||
476 | extern void __audit_seccomp(unsigned long syscall, long signr, int code); | 479 | extern void __audit_seccomp(unsigned long syscall, long signr, int code); |
477 | extern void __audit_ptrace(struct task_struct *t); | 480 | extern void __audit_ptrace(struct task_struct *t); |
478 | 481 | ||
@@ -513,9 +516,10 @@ static inline void audit_inode(const char *name, const struct dentry *dentry, | |||
513 | __audit_inode(name, dentry, parent); | 516 | __audit_inode(name, dentry, parent); |
514 | } | 517 | } |
515 | static inline void audit_inode_child(const struct inode *parent, | 518 | static inline void audit_inode_child(const struct inode *parent, |
516 | const struct dentry *dentry) { | 519 | const struct dentry *dentry, |
520 | const unsigned char type) { | ||
517 | if (unlikely(!audit_dummy_context())) | 521 | if (unlikely(!audit_dummy_context())) |
518 | __audit_inode_child(parent, dentry); | 522 | __audit_inode_child(parent, dentry, type); |
519 | } | 523 | } |
520 | void audit_core_dumps(long signr); | 524 | void audit_core_dumps(long signr); |
521 | 525 | ||
@@ -667,13 +671,15 @@ static inline void __audit_inode(const char *name, const struct dentry *dentry, | |||
667 | unsigned int parent) | 671 | unsigned int parent) |
668 | { } | 672 | { } |
669 | static inline void __audit_inode_child(const struct inode *parent, | 673 | static inline void __audit_inode_child(const struct inode *parent, |
670 | const struct dentry *dentry) | 674 | const struct dentry *dentry, |
675 | const unsigned char type) | ||
671 | { } | 676 | { } |
672 | static inline void audit_inode(const char *name, const struct dentry *dentry, | 677 | static inline void audit_inode(const char *name, const struct dentry *dentry, |
673 | unsigned int parent) | 678 | unsigned int parent) |
674 | { } | 679 | { } |
675 | static inline void audit_inode_child(const struct inode *parent, | 680 | static inline void audit_inode_child(const struct inode *parent, |
676 | const struct dentry *dentry) | 681 | const struct dentry *dentry, |
682 | const unsigned char type) | ||
677 | { } | 683 | { } |
678 | static inline void audit_core_dumps(long signr) | 684 | static inline void audit_core_dumps(long signr) |
679 | { } | 685 | { } |
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 9c284714977d..0fbfb4646d1b 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h | |||
@@ -109,7 +109,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, | |||
109 | 109 | ||
110 | if (source) | 110 | if (source) |
111 | fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0); | 111 | fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0); |
112 | audit_inode_child(new_dir, moved); | 112 | audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE); |
113 | } | 113 | } |
114 | 114 | ||
115 | /* | 115 | /* |
@@ -155,7 +155,7 @@ static inline void fsnotify_inoderemove(struct inode *inode) | |||
155 | */ | 155 | */ |
156 | static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) | 156 | static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) |
157 | { | 157 | { |
158 | audit_inode_child(inode, dentry); | 158 | audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); |
159 | 159 | ||
160 | fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); | 160 | fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); |
161 | } | 161 | } |
@@ -168,7 +168,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) | |||
168 | static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry) | 168 | static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry) |
169 | { | 169 | { |
170 | fsnotify_link_count(inode); | 170 | fsnotify_link_count(inode); |
171 | audit_inode_child(dir, new_dentry); | 171 | audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE); |
172 | 172 | ||
173 | fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0); | 173 | fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0); |
174 | } | 174 | } |
@@ -181,7 +181,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) | |||
181 | __u32 mask = (FS_CREATE | FS_ISDIR); | 181 | __u32 mask = (FS_CREATE | FS_ISDIR); |
182 | struct inode *d_inode = dentry->d_inode; | 182 | struct inode *d_inode = dentry->d_inode; |
183 | 183 | ||
184 | audit_inode_child(inode, dentry); | 184 | audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); |
185 | 185 | ||
186 | fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); | 186 | fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); |
187 | } | 187 | } |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 0160a68b4d7f..d147585e9ef3 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -2189,6 +2189,7 @@ out: | |||
2189 | * __audit_inode_child - collect inode info for created/removed objects | 2189 | * __audit_inode_child - collect inode info for created/removed objects |
2190 | * @parent: inode of dentry parent | 2190 | * @parent: inode of dentry parent |
2191 | * @dentry: dentry being audited | 2191 | * @dentry: dentry being audited |
2192 | * @type: AUDIT_TYPE_* value that we're looking for | ||
2192 | * | 2193 | * |
2193 | * For syscalls that create or remove filesystem objects, audit_inode | 2194 | * For syscalls that create or remove filesystem objects, audit_inode |
2194 | * can only collect information for the filesystem object's parent. | 2195 | * can only collect information for the filesystem object's parent. |
@@ -2199,13 +2200,13 @@ out: | |||
2199 | * unsuccessful attempts. | 2200 | * unsuccessful attempts. |
2200 | */ | 2201 | */ |
2201 | void __audit_inode_child(const struct inode *parent, | 2202 | void __audit_inode_child(const struct inode *parent, |
2202 | const struct dentry *dentry) | 2203 | const struct dentry *dentry, |
2204 | const unsigned char type) | ||
2203 | { | 2205 | { |
2204 | struct audit_context *context = current->audit_context; | 2206 | struct audit_context *context = current->audit_context; |
2205 | const char *found_parent = NULL, *found_child = NULL; | ||
2206 | const struct inode *inode = dentry->d_inode; | 2207 | const struct inode *inode = dentry->d_inode; |
2207 | const char *dname = dentry->d_name.name; | 2208 | const char *dname = dentry->d_name.name; |
2208 | struct audit_names *n; | 2209 | struct audit_names *n, *found_parent = NULL, *found_child = NULL; |
2209 | 2210 | ||
2210 | if (!context->in_syscall) | 2211 | if (!context->in_syscall) |
2211 | return; | 2212 | return; |
@@ -2213,63 +2214,65 @@ void __audit_inode_child(const struct inode *parent, | |||
2213 | if (inode) | 2214 | if (inode) |
2214 | handle_one(inode); | 2215 | handle_one(inode); |
2215 | 2216 | ||
2216 | /* parent is more likely, look for it first */ | 2217 | /* look for a parent entry first */ |
2217 | list_for_each_entry(n, &context->names_list, list) { | 2218 | list_for_each_entry(n, &context->names_list, list) { |
2218 | if (!n->name) | 2219 | if (!n->name || n->type != AUDIT_TYPE_PARENT) |
2219 | continue; | 2220 | continue; |
2220 | 2221 | ||
2221 | if (n->ino == parent->i_ino && | 2222 | if (n->ino == parent->i_ino && |
2222 | !audit_compare_dname_path(dname, n->name, n->name_len)) { | 2223 | !audit_compare_dname_path(dname, n->name, n->name_len)) { |
2223 | found_parent = n->name; | 2224 | found_parent = n; |
2224 | goto add_names; | 2225 | break; |
2225 | } | 2226 | } |
2226 | } | 2227 | } |
2227 | 2228 | ||
2228 | /* no matching parent, look for matching child */ | 2229 | /* is there a matching child entry? */ |
2229 | list_for_each_entry(n, &context->names_list, list) { | 2230 | list_for_each_entry(n, &context->names_list, list) { |
2230 | if (!n->name) | 2231 | /* can only match entries that have a name */ |
2232 | if (!n->name || n->type != type) | ||
2233 | continue; | ||
2234 | |||
2235 | /* if we found a parent, make sure this one is a child of it */ | ||
2236 | if (found_parent && (n->name != found_parent->name)) | ||
2231 | continue; | 2237 | continue; |
2232 | 2238 | ||
2233 | /* strcmp() is the more likely scenario */ | ||
2234 | if (!strcmp(dname, n->name) || | 2239 | if (!strcmp(dname, n->name) || |
2235 | !audit_compare_dname_path(dname, n->name, | 2240 | !audit_compare_dname_path(dname, n->name, |
2241 | found_parent ? | ||
2242 | found_parent->name_len : | ||
2236 | AUDIT_NAME_FULL)) { | 2243 | AUDIT_NAME_FULL)) { |
2237 | if (inode) | 2244 | found_child = n; |
2238 | audit_copy_inode(n, dentry, inode); | 2245 | break; |
2239 | else | ||
2240 | n->ino = (unsigned long)-1; | ||
2241 | n->type = AUDIT_TYPE_NORMAL; | ||
2242 | found_child = n->name; | ||
2243 | goto add_names; | ||
2244 | } | 2246 | } |
2245 | } | 2247 | } |
2246 | 2248 | ||
2247 | add_names: | ||
2248 | if (!found_parent) { | 2249 | if (!found_parent) { |
2249 | n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); | 2250 | /* create a new, "anonymous" parent record */ |
2251 | n = audit_alloc_name(context, AUDIT_TYPE_PARENT); | ||
2250 | if (!n) | 2252 | if (!n) |
2251 | return; | 2253 | return; |
2252 | audit_copy_inode(n, NULL, parent); | 2254 | audit_copy_inode(n, NULL, parent); |
2253 | } | 2255 | } |
2254 | 2256 | ||
2255 | if (!found_child) { | 2257 | if (!found_child) { |
2256 | n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); | 2258 | found_child = audit_alloc_name(context, type); |
2257 | if (!n) | 2259 | if (!found_child) |
2258 | return; | 2260 | return; |
2259 | 2261 | ||
2260 | /* Re-use the name belonging to the slot for a matching parent | 2262 | /* Re-use the name belonging to the slot for a matching parent |
2261 | * directory. All names for this context are relinquished in | 2263 | * directory. All names for this context are relinquished in |
2262 | * audit_free_names() */ | 2264 | * audit_free_names() */ |
2263 | if (found_parent) { | 2265 | if (found_parent) { |
2264 | n->name = found_parent; | 2266 | found_child->name = found_parent->name; |
2265 | n->name_len = AUDIT_NAME_FULL; | 2267 | found_child->name_len = AUDIT_NAME_FULL; |
2266 | /* don't call __putname() */ | 2268 | /* don't call __putname() */ |
2267 | n->name_put = false; | 2269 | found_child->name_put = false; |
2268 | } | 2270 | } |
2269 | |||
2270 | if (inode) | ||
2271 | audit_copy_inode(n, dentry, inode); | ||
2272 | } | 2271 | } |
2272 | if (inode) | ||
2273 | audit_copy_inode(found_child, dentry, inode); | ||
2274 | else | ||
2275 | found_child->ino = (unsigned long)-1; | ||
2273 | } | 2276 | } |
2274 | EXPORT_SYMBOL_GPL(__audit_inode_child); | 2277 | EXPORT_SYMBOL_GPL(__audit_inode_child); |
2275 | 2278 | ||