aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/auditsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r--kernel/auditsc.c124
1 files changed, 88 insertions, 36 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 14e295a4121b..174a3f624892 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -200,12 +200,13 @@ struct audit_context {
200#endif 200#endif
201}; 201};
202 202
203 203/* Determine if any context name data matches a rule's watch data */
204/* Compare a task_struct with an audit_rule. Return 1 on match, 0 204/* Compare a task_struct with an audit_rule. Return 1 on match, 0
205 * otherwise. */ 205 * otherwise. */
206static int audit_filter_rules(struct task_struct *tsk, 206static int audit_filter_rules(struct task_struct *tsk,
207 struct audit_krule *rule, 207 struct audit_krule *rule,
208 struct audit_context *ctx, 208 struct audit_context *ctx,
209 struct audit_names *name,
209 enum audit_state *state) 210 enum audit_state *state)
210{ 211{
211 int i, j, need_sid = 1; 212 int i, j, need_sid = 1;
@@ -268,7 +269,10 @@ static int audit_filter_rules(struct task_struct *tsk,
268 } 269 }
269 break; 270 break;
270 case AUDIT_DEVMAJOR: 271 case AUDIT_DEVMAJOR:
271 if (ctx) { 272 if (name)
273 result = audit_comparator(MAJOR(name->dev),
274 f->op, f->val);
275 else if (ctx) {
272 for (j = 0; j < ctx->name_count; j++) { 276 for (j = 0; j < ctx->name_count; j++) {
273 if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) { 277 if (audit_comparator(MAJOR(ctx->names[j].dev), f->op, f->val)) {
274 ++result; 278 ++result;
@@ -278,7 +282,10 @@ static int audit_filter_rules(struct task_struct *tsk,
278 } 282 }
279 break; 283 break;
280 case AUDIT_DEVMINOR: 284 case AUDIT_DEVMINOR:
281 if (ctx) { 285 if (name)
286 result = audit_comparator(MINOR(name->dev),
287 f->op, f->val);
288 else if (ctx) {
282 for (j = 0; j < ctx->name_count; j++) { 289 for (j = 0; j < ctx->name_count; j++) {
283 if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { 290 if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) {
284 ++result; 291 ++result;
@@ -288,7 +295,10 @@ static int audit_filter_rules(struct task_struct *tsk,
288 } 295 }
289 break; 296 break;
290 case AUDIT_INODE: 297 case AUDIT_INODE:
291 if (ctx) { 298 if (name)
299 result = (name->ino == f->val ||
300 name->pino == f->val);
301 else if (ctx) {
292 for (j = 0; j < ctx->name_count; j++) { 302 for (j = 0; j < ctx->name_count; j++) {
293 if (audit_comparator(ctx->names[j].ino, f->op, f->val) || 303 if (audit_comparator(ctx->names[j].ino, f->op, f->val) ||
294 audit_comparator(ctx->names[j].pino, f->op, f->val)) { 304 audit_comparator(ctx->names[j].pino, f->op, f->val)) {
@@ -298,6 +308,12 @@ static int audit_filter_rules(struct task_struct *tsk,
298 } 308 }
299 } 309 }
300 break; 310 break;
311 case AUDIT_WATCH:
312 if (name && rule->watch->ino != (unsigned long)-1)
313 result = (name->dev == rule->watch->dev &&
314 (name->ino == rule->watch->ino ||
315 name->pino == rule->watch->ino));
316 break;
301 case AUDIT_LOGINUID: 317 case AUDIT_LOGINUID:
302 result = 0; 318 result = 0;
303 if (ctx) 319 if (ctx)
@@ -354,7 +370,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk)
354 370
355 rcu_read_lock(); 371 rcu_read_lock();
356 list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { 372 list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) {
357 if (audit_filter_rules(tsk, &e->rule, NULL, &state)) { 373 if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) {
358 rcu_read_unlock(); 374 rcu_read_unlock();
359 return state; 375 return state;
360 } 376 }
@@ -384,8 +400,9 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
384 int bit = AUDIT_BIT(ctx->major); 400 int bit = AUDIT_BIT(ctx->major);
385 401
386 list_for_each_entry_rcu(e, list, list) { 402 list_for_each_entry_rcu(e, list, list) {
387 if ((e->rule.mask[word] & bit) == bit 403 if ((e->rule.mask[word] & bit) == bit &&
388 && audit_filter_rules(tsk, &e->rule, ctx, &state)) { 404 audit_filter_rules(tsk, &e->rule, ctx, NULL,
405 &state)) {
389 rcu_read_unlock(); 406 rcu_read_unlock();
390 return state; 407 return state;
391 } 408 }
@@ -395,6 +412,49 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
395 return AUDIT_BUILD_CONTEXT; 412 return AUDIT_BUILD_CONTEXT;
396} 413}
397 414
415/* At syscall exit time, this filter is called if any audit_names[] have been
416 * collected during syscall processing. We only check rules in sublists at hash
417 * buckets applicable to the inode numbers in audit_names[].
418 * Regarding audit_state, same rules apply as for audit_filter_syscall().
419 */
420enum audit_state audit_filter_inodes(struct task_struct *tsk,
421 struct audit_context *ctx)
422{
423 int i;
424 struct audit_entry *e;
425 enum audit_state state;
426
427 if (audit_pid && tsk->tgid == audit_pid)
428 return AUDIT_DISABLED;
429
430 rcu_read_lock();
431 for (i = 0; i < ctx->name_count; i++) {
432 int word = AUDIT_WORD(ctx->major);
433 int bit = AUDIT_BIT(ctx->major);
434 struct audit_names *n = &ctx->names[i];
435 int h = audit_hash_ino((u32)n->ino);
436 struct list_head *list = &audit_inode_hash[h];
437
438 if (list_empty(list))
439 continue;
440
441 list_for_each_entry_rcu(e, list, list) {
442 if ((e->rule.mask[word] & bit) == bit &&
443 audit_filter_rules(tsk, &e->rule, ctx, n, &state)) {
444 rcu_read_unlock();
445 return state;
446 }
447 }
448 }
449 rcu_read_unlock();
450 return AUDIT_BUILD_CONTEXT;
451}
452
453void audit_set_auditable(struct audit_context *ctx)
454{
455 ctx->auditable = 1;
456}
457
398static inline struct audit_context *audit_get_context(struct task_struct *tsk, 458static inline struct audit_context *audit_get_context(struct task_struct *tsk,
399 int return_valid, 459 int return_valid,
400 int return_code) 460 int return_code)
@@ -408,11 +468,20 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
408 468
409 if (context->in_syscall && !context->auditable) { 469 if (context->in_syscall && !context->auditable) {
410 enum audit_state state; 470 enum audit_state state;
471
411 state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); 472 state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
473 if (state == AUDIT_RECORD_CONTEXT) {
474 context->auditable = 1;
475 goto get_context;
476 }
477
478 state = audit_filter_inodes(tsk, context);
412 if (state == AUDIT_RECORD_CONTEXT) 479 if (state == AUDIT_RECORD_CONTEXT)
413 context->auditable = 1; 480 context->auditable = 1;
481
414 } 482 }
415 483
484get_context:
416 context->pid = tsk->pid; 485 context->pid = tsk->pid;
417 context->ppid = sys_getppid(); /* sic. tsk == current in all cases */ 486 context->ppid = sys_getppid(); /* sic. tsk == current in all cases */
418 context->uid = tsk->uid; 487 context->uid = tsk->uid;
@@ -1142,37 +1211,20 @@ void __audit_inode_child(const char *dname, const struct inode *inode,
1142 return; 1211 return;
1143 1212
1144 /* determine matching parent */ 1213 /* determine matching parent */
1145 if (dname) 1214 if (!dname)
1146 for (idx = 0; idx < context->name_count; idx++) 1215 goto no_match;
1147 if (context->names[idx].pino == pino) { 1216 for (idx = 0; idx < context->name_count; idx++)
1148 const char *n; 1217 if (context->names[idx].pino == pino) {
1149 const char *name = context->names[idx].name; 1218 const char *name = context->names[idx].name;
1150 int dlen = strlen(dname);
1151 int nlen = name ? strlen(name) : 0;
1152
1153 if (nlen < dlen)
1154 continue;
1155
1156 /* disregard trailing slashes */
1157 n = name + nlen - 1;
1158 while ((*n == '/') && (n > name))
1159 n--;
1160
1161 /* find last path component */
1162 n = n - dlen + 1;
1163 if (n < name)
1164 continue;
1165 else if (n > name) {
1166 if (*--n != '/')
1167 continue;
1168 else
1169 n++;
1170 }
1171 1219
1172 if (strncmp(n, dname, dlen) == 0) 1220 if (!name)
1173 goto update_context; 1221 continue;
1174 } 1222
1223 if (audit_compare_dname_path(dname, name) == 0)
1224 goto update_context;
1225 }
1175 1226
1227no_match:
1176 /* catch-all in case match not found */ 1228 /* catch-all in case match not found */
1177 idx = context->name_count++; 1229 idx = context->name_count++;
1178 context->names[idx].name = NULL; 1230 context->names[idx].name = NULL;