aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-12 21:04:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-12 21:04:42 -0400
commit8418263e3547ed3816475e4c55a77004f0426ee6 (patch)
tree97c548b16e6753e1911870d824a07b7e726b6229 /kernel
parentccff9b1db693062b0a9c9070f4304deb47ef215c (diff)
parentf81700bd831efcd12eb7f0e66b24b16c2ad00a32 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull third pile of VFS updates from Al Viro: "Stuff from Jeff Layton, mostly. Sanitizing interplay between audit and namei, removing a lot of insanity from audit_inode() mess and getting things ready for his ESTALE patchset." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: procfs: don't need a PATH_MAX allocation to hold a string representation of an int vfs: embed struct filename inside of names_cache allocation if possible audit: make audit_inode take struct filename vfs: make path_openat take a struct filename pointer vfs: turn do_path_lookup into wrapper around struct filename variant audit: allow audit code to satisfy getname requests from its names_list vfs: define struct filename and have getname() return it vfs: unexport getname and putname symbols acct: constify the name arg to acct_on vfs: allocate page instead of names_cache buffer in mount_block_root audit: overhaul __audit_inode_child to accomodate retrying audit: optimize audit_compare_dname_path audit: make audit_compare_dname_path use parent_len helper audit: remove dirlen argument to audit_compare_dname_path audit: set the name_len in audit_inode for parent lookups audit: add a new "type" field to audit_names struct audit: reverse arguments to audit_inode_child audit: no need to walk list in audit_inode if name is NULL audit: pass in dentry to audit_copy_inode wherever possible audit: remove unnecessary NULL ptr checks from do_path_lookup
Diffstat (limited to 'kernel')
-rw-r--r--kernel/acct.c6
-rw-r--r--kernel/audit.h7
-rw-r--r--kernel/audit_watch.c3
-rw-r--r--kernel/auditfilter.c65
-rw-r--r--kernel/auditsc.c217
5 files changed, 199 insertions, 99 deletions
diff --git a/kernel/acct.c b/kernel/acct.c
index 6cd7529c9e6a..051e071a06e7 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -193,7 +193,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file,
193 } 193 }
194} 194}
195 195
196static int acct_on(char *name) 196static int acct_on(struct filename *pathname)
197{ 197{
198 struct file *file; 198 struct file *file;
199 struct vfsmount *mnt; 199 struct vfsmount *mnt;
@@ -201,7 +201,7 @@ static int acct_on(char *name)
201 struct bsd_acct_struct *acct = NULL; 201 struct bsd_acct_struct *acct = NULL;
202 202
203 /* Difference from BSD - they don't do O_APPEND */ 203 /* Difference from BSD - they don't do O_APPEND */
204 file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); 204 file = file_open_name(pathname, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
205 if (IS_ERR(file)) 205 if (IS_ERR(file))
206 return PTR_ERR(file); 206 return PTR_ERR(file);
207 207
@@ -260,7 +260,7 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
260 return -EPERM; 260 return -EPERM;
261 261
262 if (name) { 262 if (name) {
263 char *tmp = getname(name); 263 struct filename *tmp = getname(name);
264 if (IS_ERR(tmp)) 264 if (IS_ERR(tmp))
265 return (PTR_ERR(tmp)); 265 return (PTR_ERR(tmp));
266 error = acct_on(tmp); 266 error = acct_on(tmp);
diff --git a/kernel/audit.h b/kernel/audit.h
index 9eb3d79482b6..d51cba868e1b 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -74,12 +74,15 @@ static inline int audit_hash_ino(u32 ino)
74 return (ino & (AUDIT_INODE_BUCKETS-1)); 74 return (ino & (AUDIT_INODE_BUCKETS-1));
75} 75}
76 76
77/* Indicates that audit should log the full pathname. */
78#define AUDIT_NAME_FULL -1
79
77extern int audit_match_class(int class, unsigned syscall); 80extern int audit_match_class(int class, unsigned syscall);
78extern int audit_comparator(const u32 left, const u32 op, const u32 right); 81extern int audit_comparator(const u32 left, const u32 op, const u32 right);
79extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); 82extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right);
80extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); 83extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right);
81extern int audit_compare_dname_path(const char *dname, const char *path, 84extern int parent_len(const char *path);
82 int *dirlen); 85extern int audit_compare_dname_path(const char *dname, const char *path, int plen);
83extern struct sk_buff * audit_make_reply(int pid, int seq, int type, 86extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
84 int done, int multi, 87 int done, int multi,
85 const void *payload, int size); 88 const void *payload, int size);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 1c22ec3d87bc..9a9ae6e3d290 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -265,7 +265,8 @@ static void audit_update_watch(struct audit_parent *parent,
265 /* Run all of the watches on this parent looking for the one that 265 /* Run all of the watches on this parent looking for the one that
266 * matches the given dname */ 266 * matches the given dname */
267 list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { 267 list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
268 if (audit_compare_dname_path(dname, owatch->path, NULL)) 268 if (audit_compare_dname_path(dname, owatch->path,
269 AUDIT_NAME_FULL))
269 continue; 270 continue;
270 271
271 /* If the update involves invalidating rules, do the inode-based 272 /* If the update involves invalidating rules, do the inode-based
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index c4bcdbaf4d4d..7f19f23d38a3 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1298,41 +1298,60 @@ int audit_gid_comparator(kgid_t left, u32 op, kgid_t right)
1298 } 1298 }
1299} 1299}
1300 1300
1301/* Compare given dentry name with last component in given path, 1301/**
1302 * return of 0 indicates a match. */ 1302 * parent_len - find the length of the parent portion of a pathname
1303int audit_compare_dname_path(const char *dname, const char *path, 1303 * @path: pathname of which to determine length
1304 int *dirlen) 1304 */
1305int parent_len(const char *path)
1305{ 1306{
1306 int dlen, plen; 1307 int plen;
1307 const char *p; 1308 const char *p;
1308 1309
1309 if (!dname || !path)
1310 return 1;
1311
1312 dlen = strlen(dname);
1313 plen = strlen(path); 1310 plen = strlen(path);
1314 if (plen < dlen) 1311
1315 return 1; 1312 if (plen == 0)
1313 return plen;
1316 1314
1317 /* disregard trailing slashes */ 1315 /* disregard trailing slashes */
1318 p = path + plen - 1; 1316 p = path + plen - 1;
1319 while ((*p == '/') && (p > path)) 1317 while ((*p == '/') && (p > path))
1320 p--; 1318 p--;
1321 1319
1322 /* find last path component */ 1320 /* walk backward until we find the next slash or hit beginning */
1323 p = p - dlen + 1; 1321 while ((*p != '/') && (p > path))
1324 if (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
1331/**
1332 * audit_compare_dname_path - compare given dentry name with last component in
1333 * given path. Return of 0 indicates a match.
1334 * @dname: dentry name that we're comparing
1335 * @path: full pathname that we're comparing
1336 * @parentlen: length of the parent if known. Passing in AUDIT_NAME_FULL
1337 * here indicates that we must compute this value.
1338 */
1339int audit_compare_dname_path(const char *dname, const char *path, int parentlen)
1340{
1341 int dlen, pathlen;
1342 const char *p;
1343
1344 dlen = strlen(dname);
1345 pathlen = strlen(path);
1346 if (pathlen < dlen)
1325 return 1; 1347 return 1;
1326 else if (p > path) {
1327 if (*--p != '/')
1328 return 1;
1329 else
1330 p++;
1331 }
1332 1348
1333 /* return length of path's directory component */ 1349 parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
1334 if (dirlen) 1350 if (pathlen - parentlen != dlen)
1335 *dirlen = p - path; 1351 return 1;
1352
1353 p = path + parentlen;
1354
1336 return strncmp(p, dname, dlen); 1355 return strncmp(p, dname, dlen);
1337} 1356}
1338 1357
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f4a7756f999c..2f186ed80c40 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -81,9 +81,6 @@
81 * a name dynamically and also add those to the list anchored by names_list. */ 81 * a name dynamically and also add those to the list anchored by names_list. */
82#define AUDIT_NAMES 5 82#define AUDIT_NAMES 5
83 83
84/* Indicates that audit should log the full pathname. */
85#define AUDIT_NAME_FULL -1
86
87/* no execve audit message should be longer than this (userspace limits) */ 84/* no execve audit message should be longer than this (userspace limits) */
88#define MAX_EXECVE_AUDIT_LEN 7500 85#define MAX_EXECVE_AUDIT_LEN 7500
89 86
@@ -106,27 +103,29 @@ struct audit_cap_data {
106 * we don't let putname() free it (instead we free all of the saved 103 * we don't let putname() free it (instead we free all of the saved
107 * pointers at syscall exit time). 104 * pointers at syscall exit time).
108 * 105 *
109 * Further, in fs/namei.c:path_lookup() we store the inode and device. */ 106 * Further, in fs/namei.c:path_lookup() we store the inode and device.
107 */
110struct audit_names { 108struct audit_names {
111 struct list_head list; /* audit_context->names_list */ 109 struct list_head list; /* audit_context->names_list */
112 const char *name; 110 struct filename *name;
113 unsigned long ino; 111 unsigned long ino;
114 dev_t dev; 112 dev_t dev;
115 umode_t mode; 113 umode_t mode;
116 kuid_t uid; 114 kuid_t uid;
117 kgid_t gid; 115 kgid_t gid;
118 dev_t rdev; 116 dev_t rdev;
119 u32 osid; 117 u32 osid;
120 struct audit_cap_data fcap; 118 struct audit_cap_data fcap;
121 unsigned int fcap_ver; 119 unsigned int fcap_ver;
122 int name_len; /* number of name's characters to log */ 120 int name_len; /* number of name's characters to log */
123 bool name_put; /* call __putname() for this name */ 121 unsigned char type; /* record type */
122 bool name_put; /* call __putname() for this name */
124 /* 123 /*
125 * This was an allocated audit_names and not from the array of 124 * This was an allocated audit_names and not from the array of
126 * names allocated in the task audit context. Thus this name 125 * names allocated in the task audit context. Thus this name
127 * should be freed on syscall exit 126 * should be freed on syscall exit
128 */ 127 */
129 bool should_free; 128 bool should_free;
130}; 129};
131 130
132struct audit_aux_data { 131struct audit_aux_data {
@@ -998,7 +997,7 @@ static inline void audit_free_names(struct audit_context *context)
998 context->ino_count); 997 context->ino_count);
999 list_for_each_entry(n, &context->names_list, list) { 998 list_for_each_entry(n, &context->names_list, list) {
1000 printk(KERN_ERR "names[%d] = %p = %s\n", i, 999 printk(KERN_ERR "names[%d] = %p = %s\n", i,
1001 n->name, n->name ?: "(null)"); 1000 n->name, n->name->name ?: "(null)");
1002 } 1001 }
1003 dump_stack(); 1002 dump_stack();
1004 return; 1003 return;
@@ -1555,7 +1554,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
1555 case AUDIT_NAME_FULL: 1554 case AUDIT_NAME_FULL:
1556 /* log the full path */ 1555 /* log the full path */
1557 audit_log_format(ab, " name="); 1556 audit_log_format(ab, " name=");
1558 audit_log_untrustedstring(ab, n->name); 1557 audit_log_untrustedstring(ab, n->name->name);
1559 break; 1558 break;
1560 case 0: 1559 case 0:
1561 /* name was specified as a relative path and the 1560 /* name was specified as a relative path and the
@@ -1565,7 +1564,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
1565 default: 1564 default:
1566 /* log the name's directory component */ 1565 /* log the name's directory component */
1567 audit_log_format(ab, " name="); 1566 audit_log_format(ab, " name=");
1568 audit_log_n_untrustedstring(ab, n->name, 1567 audit_log_n_untrustedstring(ab, n->name->name,
1569 n->name_len); 1568 n->name_len);
1570 } 1569 }
1571 } else 1570 } else
@@ -1995,7 +1994,8 @@ retry:
1995#endif 1994#endif
1996} 1995}
1997 1996
1998static struct audit_names *audit_alloc_name(struct audit_context *context) 1997static struct audit_names *audit_alloc_name(struct audit_context *context,
1998 unsigned char type)
1999{ 1999{
2000 struct audit_names *aname; 2000 struct audit_names *aname;
2001 2001
@@ -2010,6 +2010,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context)
2010 } 2010 }
2011 2011
2012 aname->ino = (unsigned long)-1; 2012 aname->ino = (unsigned long)-1;
2013 aname->type = type;
2013 list_add_tail(&aname->list, &context->names_list); 2014 list_add_tail(&aname->list, &context->names_list);
2014 2015
2015 context->name_count++; 2016 context->name_count++;
@@ -2020,13 +2021,36 @@ static struct audit_names *audit_alloc_name(struct audit_context *context)
2020} 2021}
2021 2022
2022/** 2023/**
2024 * audit_reusename - fill out filename with info from existing entry
2025 * @uptr: userland ptr to pathname
2026 *
2027 * Search the audit_names list for the current audit context. If there is an
2028 * existing entry with a matching "uptr" then return the filename
2029 * associated with that audit_name. If not, return NULL.
2030 */
2031struct filename *
2032__audit_reusename(const __user char *uptr)
2033{
2034 struct audit_context *context = current->audit_context;
2035 struct audit_names *n;
2036
2037 list_for_each_entry(n, &context->names_list, list) {
2038 if (!n->name)
2039 continue;
2040 if (n->name->uptr == uptr)
2041 return n->name;
2042 }
2043 return NULL;
2044}
2045
2046/**
2023 * audit_getname - add a name to the list 2047 * audit_getname - add a name to the list
2024 * @name: name to add 2048 * @name: name to add
2025 * 2049 *
2026 * Add a name to the list of audit names for this context. 2050 * Add a name to the list of audit names for this context.
2027 * Called from fs/namei.c:getname(). 2051 * Called from fs/namei.c:getname().
2028 */ 2052 */
2029void __audit_getname(const char *name) 2053void __audit_getname(struct filename *name)
2030{ 2054{
2031 struct audit_context *context = current->audit_context; 2055 struct audit_context *context = current->audit_context;
2032 struct audit_names *n; 2056 struct audit_names *n;
@@ -2040,13 +2064,19 @@ void __audit_getname(const char *name)
2040 return; 2064 return;
2041 } 2065 }
2042 2066
2043 n = audit_alloc_name(context); 2067#if AUDIT_DEBUG
2068 /* The filename _must_ have a populated ->name */
2069 BUG_ON(!name->name);
2070#endif
2071
2072 n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
2044 if (!n) 2073 if (!n)
2045 return; 2074 return;
2046 2075
2047 n->name = name; 2076 n->name = name;
2048 n->name_len = AUDIT_NAME_FULL; 2077 n->name_len = AUDIT_NAME_FULL;
2049 n->name_put = true; 2078 n->name_put = true;
2079 name->aname = n;
2050 2080
2051 if (!context->pwd.dentry) 2081 if (!context->pwd.dentry)
2052 get_fs_pwd(current->fs, &context->pwd); 2082 get_fs_pwd(current->fs, &context->pwd);
@@ -2059,7 +2089,7 @@ void __audit_getname(const char *name)
2059 * then we delay the putname until syscall exit. 2089 * then we delay the putname until syscall exit.
2060 * Called from include/linux/fs.h:putname(). 2090 * Called from include/linux/fs.h:putname().
2061 */ 2091 */
2062void audit_putname(const char *name) 2092void audit_putname(struct filename *name)
2063{ 2093{
2064 struct audit_context *context = current->audit_context; 2094 struct audit_context *context = current->audit_context;
2065 2095
@@ -2074,7 +2104,7 @@ void audit_putname(const char *name)
2074 2104
2075 list_for_each_entry(n, &context->names_list, list) 2105 list_for_each_entry(n, &context->names_list, list)
2076 printk(KERN_ERR "name[%d] = %p = %s\n", i, 2106 printk(KERN_ERR "name[%d] = %p = %s\n", i,
2077 n->name, n->name ?: "(null)"); 2107 n->name, n->name->name ?: "(null)");
2078 } 2108 }
2079#endif 2109#endif
2080 __putname(name); 2110 __putname(name);
@@ -2088,8 +2118,8 @@ void audit_putname(const char *name)
2088 " put_count=%d\n", 2118 " put_count=%d\n",
2089 __FILE__, __LINE__, 2119 __FILE__, __LINE__,
2090 context->serial, context->major, 2120 context->serial, context->major,
2091 context->in_syscall, name, context->name_count, 2121 context->in_syscall, name->name,
2092 context->put_count); 2122 context->name_count, context->put_count);
2093 dump_stack(); 2123 dump_stack();
2094 } 2124 }
2095 } 2125 }
@@ -2132,13 +2162,13 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent
2132} 2162}
2133 2163
2134/** 2164/**
2135 * audit_inode - store the inode and device from a lookup 2165 * __audit_inode - store the inode and device from a lookup
2136 * @name: name being audited 2166 * @name: name being audited
2137 * @dentry: dentry being audited 2167 * @dentry: dentry being audited
2138 * 2168 * @parent: does this dentry represent the parent?
2139 * Called from fs/namei.c:path_lookup().
2140 */ 2169 */
2141void __audit_inode(const char *name, const struct dentry *dentry) 2170void __audit_inode(struct filename *name, const struct dentry *dentry,
2171 unsigned int parent)
2142{ 2172{
2143 struct audit_context *context = current->audit_context; 2173 struct audit_context *context = current->audit_context;
2144 const struct inode *inode = dentry->d_inode; 2174 const struct inode *inode = dentry->d_inode;
@@ -2147,24 +2177,69 @@ void __audit_inode(const char *name, const struct dentry *dentry)
2147 if (!context->in_syscall) 2177 if (!context->in_syscall)
2148 return; 2178 return;
2149 2179
2180 if (!name)
2181 goto out_alloc;
2182
2183#if AUDIT_DEBUG
2184 /* The struct filename _must_ have a populated ->name */
2185 BUG_ON(!name->name);
2186#endif
2187 /*
2188 * If we have a pointer to an audit_names entry already, then we can
2189 * just use it directly if the type is correct.
2190 */
2191 n = name->aname;
2192 if (n) {
2193 if (parent) {
2194 if (n->type == AUDIT_TYPE_PARENT ||
2195 n->type == AUDIT_TYPE_UNKNOWN)
2196 goto out;
2197 } else {
2198 if (n->type != AUDIT_TYPE_PARENT)
2199 goto out;
2200 }
2201 }
2202
2150 list_for_each_entry_reverse(n, &context->names_list, list) { 2203 list_for_each_entry_reverse(n, &context->names_list, list) {
2151 if (n->name && (n->name == name)) 2204 /* does the name pointer match? */
2152 goto out; 2205 if (!n->name || n->name->name != name->name)
2206 continue;
2207
2208 /* match the correct record type */
2209 if (parent) {
2210 if (n->type == AUDIT_TYPE_PARENT ||
2211 n->type == AUDIT_TYPE_UNKNOWN)
2212 goto out;
2213 } else {
2214 if (n->type != AUDIT_TYPE_PARENT)
2215 goto out;
2216 }
2153 } 2217 }
2154 2218
2155 /* unable to find the name from a previous getname() */ 2219out_alloc:
2156 n = audit_alloc_name(context); 2220 /* unable to find the name from a previous getname(). Allocate a new
2221 * anonymous entry.
2222 */
2223 n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
2157 if (!n) 2224 if (!n)
2158 return; 2225 return;
2159out: 2226out:
2227 if (parent) {
2228 n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;
2229 n->type = AUDIT_TYPE_PARENT;
2230 } else {
2231 n->name_len = AUDIT_NAME_FULL;
2232 n->type = AUDIT_TYPE_NORMAL;
2233 }
2160 handle_path(dentry); 2234 handle_path(dentry);
2161 audit_copy_inode(n, dentry, inode); 2235 audit_copy_inode(n, dentry, inode);
2162} 2236}
2163 2237
2164/** 2238/**
2165 * audit_inode_child - collect inode info for created/removed objects 2239 * __audit_inode_child - collect inode info for created/removed objects
2166 * @dentry: dentry being audited
2167 * @parent: inode of dentry parent 2240 * @parent: inode of dentry parent
2241 * @dentry: dentry being audited
2242 * @type: AUDIT_TYPE_* value that we're looking for
2168 * 2243 *
2169 * For syscalls that create or remove filesystem objects, audit_inode 2244 * For syscalls that create or remove filesystem objects, audit_inode
2170 * can only collect information for the filesystem object's parent. 2245 * can only collect information for the filesystem object's parent.
@@ -2174,15 +2249,14 @@ out:
2174 * must be hooked prior, in order to capture the target inode during 2249 * must be hooked prior, in order to capture the target inode during
2175 * unsuccessful attempts. 2250 * unsuccessful attempts.
2176 */ 2251 */
2177void __audit_inode_child(const struct dentry *dentry, 2252void __audit_inode_child(const struct inode *parent,
2178 const struct inode *parent) 2253 const struct dentry *dentry,
2254 const unsigned char type)
2179{ 2255{
2180 struct audit_context *context = current->audit_context; 2256 struct audit_context *context = current->audit_context;
2181 const char *found_parent = NULL, *found_child = NULL;
2182 const struct inode *inode = dentry->d_inode; 2257 const struct inode *inode = dentry->d_inode;
2183 const char *dname = dentry->d_name.name; 2258 const char *dname = dentry->d_name.name;
2184 struct audit_names *n; 2259 struct audit_names *n, *found_parent = NULL, *found_child = NULL;
2185 int dirlen = 0;
2186 2260
2187 if (!context->in_syscall) 2261 if (!context->in_syscall)
2188 return; 2262 return;
@@ -2190,62 +2264,65 @@ void __audit_inode_child(const struct dentry *dentry,
2190 if (inode) 2264 if (inode)
2191 handle_one(inode); 2265 handle_one(inode);
2192 2266
2193 /* parent is more likely, look for it first */ 2267 /* look for a parent entry first */
2194 list_for_each_entry(n, &context->names_list, list) { 2268 list_for_each_entry(n, &context->names_list, list) {
2195 if (!n->name) 2269 if (!n->name || n->type != AUDIT_TYPE_PARENT)
2196 continue; 2270 continue;
2197 2271
2198 if (n->ino == parent->i_ino && 2272 if (n->ino == parent->i_ino &&
2199 !audit_compare_dname_path(dname, n->name, &dirlen)) { 2273 !audit_compare_dname_path(dname, n->name->name, n->name_len)) {
2200 n->name_len = dirlen; /* update parent data in place */ 2274 found_parent = n;
2201 found_parent = n->name; 2275 break;
2202 goto add_names;
2203 } 2276 }
2204 } 2277 }
2205 2278
2206 /* no matching parent, look for matching child */ 2279 /* is there a matching child entry? */
2207 list_for_each_entry(n, &context->names_list, list) { 2280 list_for_each_entry(n, &context->names_list, list) {
2208 if (!n->name) 2281 /* can only match entries that have a name */
2282 if (!n->name || n->type != type)
2209 continue; 2283 continue;
2210 2284
2211 /* strcmp() is the more likely scenario */ 2285 /* if we found a parent, make sure this one is a child of it */
2212 if (!strcmp(dname, n->name) || 2286 if (found_parent && (n->name != found_parent->name))
2213 !audit_compare_dname_path(dname, n->name, &dirlen)) { 2287 continue;
2214 if (inode) 2288
2215 audit_copy_inode(n, NULL, inode); 2289 if (!strcmp(dname, n->name->name) ||
2216 else 2290 !audit_compare_dname_path(dname, n->name->name,
2217 n->ino = (unsigned long)-1; 2291 found_parent ?
2218 found_child = n->name; 2292 found_parent->name_len :
2219 goto add_names; 2293 AUDIT_NAME_FULL)) {
2294 found_child = n;
2295 break;
2220 } 2296 }
2221 } 2297 }
2222 2298
2223add_names:
2224 if (!found_parent) { 2299 if (!found_parent) {
2225 n = audit_alloc_name(context); 2300 /* create a new, "anonymous" parent record */
2301 n = audit_alloc_name(context, AUDIT_TYPE_PARENT);
2226 if (!n) 2302 if (!n)
2227 return; 2303 return;
2228 audit_copy_inode(n, NULL, parent); 2304 audit_copy_inode(n, NULL, parent);
2229 } 2305 }
2230 2306
2231 if (!found_child) { 2307 if (!found_child) {
2232 n = audit_alloc_name(context); 2308 found_child = audit_alloc_name(context, type);
2233 if (!n) 2309 if (!found_child)
2234 return; 2310 return;
2235 2311
2236 /* Re-use the name belonging to the slot for a matching parent 2312 /* Re-use the name belonging to the slot for a matching parent
2237 * directory. All names for this context are relinquished in 2313 * directory. All names for this context are relinquished in
2238 * audit_free_names() */ 2314 * audit_free_names() */
2239 if (found_parent) { 2315 if (found_parent) {
2240 n->name = found_parent; 2316 found_child->name = found_parent->name;
2241 n->name_len = AUDIT_NAME_FULL; 2317 found_child->name_len = AUDIT_NAME_FULL;
2242 /* don't call __putname() */ 2318 /* don't call __putname() */
2243 n->name_put = false; 2319 found_child->name_put = false;
2244 } 2320 }
2245
2246 if (inode)
2247 audit_copy_inode(n, NULL, inode);
2248 } 2321 }
2322 if (inode)
2323 audit_copy_inode(found_child, dentry, inode);
2324 else
2325 found_child->ino = (unsigned long)-1;
2249} 2326}
2250EXPORT_SYMBOL_GPL(__audit_inode_child); 2327EXPORT_SYMBOL_GPL(__audit_inode_child);
2251 2328