diff options
| author | Jeff Layton <jlayton@redhat.com> | 2012-10-10 15:25:23 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-12 00:32:01 -0400 |
| commit | bfcec7087458812f575d9022b2d151641f34ee84 (patch) | |
| tree | 6c0f7dd3b016992da8d113ceeaae404c6abc03a1 /kernel | |
| parent | 78e2e802a8519031e5858595070b39713e26340d (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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/audit.h | 1 | ||||
| -rw-r--r-- | kernel/auditfilter.c | 30 | ||||
| -rw-r--r-- | kernel/auditsc.c | 41 |
3 files changed, 60 insertions, 12 deletions
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); | |||
| 78 | extern int audit_comparator(const u32 left, const u32 op, const u32 right); | 78 | extern int audit_comparator(const u32 left, const u32 op, const u32 right); |
| 79 | extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); | 79 | extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); |
| 80 | extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); | 80 | extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); |
| 81 | extern int parent_len(const char *path); | ||
| 81 | extern int audit_compare_dname_path(const char *dname, const char *path, | 82 | extern int audit_compare_dname_path(const char *dname, const char *path, |
| 82 | int *dirlen); | 83 | int *dirlen); |
| 83 | extern struct sk_buff * audit_make_reply(int pid, int seq, int type, | 84 | extern 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 | */ | ||
| 1305 | int 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. */ |
| 1303 | int audit_compare_dname_path(const char *dname, const char *path, | 1333 | int 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 | */ |
| 2144 | void __audit_inode(const char *name, const struct dentry *dentry) | 2143 | void __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 | ||
| 2161 | out_alloc: | 2172 | out_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; |
| 2166 | out: | 2179 | out: |
| 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 |
