diff options
author | Jeff Layton <jlayton@redhat.com> | 2012-10-10 15:25:28 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-12 20:14:55 -0400 |
commit | 91a27b2a756784714e924e5e854b919273082d26 (patch) | |
tree | 3913246b7d6e62703ec915f481e3a7159393f0f0 /kernel/auditsc.c | |
parent | 8e377d15078a501c4da98471f56396343c407d92 (diff) |
vfs: define struct filename and have getname() return it
getname() is intended to copy pathname strings from userspace into a
kernel buffer. The result is just a string in kernel space. It would
however be quite helpful to be able to attach some ancillary info to
the string.
For instance, we could attach some audit-related info to reduce the
amount of audit-related processing needed. When auditing is enabled,
we could also call getname() on the string more than once and not
need to recopy it from userspace.
This patchset converts the getname()/putname() interfaces to return
a struct instead of a string. For now, the struct just tracks the
string in kernel space and the original userland pointer for it.
Later, we'll add other information to the struct as it becomes
convenient.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r-- | kernel/auditsc.c | 64 |
1 files changed, 35 insertions, 29 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index d147585e9ef3..d4d82319eed5 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -103,28 +103,29 @@ struct audit_cap_data { | |||
103 | * 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 |
104 | * pointers at syscall exit time). | 104 | * pointers at syscall exit time). |
105 | * | 105 | * |
106 | * 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 | */ | ||
107 | struct audit_names { | 108 | struct audit_names { |
108 | struct list_head list; /* audit_context->names_list */ | 109 | struct list_head list; /* audit_context->names_list */ |
109 | const char *name; | 110 | struct filename *name; |
110 | unsigned long ino; | 111 | unsigned long ino; |
111 | dev_t dev; | 112 | dev_t dev; |
112 | umode_t mode; | 113 | umode_t mode; |
113 | kuid_t uid; | 114 | kuid_t uid; |
114 | kgid_t gid; | 115 | kgid_t gid; |
115 | dev_t rdev; | 116 | dev_t rdev; |
116 | u32 osid; | 117 | u32 osid; |
117 | struct audit_cap_data fcap; | 118 | struct audit_cap_data fcap; |
118 | unsigned int fcap_ver; | 119 | unsigned int fcap_ver; |
119 | int name_len; /* number of name's characters to log */ | 120 | int name_len; /* number of name's characters to log */ |
120 | unsigned char type; /* record type */ | 121 | unsigned char type; /* record type */ |
121 | bool name_put; /* call __putname() for this name */ | 122 | bool name_put; /* call __putname() for this name */ |
122 | /* | 123 | /* |
123 | * 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 |
124 | * names allocated in the task audit context. Thus this name | 125 | * names allocated in the task audit context. Thus this name |
125 | * should be freed on syscall exit | 126 | * should be freed on syscall exit |
126 | */ | 127 | */ |
127 | bool should_free; | 128 | bool should_free; |
128 | }; | 129 | }; |
129 | 130 | ||
130 | struct audit_aux_data { | 131 | struct audit_aux_data { |
@@ -996,7 +997,7 @@ static inline void audit_free_names(struct audit_context *context) | |||
996 | context->ino_count); | 997 | context->ino_count); |
997 | list_for_each_entry(n, &context->names_list, list) { | 998 | list_for_each_entry(n, &context->names_list, list) { |
998 | printk(KERN_ERR "names[%d] = %p = %s\n", i, | 999 | printk(KERN_ERR "names[%d] = %p = %s\n", i, |
999 | n->name, n->name ?: "(null)"); | 1000 | n->name, n->name->name ?: "(null)"); |
1000 | } | 1001 | } |
1001 | dump_stack(); | 1002 | dump_stack(); |
1002 | return; | 1003 | return; |
@@ -1553,7 +1554,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n, | |||
1553 | case AUDIT_NAME_FULL: | 1554 | case AUDIT_NAME_FULL: |
1554 | /* log the full path */ | 1555 | /* log the full path */ |
1555 | audit_log_format(ab, " name="); | 1556 | audit_log_format(ab, " name="); |
1556 | audit_log_untrustedstring(ab, n->name); | 1557 | audit_log_untrustedstring(ab, n->name->name); |
1557 | break; | 1558 | break; |
1558 | case 0: | 1559 | case 0: |
1559 | /* name was specified as a relative path and the | 1560 | /* name was specified as a relative path and the |
@@ -1563,7 +1564,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n, | |||
1563 | default: | 1564 | default: |
1564 | /* log the name's directory component */ | 1565 | /* log the name's directory component */ |
1565 | audit_log_format(ab, " name="); | 1566 | audit_log_format(ab, " name="); |
1566 | audit_log_n_untrustedstring(ab, n->name, | 1567 | audit_log_n_untrustedstring(ab, n->name->name, |
1567 | n->name_len); | 1568 | n->name_len); |
1568 | } | 1569 | } |
1569 | } else | 1570 | } else |
@@ -2026,7 +2027,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context, | |||
2026 | * Add a name to the list of audit names for this context. | 2027 | * Add a name to the list of audit names for this context. |
2027 | * Called from fs/namei.c:getname(). | 2028 | * Called from fs/namei.c:getname(). |
2028 | */ | 2029 | */ |
2029 | void __audit_getname(const char *name) | 2030 | void __audit_getname(struct filename *name) |
2030 | { | 2031 | { |
2031 | struct audit_context *context = current->audit_context; | 2032 | struct audit_context *context = current->audit_context; |
2032 | struct audit_names *n; | 2033 | struct audit_names *n; |
@@ -2040,6 +2041,11 @@ void __audit_getname(const char *name) | |||
2040 | return; | 2041 | return; |
2041 | } | 2042 | } |
2042 | 2043 | ||
2044 | #if AUDIT_DEBUG | ||
2045 | /* The filename _must_ have a populated ->name */ | ||
2046 | BUG_ON(!name->name); | ||
2047 | #endif | ||
2048 | |||
2043 | n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); | 2049 | n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); |
2044 | if (!n) | 2050 | if (!n) |
2045 | return; | 2051 | return; |
@@ -2059,7 +2065,7 @@ void __audit_getname(const char *name) | |||
2059 | * then we delay the putname until syscall exit. | 2065 | * then we delay the putname until syscall exit. |
2060 | * Called from include/linux/fs.h:putname(). | 2066 | * Called from include/linux/fs.h:putname(). |
2061 | */ | 2067 | */ |
2062 | void audit_putname(const char *name) | 2068 | void audit_putname(struct filename *name) |
2063 | { | 2069 | { |
2064 | struct audit_context *context = current->audit_context; | 2070 | struct audit_context *context = current->audit_context; |
2065 | 2071 | ||
@@ -2074,7 +2080,7 @@ void audit_putname(const char *name) | |||
2074 | 2080 | ||
2075 | list_for_each_entry(n, &context->names_list, list) | 2081 | list_for_each_entry(n, &context->names_list, list) |
2076 | printk(KERN_ERR "name[%d] = %p = %s\n", i, | 2082 | printk(KERN_ERR "name[%d] = %p = %s\n", i, |
2077 | n->name, n->name ?: "(null)"); | 2083 | n->name, n->name->name ?: "(null)"); |
2078 | } | 2084 | } |
2079 | #endif | 2085 | #endif |
2080 | __putname(name); | 2086 | __putname(name); |
@@ -2088,8 +2094,8 @@ void audit_putname(const char *name) | |||
2088 | " put_count=%d\n", | 2094 | " put_count=%d\n", |
2089 | __FILE__, __LINE__, | 2095 | __FILE__, __LINE__, |
2090 | context->serial, context->major, | 2096 | context->serial, context->major, |
2091 | context->in_syscall, name, context->name_count, | 2097 | context->in_syscall, name->name, |
2092 | context->put_count); | 2098 | context->name_count, context->put_count); |
2093 | dump_stack(); | 2099 | dump_stack(); |
2094 | } | 2100 | } |
2095 | } | 2101 | } |
@@ -2152,7 +2158,7 @@ void __audit_inode(const char *name, const struct dentry *dentry, | |||
2152 | 2158 | ||
2153 | list_for_each_entry_reverse(n, &context->names_list, list) { | 2159 | list_for_each_entry_reverse(n, &context->names_list, list) { |
2154 | /* does the name pointer match? */ | 2160 | /* does the name pointer match? */ |
2155 | if (n->name != name) | 2161 | if (!n->name || n->name->name != name) |
2156 | continue; | 2162 | continue; |
2157 | 2163 | ||
2158 | /* match the correct record type */ | 2164 | /* match the correct record type */ |
@@ -2175,7 +2181,7 @@ out_alloc: | |||
2175 | return; | 2181 | return; |
2176 | out: | 2182 | out: |
2177 | if (parent) { | 2183 | if (parent) { |
2178 | n->name_len = n->name ? parent_len(n->name) : AUDIT_NAME_FULL; | 2184 | n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; |
2179 | n->type = AUDIT_TYPE_PARENT; | 2185 | n->type = AUDIT_TYPE_PARENT; |
2180 | } else { | 2186 | } else { |
2181 | n->name_len = AUDIT_NAME_FULL; | 2187 | n->name_len = AUDIT_NAME_FULL; |
@@ -2220,7 +2226,7 @@ void __audit_inode_child(const struct inode *parent, | |||
2220 | continue; | 2226 | continue; |
2221 | 2227 | ||
2222 | if (n->ino == parent->i_ino && | 2228 | if (n->ino == parent->i_ino && |
2223 | !audit_compare_dname_path(dname, n->name, n->name_len)) { | 2229 | !audit_compare_dname_path(dname, n->name->name, n->name_len)) { |
2224 | found_parent = n; | 2230 | found_parent = n; |
2225 | break; | 2231 | break; |
2226 | } | 2232 | } |
@@ -2236,8 +2242,8 @@ void __audit_inode_child(const struct inode *parent, | |||
2236 | if (found_parent && (n->name != found_parent->name)) | 2242 | if (found_parent && (n->name != found_parent->name)) |
2237 | continue; | 2243 | continue; |
2238 | 2244 | ||
2239 | if (!strcmp(dname, n->name) || | 2245 | if (!strcmp(dname, n->name->name) || |
2240 | !audit_compare_dname_path(dname, n->name, | 2246 | !audit_compare_dname_path(dname, n->name->name, |
2241 | found_parent ? | 2247 | found_parent ? |
2242 | found_parent->name_len : | 2248 | found_parent->name_len : |
2243 | AUDIT_NAME_FULL)) { | 2249 | AUDIT_NAME_FULL)) { |