diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/auditsc.c | 142 |
1 files changed, 84 insertions, 58 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 25d890e997f2..5276b7ef05f1 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -78,11 +78,6 @@ extern int audit_enabled; | |||
78 | * for saving names from getname(). */ | 78 | * for saving names from getname(). */ |
79 | #define AUDIT_NAMES 20 | 79 | #define AUDIT_NAMES 20 |
80 | 80 | ||
81 | /* AUDIT_NAMES_RESERVED is the number of slots we reserve in the | ||
82 | * audit_context from being used for nameless inodes from | ||
83 | * path_lookup. */ | ||
84 | #define AUDIT_NAMES_RESERVED 7 | ||
85 | |||
86 | /* Indicates that audit should log the full pathname. */ | 81 | /* Indicates that audit should log the full pathname. */ |
87 | #define AUDIT_NAME_FULL -1 | 82 | #define AUDIT_NAME_FULL -1 |
88 | 83 | ||
@@ -1343,6 +1338,28 @@ void audit_putname(const char *name) | |||
1343 | #endif | 1338 | #endif |
1344 | } | 1339 | } |
1345 | 1340 | ||
1341 | static int audit_inc_name_count(struct audit_context *context, | ||
1342 | const struct inode *inode) | ||
1343 | { | ||
1344 | if (context->name_count >= AUDIT_NAMES) { | ||
1345 | if (inode) | ||
1346 | printk(KERN_DEBUG "name_count maxed, losing inode data: " | ||
1347 | "dev=%02x:%02x, inode=%lu", | ||
1348 | MAJOR(inode->i_sb->s_dev), | ||
1349 | MINOR(inode->i_sb->s_dev), | ||
1350 | inode->i_ino); | ||
1351 | |||
1352 | else | ||
1353 | printk(KERN_DEBUG "name_count maxed, losing inode data"); | ||
1354 | return 1; | ||
1355 | } | ||
1356 | context->name_count++; | ||
1357 | #if AUDIT_DEBUG | ||
1358 | context->ino_count++; | ||
1359 | #endif | ||
1360 | return 0; | ||
1361 | } | ||
1362 | |||
1346 | /* Copy inode data into an audit_names. */ | 1363 | /* Copy inode data into an audit_names. */ |
1347 | static void audit_copy_inode(struct audit_names *name, const struct inode *inode) | 1364 | static void audit_copy_inode(struct audit_names *name, const struct inode *inode) |
1348 | { | 1365 | { |
@@ -1380,13 +1397,10 @@ void __audit_inode(const char *name, const struct inode *inode) | |||
1380 | else { | 1397 | else { |
1381 | /* FIXME: how much do we care about inodes that have no | 1398 | /* FIXME: how much do we care about inodes that have no |
1382 | * associated name? */ | 1399 | * associated name? */ |
1383 | if (context->name_count >= AUDIT_NAMES - AUDIT_NAMES_RESERVED) | 1400 | if (audit_inc_name_count(context, inode)) |
1384 | return; | 1401 | return; |
1385 | idx = context->name_count++; | 1402 | idx = context->name_count - 1; |
1386 | context->names[idx].name = NULL; | 1403 | context->names[idx].name = NULL; |
1387 | #if AUDIT_DEBUG | ||
1388 | ++context->ino_count; | ||
1389 | #endif | ||
1390 | } | 1404 | } |
1391 | audit_copy_inode(&context->names[idx], inode); | 1405 | audit_copy_inode(&context->names[idx], inode); |
1392 | } | 1406 | } |
@@ -1410,7 +1424,7 @@ void __audit_inode_child(const char *dname, const struct inode *inode, | |||
1410 | { | 1424 | { |
1411 | int idx; | 1425 | int idx; |
1412 | struct audit_context *context = current->audit_context; | 1426 | struct audit_context *context = current->audit_context; |
1413 | const char *found_name = NULL; | 1427 | const char *found_parent = NULL, *found_child = NULL; |
1414 | int dirlen = 0; | 1428 | int dirlen = 0; |
1415 | 1429 | ||
1416 | if (!context->in_syscall) | 1430 | if (!context->in_syscall) |
@@ -1418,61 +1432,73 @@ void __audit_inode_child(const char *dname, const struct inode *inode, | |||
1418 | 1432 | ||
1419 | /* determine matching parent */ | 1433 | /* determine matching parent */ |
1420 | if (!dname) | 1434 | if (!dname) |
1421 | goto update_context; | 1435 | goto add_names; |
1422 | for (idx = 0; idx < context->name_count; idx++) | ||
1423 | if (context->names[idx].ino == parent->i_ino) { | ||
1424 | const char *name = context->names[idx].name; | ||
1425 | 1436 | ||
1426 | if (!name) | 1437 | /* parent is more likely, look for it first */ |
1427 | continue; | 1438 | for (idx = 0; idx < context->name_count; idx++) { |
1439 | struct audit_names *n = &context->names[idx]; | ||
1428 | 1440 | ||
1429 | if (audit_compare_dname_path(dname, name, &dirlen) == 0) { | 1441 | if (!n->name) |
1430 | context->names[idx].name_len = dirlen; | 1442 | continue; |
1431 | found_name = name; | 1443 | |
1432 | break; | 1444 | if (n->ino == parent->i_ino && |
1433 | } | 1445 | !audit_compare_dname_path(dname, n->name, &dirlen)) { |
1446 | n->name_len = dirlen; /* update parent data in place */ | ||
1447 | found_parent = n->name; | ||
1448 | goto add_names; | ||
1434 | } | 1449 | } |
1450 | } | ||
1435 | 1451 | ||
1436 | update_context: | 1452 | /* no matching parent, look for matching child */ |
1437 | idx = context->name_count; | 1453 | for (idx = 0; idx < context->name_count; idx++) { |
1438 | if (context->name_count == AUDIT_NAMES) { | 1454 | struct audit_names *n = &context->names[idx]; |
1439 | printk(KERN_DEBUG "name_count maxed and losing %s\n", | 1455 | |
1440 | found_name ?: "(null)"); | 1456 | if (!n->name) |
1441 | return; | 1457 | continue; |
1458 | |||
1459 | /* strcmp() is the more likely scenario */ | ||
1460 | if (!strcmp(dname, n->name) || | ||
1461 | !audit_compare_dname_path(dname, n->name, &dirlen)) { | ||
1462 | if (inode) | ||
1463 | audit_copy_inode(n, inode); | ||
1464 | else | ||
1465 | n->ino = (unsigned long)-1; | ||
1466 | found_child = n->name; | ||
1467 | goto add_names; | ||
1468 | } | ||
1442 | } | 1469 | } |
1443 | context->name_count++; | 1470 | |
1444 | #if AUDIT_DEBUG | 1471 | add_names: |
1445 | context->ino_count++; | 1472 | if (!found_parent) { |
1446 | #endif | 1473 | if (audit_inc_name_count(context, parent)) |
1447 | /* Re-use the name belonging to the slot for a matching parent directory. | ||
1448 | * All names for this context are relinquished in audit_free_names() */ | ||
1449 | context->names[idx].name = found_name; | ||
1450 | context->names[idx].name_len = AUDIT_NAME_FULL; | ||
1451 | context->names[idx].name_put = 0; /* don't call __putname() */ | ||
1452 | |||
1453 | if (!inode) | ||
1454 | context->names[idx].ino = (unsigned long)-1; | ||
1455 | else | ||
1456 | audit_copy_inode(&context->names[idx], inode); | ||
1457 | |||
1458 | /* A parent was not found in audit_names, so copy the inode data for the | ||
1459 | * provided parent. */ | ||
1460 | if (!found_name) { | ||
1461 | idx = context->name_count; | ||
1462 | if (context->name_count == AUDIT_NAMES) { | ||
1463 | printk(KERN_DEBUG | ||
1464 | "name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu", | ||
1465 | MAJOR(parent->i_sb->s_dev), | ||
1466 | MINOR(parent->i_sb->s_dev), | ||
1467 | parent->i_ino); | ||
1468 | return; | 1474 | return; |
1469 | } | 1475 | idx = context->name_count - 1; |
1470 | context->name_count++; | 1476 | context->names[idx].name = NULL; |
1471 | #if AUDIT_DEBUG | ||
1472 | context->ino_count++; | ||
1473 | #endif | ||
1474 | audit_copy_inode(&context->names[idx], parent); | 1477 | audit_copy_inode(&context->names[idx], parent); |
1475 | } | 1478 | } |
1479 | |||
1480 | if (!found_child) { | ||
1481 | if (audit_inc_name_count(context, inode)) | ||
1482 | return; | ||
1483 | idx = context->name_count - 1; | ||
1484 | |||
1485 | /* Re-use the name belonging to the slot for a matching parent | ||
1486 | * directory. All names for this context are relinquished in | ||
1487 | * audit_free_names() */ | ||
1488 | if (found_parent) { | ||
1489 | context->names[idx].name = found_parent; | ||
1490 | context->names[idx].name_len = AUDIT_NAME_FULL; | ||
1491 | /* don't call __putname() */ | ||
1492 | context->names[idx].name_put = 0; | ||
1493 | } else { | ||
1494 | context->names[idx].name = NULL; | ||
1495 | } | ||
1496 | |||
1497 | if (inode) | ||
1498 | audit_copy_inode(&context->names[idx], inode); | ||
1499 | else | ||
1500 | context->names[idx].ino = (unsigned long)-1; | ||
1501 | } | ||
1476 | } | 1502 | } |
1477 | 1503 | ||
1478 | /** | 1504 | /** |