diff options
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r-- | kernel/auditsc.c | 95 |
1 files changed, 56 insertions, 39 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 818ef9fdab3c..488ba3dea8bb 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -190,9 +190,36 @@ struct audit_entry { | |||
190 | 190 | ||
191 | extern int audit_pid; | 191 | extern int audit_pid; |
192 | 192 | ||
193 | /* Copy rule from user-space to kernel-space. Called from | ||
194 | * audit_add_rule during AUDIT_ADD. */ | ||
195 | static inline int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) | ||
196 | { | ||
197 | int i; | ||
198 | |||
199 | if (s->action != AUDIT_NEVER | ||
200 | && s->action != AUDIT_POSSIBLE | ||
201 | && s->action != AUDIT_ALWAYS) | ||
202 | return -1; | ||
203 | if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS) | ||
204 | return -1; | ||
205 | if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS) | ||
206 | return -1; | ||
207 | |||
208 | d->flags = s->flags; | ||
209 | d->action = s->action; | ||
210 | d->field_count = s->field_count; | ||
211 | for (i = 0; i < d->field_count; i++) { | ||
212 | d->fields[i] = s->fields[i]; | ||
213 | d->values[i] = s->values[i]; | ||
214 | } | ||
215 | for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i]; | ||
216 | return 0; | ||
217 | } | ||
218 | |||
193 | /* Check to see if two rules are identical. It is called from | 219 | /* Check to see if two rules are identical. It is called from |
220 | * audit_add_rule during AUDIT_ADD and | ||
194 | * audit_del_rule during AUDIT_DEL. */ | 221 | * audit_del_rule during AUDIT_DEL. */ |
195 | static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) | 222 | static inline int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) |
196 | { | 223 | { |
197 | int i; | 224 | int i; |
198 | 225 | ||
@@ -221,18 +248,37 @@ static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) | |||
221 | /* Note that audit_add_rule and audit_del_rule are called via | 248 | /* Note that audit_add_rule and audit_del_rule are called via |
222 | * audit_receive() in audit.c, and are protected by | 249 | * audit_receive() in audit.c, and are protected by |
223 | * audit_netlink_sem. */ | 250 | * audit_netlink_sem. */ |
224 | static inline void audit_add_rule(struct audit_entry *entry, | 251 | static inline int audit_add_rule(struct audit_rule *rule, |
225 | struct list_head *list) | 252 | struct list_head *list) |
226 | { | 253 | { |
254 | struct audit_entry *entry; | ||
255 | |||
256 | /* Do not use the _rcu iterator here, since this is the only | ||
257 | * addition routine. */ | ||
258 | list_for_each_entry(entry, list, list) { | ||
259 | if (!audit_compare_rule(rule, &entry->rule)) { | ||
260 | return -EEXIST; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) | ||
265 | return -ENOMEM; | ||
266 | if (audit_copy_rule(&entry->rule, rule)) { | ||
267 | kfree(entry); | ||
268 | return -EINVAL; | ||
269 | } | ||
270 | |||
227 | if (entry->rule.flags & AUDIT_FILTER_PREPEND) { | 271 | if (entry->rule.flags & AUDIT_FILTER_PREPEND) { |
228 | entry->rule.flags &= ~AUDIT_FILTER_PREPEND; | 272 | entry->rule.flags &= ~AUDIT_FILTER_PREPEND; |
229 | list_add_rcu(&entry->list, list); | 273 | list_add_rcu(&entry->list, list); |
230 | } else { | 274 | } else { |
231 | list_add_tail_rcu(&entry->list, list); | 275 | list_add_tail_rcu(&entry->list, list); |
232 | } | 276 | } |
277 | |||
278 | return 0; | ||
233 | } | 279 | } |
234 | 280 | ||
235 | static void audit_free_rule(struct rcu_head *head) | 281 | static inline void audit_free_rule(struct rcu_head *head) |
236 | { | 282 | { |
237 | struct audit_entry *e = container_of(head, struct audit_entry, rcu); | 283 | struct audit_entry *e = container_of(head, struct audit_entry, rcu); |
238 | kfree(e); | 284 | kfree(e); |
@@ -258,32 +304,6 @@ static inline int audit_del_rule(struct audit_rule *rule, | |||
258 | return -ENOENT; /* No matching rule */ | 304 | return -ENOENT; /* No matching rule */ |
259 | } | 305 | } |
260 | 306 | ||
261 | /* Copy rule from user-space to kernel-space. Called during | ||
262 | * AUDIT_ADD. */ | ||
263 | static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) | ||
264 | { | ||
265 | int i; | ||
266 | |||
267 | if (s->action != AUDIT_NEVER | ||
268 | && s->action != AUDIT_POSSIBLE | ||
269 | && s->action != AUDIT_ALWAYS) | ||
270 | return -1; | ||
271 | if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS) | ||
272 | return -1; | ||
273 | if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS) | ||
274 | return -1; | ||
275 | |||
276 | d->flags = s->flags; | ||
277 | d->action = s->action; | ||
278 | d->field_count = s->field_count; | ||
279 | for (i = 0; i < d->field_count; i++) { | ||
280 | d->fields[i] = s->fields[i]; | ||
281 | d->values[i] = s->values[i]; | ||
282 | } | ||
283 | for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i]; | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int audit_list_rules(void *_dest) | 307 | static int audit_list_rules(void *_dest) |
288 | { | 308 | { |
289 | int pid, seq; | 309 | int pid, seq; |
@@ -313,7 +333,6 @@ static int audit_list_rules(void *_dest) | |||
313 | int audit_receive_filter(int type, int pid, int uid, int seq, void *data, | 333 | int audit_receive_filter(int type, int pid, int uid, int seq, void *data, |
314 | uid_t loginuid) | 334 | uid_t loginuid) |
315 | { | 335 | { |
316 | struct audit_entry *entry; | ||
317 | struct task_struct *tsk; | 336 | struct task_struct *tsk; |
318 | int *dest; | 337 | int *dest; |
319 | int err = 0; | 338 | int err = 0; |
@@ -340,16 +359,14 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, | |||
340 | } | 359 | } |
341 | break; | 360 | break; |
342 | case AUDIT_ADD: | 361 | case AUDIT_ADD: |
343 | if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) | 362 | listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND; |
344 | return -ENOMEM; | 363 | if (listnr >= AUDIT_NR_FILTERS) |
345 | if (audit_copy_rule(&entry->rule, data)) { | ||
346 | kfree(entry); | ||
347 | return -EINVAL; | 364 | return -EINVAL; |
348 | } | 365 | |
349 | listnr = entry->rule.flags & ~AUDIT_FILTER_PREPEND; | 366 | err = audit_add_rule(data, &audit_filter_list[listnr]); |
350 | audit_add_rule(entry, &audit_filter_list[listnr]); | 367 | if (!err) |
351 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, | 368 | audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, |
352 | "auid=%u added an audit rule\n", loginuid); | 369 | "auid=%u added an audit rule\n", loginuid); |
353 | break; | 370 | break; |
354 | case AUDIT_DEL: | 371 | case AUDIT_DEL: |
355 | listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND; | 372 | listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND; |