diff options
author | Richard Guy Briggs <rgb@redhat.com> | 2019-01-23 13:35:00 -0500 |
---|---|---|
committer | Paul Moore <paul@paul-moore.com> | 2019-01-30 20:51:47 -0500 |
commit | 57d4657716aca81ef4d7ec23e8123d26e3d28954 (patch) | |
tree | 61af3d955d7a01767f7d1e6ede67ca6096cc8a07 | |
parent | 05c7a9cb2727cd3c3d8e767f48e5cd18486a8d16 (diff) |
audit: ignore fcaps on umount
Don't fetch fcaps when umount2 is called to avoid a process hang while
it waits for the missing resource to (possibly never) re-appear.
Note the comment above user_path_mountpoint_at():
* A umount is a special case for path walking. We're not actually interested
* in the inode in this situation, and ESTALE errors can be a problem. We
* simply want track down the dentry and vfsmount attached at the mountpoint
* and avoid revalidating the last component.
This can happen on ceph, cifs, 9p, lustre, fuse (gluster) or NFS.
Please see the github issue tracker
https://github.com/linux-audit/audit-kernel/issues/100
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
[PM: merge fuzz in audit_log_fcaps()]
Signed-off-by: Paul Moore <paul@paul-moore.com>
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | fs/namespace.c | 2 | ||||
-rw-r--r-- | include/linux/audit.h | 15 | ||||
-rw-r--r-- | include/linux/namei.h | 3 | ||||
-rw-r--r-- | kernel/audit.c | 10 | ||||
-rw-r--r-- | kernel/audit.h | 2 | ||||
-rw-r--r-- | kernel/auditsc.c | 6 |
7 files changed, 29 insertions, 11 deletions
diff --git a/fs/namei.c b/fs/namei.c index 914178cdbe94..87d7710a2e1d 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2720,7 +2720,7 @@ filename_mountpoint(int dfd, struct filename *name, struct path *path, | |||
2720 | if (unlikely(error == -ESTALE)) | 2720 | if (unlikely(error == -ESTALE)) |
2721 | error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path); | 2721 | error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path); |
2722 | if (likely(!error)) | 2722 | if (likely(!error)) |
2723 | audit_inode(name, path->dentry, 0); | 2723 | audit_inode(name, path->dentry, flags & LOOKUP_NO_EVAL); |
2724 | restore_nameidata(); | 2724 | restore_nameidata(); |
2725 | putname(name); | 2725 | putname(name); |
2726 | return error; | 2726 | return error; |
diff --git a/fs/namespace.c b/fs/namespace.c index a677b59efd74..e5de0e372df2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1640,6 +1640,8 @@ int ksys_umount(char __user *name, int flags) | |||
1640 | if (!(flags & UMOUNT_NOFOLLOW)) | 1640 | if (!(flags & UMOUNT_NOFOLLOW)) |
1641 | lookup_flags |= LOOKUP_FOLLOW; | 1641 | lookup_flags |= LOOKUP_FOLLOW; |
1642 | 1642 | ||
1643 | lookup_flags |= LOOKUP_NO_EVAL; | ||
1644 | |||
1643 | retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path); | 1645 | retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path); |
1644 | if (retval) | 1646 | if (retval) |
1645 | goto out; | 1647 | goto out; |
diff --git a/include/linux/audit.h b/include/linux/audit.h index ecb5d317d6a2..29251b18331a 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | #include <linux/ptrace.h> | 27 | #include <linux/ptrace.h> |
28 | #include <linux/namei.h> /* LOOKUP_* */ | ||
28 | #include <uapi/linux/audit.h> | 29 | #include <uapi/linux/audit.h> |
29 | 30 | ||
30 | #define AUDIT_INO_UNSET ((unsigned long)-1) | 31 | #define AUDIT_INO_UNSET ((unsigned long)-1) |
@@ -248,6 +249,7 @@ extern void __audit_getname(struct filename *name); | |||
248 | 249 | ||
249 | #define AUDIT_INODE_PARENT 1 /* dentry represents the parent */ | 250 | #define AUDIT_INODE_PARENT 1 /* dentry represents the parent */ |
250 | #define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */ | 251 | #define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */ |
252 | #define AUDIT_INODE_NOEVAL 4 /* audit record incomplete */ | ||
251 | extern void __audit_inode(struct filename *name, const struct dentry *dentry, | 253 | extern void __audit_inode(struct filename *name, const struct dentry *dentry, |
252 | unsigned int flags); | 254 | unsigned int flags); |
253 | extern void __audit_file(const struct file *); | 255 | extern void __audit_file(const struct file *); |
@@ -308,12 +310,15 @@ static inline void audit_getname(struct filename *name) | |||
308 | } | 310 | } |
309 | static inline void audit_inode(struct filename *name, | 311 | static inline void audit_inode(struct filename *name, |
310 | const struct dentry *dentry, | 312 | const struct dentry *dentry, |
311 | unsigned int parent) { | 313 | unsigned int flags) { |
312 | if (unlikely(!audit_dummy_context())) { | 314 | if (unlikely(!audit_dummy_context())) { |
313 | unsigned int flags = 0; | 315 | unsigned int aflags = 0; |
314 | if (parent) | 316 | |
315 | flags |= AUDIT_INODE_PARENT; | 317 | if (flags & LOOKUP_PARENT) |
316 | __audit_inode(name, dentry, flags); | 318 | aflags |= AUDIT_INODE_PARENT; |
319 | if (flags & LOOKUP_NO_EVAL) | ||
320 | aflags |= AUDIT_INODE_NOEVAL; | ||
321 | __audit_inode(name, dentry, aflags); | ||
317 | } | 322 | } |
318 | } | 323 | } |
319 | static inline void audit_file(struct file *file) | 324 | static inline void audit_file(struct file *file) |
diff --git a/include/linux/namei.h b/include/linux/namei.h index a78606e8e3df..9138b4471dbf 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
@@ -24,6 +24,8 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; | |||
24 | * - internal "there are more path components" flag | 24 | * - internal "there are more path components" flag |
25 | * - dentry cache is untrusted; force a real lookup | 25 | * - dentry cache is untrusted; force a real lookup |
26 | * - suppress terminal automount | 26 | * - suppress terminal automount |
27 | * - skip revalidation | ||
28 | * - don't fetch xattrs on audit_inode | ||
27 | */ | 29 | */ |
28 | #define LOOKUP_FOLLOW 0x0001 | 30 | #define LOOKUP_FOLLOW 0x0001 |
29 | #define LOOKUP_DIRECTORY 0x0002 | 31 | #define LOOKUP_DIRECTORY 0x0002 |
@@ -33,6 +35,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; | |||
33 | #define LOOKUP_REVAL 0x0020 | 35 | #define LOOKUP_REVAL 0x0020 |
34 | #define LOOKUP_RCU 0x0040 | 36 | #define LOOKUP_RCU 0x0040 |
35 | #define LOOKUP_NO_REVAL 0x0080 | 37 | #define LOOKUP_NO_REVAL 0x0080 |
38 | #define LOOKUP_NO_EVAL 0x0100 | ||
36 | 39 | ||
37 | /* | 40 | /* |
38 | * Intent data | 41 | * Intent data |
diff --git a/kernel/audit.c b/kernel/audit.c index 3f3f1888cac7..b7177a8def2e 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -2082,6 +2082,10 @@ void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap) | |||
2082 | 2082 | ||
2083 | static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) | 2083 | static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) |
2084 | { | 2084 | { |
2085 | if (name->fcap_ver == -1) { | ||
2086 | audit_log_format(ab, " cap_fe=? cap_fver=? cap_fp=? cap_fi=?"); | ||
2087 | return; | ||
2088 | } | ||
2085 | audit_log_cap(ab, "cap_fp", &name->fcap.permitted); | 2089 | audit_log_cap(ab, "cap_fp", &name->fcap.permitted); |
2086 | audit_log_cap(ab, "cap_fi", &name->fcap.inheritable); | 2090 | audit_log_cap(ab, "cap_fi", &name->fcap.inheritable); |
2087 | audit_log_format(ab, " cap_fe=%d cap_fver=%x cap_frootid=%d", | 2091 | audit_log_format(ab, " cap_fe=%d cap_fver=%x cap_frootid=%d", |
@@ -2114,7 +2118,7 @@ static inline int audit_copy_fcaps(struct audit_names *name, | |||
2114 | 2118 | ||
2115 | /* Copy inode data into an audit_names. */ | 2119 | /* Copy inode data into an audit_names. */ |
2116 | void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, | 2120 | void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, |
2117 | struct inode *inode) | 2121 | struct inode *inode, unsigned int flags) |
2118 | { | 2122 | { |
2119 | name->ino = inode->i_ino; | 2123 | name->ino = inode->i_ino; |
2120 | name->dev = inode->i_sb->s_dev; | 2124 | name->dev = inode->i_sb->s_dev; |
@@ -2123,6 +2127,10 @@ void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, | |||
2123 | name->gid = inode->i_gid; | 2127 | name->gid = inode->i_gid; |
2124 | name->rdev = inode->i_rdev; | 2128 | name->rdev = inode->i_rdev; |
2125 | security_inode_getsecid(inode, &name->osid); | 2129 | security_inode_getsecid(inode, &name->osid); |
2130 | if (flags & AUDIT_INODE_NOEVAL) { | ||
2131 | name->fcap_ver = -1; | ||
2132 | return; | ||
2133 | } | ||
2126 | audit_copy_fcaps(name, dentry); | 2134 | audit_copy_fcaps(name, dentry); |
2127 | } | 2135 | } |
2128 | 2136 | ||
diff --git a/kernel/audit.h b/kernel/audit.h index 9acb8691ed87..002f0f7ba732 100644 --- a/kernel/audit.h +++ b/kernel/audit.h | |||
@@ -215,7 +215,7 @@ extern void audit_log_session_info(struct audit_buffer *ab); | |||
215 | 215 | ||
216 | extern void audit_copy_inode(struct audit_names *name, | 216 | extern void audit_copy_inode(struct audit_names *name, |
217 | const struct dentry *dentry, | 217 | const struct dentry *dentry, |
218 | struct inode *inode); | 218 | struct inode *inode, unsigned int flags); |
219 | extern void audit_log_cap(struct audit_buffer *ab, char *prefix, | 219 | extern void audit_log_cap(struct audit_buffer *ab, char *prefix, |
220 | kernel_cap_t *cap); | 220 | kernel_cap_t *cap); |
221 | extern void audit_log_name(struct audit_context *context, | 221 | extern void audit_log_name(struct audit_context *context, |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index a2696ce790f9..68da71001096 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -1856,7 +1856,7 @@ out: | |||
1856 | n->type = AUDIT_TYPE_NORMAL; | 1856 | n->type = AUDIT_TYPE_NORMAL; |
1857 | } | 1857 | } |
1858 | handle_path(dentry); | 1858 | handle_path(dentry); |
1859 | audit_copy_inode(n, dentry, inode); | 1859 | audit_copy_inode(n, dentry, inode, flags & AUDIT_INODE_NOEVAL); |
1860 | } | 1860 | } |
1861 | 1861 | ||
1862 | void __audit_file(const struct file *file) | 1862 | void __audit_file(const struct file *file) |
@@ -1955,7 +1955,7 @@ void __audit_inode_child(struct inode *parent, | |||
1955 | n = audit_alloc_name(context, AUDIT_TYPE_PARENT); | 1955 | n = audit_alloc_name(context, AUDIT_TYPE_PARENT); |
1956 | if (!n) | 1956 | if (!n) |
1957 | return; | 1957 | return; |
1958 | audit_copy_inode(n, NULL, parent); | 1958 | audit_copy_inode(n, NULL, parent, 0); |
1959 | } | 1959 | } |
1960 | 1960 | ||
1961 | if (!found_child) { | 1961 | if (!found_child) { |
@@ -1974,7 +1974,7 @@ void __audit_inode_child(struct inode *parent, | |||
1974 | } | 1974 | } |
1975 | 1975 | ||
1976 | if (inode) | 1976 | if (inode) |
1977 | audit_copy_inode(found_child, dentry, inode); | 1977 | audit_copy_inode(found_child, dentry, inode, 0); |
1978 | else | 1978 | else |
1979 | found_child->ino = AUDIT_INO_UNSET; | 1979 | found_child->ino = AUDIT_INO_UNSET; |
1980 | } | 1980 | } |