diff options
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r-- | kernel/auditsc.c | 123 |
1 files changed, 69 insertions, 54 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 174a3f624892..851ae0217e4b 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -82,6 +82,9 @@ extern int audit_enabled; | |||
82 | * path_lookup. */ | 82 | * path_lookup. */ |
83 | #define AUDIT_NAMES_RESERVED 7 | 83 | #define AUDIT_NAMES_RESERVED 7 |
84 | 84 | ||
85 | /* Indicates that audit should log the full pathname. */ | ||
86 | #define AUDIT_NAME_FULL -1 | ||
87 | |||
85 | /* When fs/namei.c:getname() is called, we store the pointer in name and | 88 | /* When fs/namei.c:getname() is called, we store the pointer in name and |
86 | * we don't let putname() free it (instead we free all of the saved | 89 | * we don't let putname() free it (instead we free all of the saved |
87 | * pointers at syscall exit time). | 90 | * pointers at syscall exit time). |
@@ -89,8 +92,9 @@ extern int audit_enabled; | |||
89 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ | 92 | * Further, in fs/namei.c:path_lookup() we store the inode and device. */ |
90 | struct audit_names { | 93 | struct audit_names { |
91 | const char *name; | 94 | const char *name; |
95 | int name_len; /* number of name's characters to log */ | ||
96 | unsigned name_put; /* call __putname() for this name */ | ||
92 | unsigned long ino; | 97 | unsigned long ino; |
93 | unsigned long pino; | ||
94 | dev_t dev; | 98 | dev_t dev; |
95 | umode_t mode; | 99 | umode_t mode; |
96 | uid_t uid; | 100 | uid_t uid; |
@@ -296,12 +300,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
296 | break; | 300 | break; |
297 | case AUDIT_INODE: | 301 | case AUDIT_INODE: |
298 | if (name) | 302 | if (name) |
299 | result = (name->ino == f->val || | 303 | result = (name->ino == f->val); |
300 | name->pino == f->val); | ||
301 | else if (ctx) { | 304 | else if (ctx) { |
302 | for (j = 0; j < ctx->name_count; j++) { | 305 | for (j = 0; j < ctx->name_count; j++) { |
303 | if (audit_comparator(ctx->names[j].ino, f->op, f->val) || | 306 | if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { |
304 | audit_comparator(ctx->names[j].pino, f->op, f->val)) { | ||
305 | ++result; | 307 | ++result; |
306 | break; | 308 | break; |
307 | } | 309 | } |
@@ -311,8 +313,7 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
311 | case AUDIT_WATCH: | 313 | case AUDIT_WATCH: |
312 | if (name && rule->watch->ino != (unsigned long)-1) | 314 | if (name && rule->watch->ino != (unsigned long)-1) |
313 | result = (name->dev == rule->watch->dev && | 315 | result = (name->dev == rule->watch->dev && |
314 | (name->ino == rule->watch->ino || | 316 | name->ino == rule->watch->ino); |
315 | name->pino == rule->watch->ino)); | ||
316 | break; | 317 | break; |
317 | case AUDIT_LOGINUID: | 318 | case AUDIT_LOGINUID: |
318 | result = 0; | 319 | result = 0; |
@@ -526,7 +527,7 @@ static inline void audit_free_names(struct audit_context *context) | |||
526 | #endif | 527 | #endif |
527 | 528 | ||
528 | for (i = 0; i < context->name_count; i++) { | 529 | for (i = 0; i < context->name_count; i++) { |
529 | if (context->names[i].name) | 530 | if (context->names[i].name && context->names[i].name_put) |
530 | __putname(context->names[i].name); | 531 | __putname(context->names[i].name); |
531 | } | 532 | } |
532 | context->name_count = 0; | 533 | context->name_count = 0; |
@@ -850,8 +851,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
850 | } | 851 | } |
851 | } | 852 | } |
852 | for (i = 0; i < context->name_count; i++) { | 853 | for (i = 0; i < context->name_count; i++) { |
853 | unsigned long ino = context->names[i].ino; | 854 | struct audit_names *n = &context->names[i]; |
854 | unsigned long pino = context->names[i].pino; | ||
855 | 855 | ||
856 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); | 856 | ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); |
857 | if (!ab) | 857 | if (!ab) |
@@ -859,33 +859,47 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
859 | 859 | ||
860 | audit_log_format(ab, "item=%d", i); | 860 | audit_log_format(ab, "item=%d", i); |
861 | 861 | ||
862 | audit_log_format(ab, " name="); | 862 | if (n->name) { |
863 | if (context->names[i].name) | 863 | switch(n->name_len) { |
864 | audit_log_untrustedstring(ab, context->names[i].name); | 864 | case AUDIT_NAME_FULL: |
865 | else | 865 | /* log the full path */ |
866 | audit_log_format(ab, "(null)"); | 866 | audit_log_format(ab, " name="); |
867 | 867 | audit_log_untrustedstring(ab, n->name); | |
868 | if (pino != (unsigned long)-1) | 868 | break; |
869 | audit_log_format(ab, " parent=%lu", pino); | 869 | case 0: |
870 | if (ino != (unsigned long)-1) | 870 | /* name was specified as a relative path and the |
871 | audit_log_format(ab, " inode=%lu", ino); | 871 | * directory component is the cwd */ |
872 | if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1)) | 872 | audit_log_d_path(ab, " name=", context->pwd, |
873 | audit_log_format(ab, " dev=%02x:%02x mode=%#o" | 873 | context->pwdmnt); |
874 | " ouid=%u ogid=%u rdev=%02x:%02x", | 874 | break; |
875 | MAJOR(context->names[i].dev), | 875 | default: |
876 | MINOR(context->names[i].dev), | 876 | /* log the name's directory component */ |
877 | context->names[i].mode, | 877 | audit_log_format(ab, " name="); |
878 | context->names[i].uid, | 878 | audit_log_n_untrustedstring(ab, n->name_len, |
879 | context->names[i].gid, | 879 | n->name); |
880 | MAJOR(context->names[i].rdev), | 880 | } |
881 | MINOR(context->names[i].rdev)); | 881 | } else |
882 | if (context->names[i].osid != 0) { | 882 | audit_log_format(ab, " name=(null)"); |
883 | |||
884 | if (n->ino != (unsigned long)-1) { | ||
885 | audit_log_format(ab, " inode=%lu" | ||
886 | " dev=%02x:%02x mode=%#o" | ||
887 | " ouid=%u ogid=%u rdev=%02x:%02x", | ||
888 | n->ino, | ||
889 | MAJOR(n->dev), | ||
890 | MINOR(n->dev), | ||
891 | n->mode, | ||
892 | n->uid, | ||
893 | n->gid, | ||
894 | MAJOR(n->rdev), | ||
895 | MINOR(n->rdev)); | ||
896 | } | ||
897 | if (n->osid != 0) { | ||
883 | char *ctx = NULL; | 898 | char *ctx = NULL; |
884 | u32 len; | 899 | u32 len; |
885 | if (selinux_ctxid_to_string( | 900 | if (selinux_ctxid_to_string( |
886 | context->names[i].osid, &ctx, &len)) { | 901 | n->osid, &ctx, &len)) { |
887 | audit_log_format(ab, " osid=%u", | 902 | audit_log_format(ab, " osid=%u", n->osid); |
888 | context->names[i].osid); | ||
889 | call_panic = 2; | 903 | call_panic = 2; |
890 | } else | 904 | } else |
891 | audit_log_format(ab, " obj=%s", ctx); | 905 | audit_log_format(ab, " obj=%s", ctx); |
@@ -1075,6 +1089,8 @@ void __audit_getname(const char *name) | |||
1075 | } | 1089 | } |
1076 | BUG_ON(context->name_count >= AUDIT_NAMES); | 1090 | BUG_ON(context->name_count >= AUDIT_NAMES); |
1077 | context->names[context->name_count].name = name; | 1091 | context->names[context->name_count].name = name; |
1092 | context->names[context->name_count].name_len = AUDIT_NAME_FULL; | ||
1093 | context->names[context->name_count].name_put = 1; | ||
1078 | context->names[context->name_count].ino = (unsigned long)-1; | 1094 | context->names[context->name_count].ino = (unsigned long)-1; |
1079 | ++context->name_count; | 1095 | ++context->name_count; |
1080 | if (!context->pwd) { | 1096 | if (!context->pwd) { |
@@ -1141,11 +1157,10 @@ static void audit_inode_context(int idx, const struct inode *inode) | |||
1141 | * audit_inode - store the inode and device from a lookup | 1157 | * audit_inode - store the inode and device from a lookup |
1142 | * @name: name being audited | 1158 | * @name: name being audited |
1143 | * @inode: inode being audited | 1159 | * @inode: inode being audited |
1144 | * @flags: lookup flags (as used in path_lookup()) | ||
1145 | * | 1160 | * |
1146 | * Called from fs/namei.c:path_lookup(). | 1161 | * Called from fs/namei.c:path_lookup(). |
1147 | */ | 1162 | */ |
1148 | void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | 1163 | void __audit_inode(const char *name, const struct inode *inode) |
1149 | { | 1164 | { |
1150 | int idx; | 1165 | int idx; |
1151 | struct audit_context *context = current->audit_context; | 1166 | struct audit_context *context = current->audit_context; |
@@ -1171,20 +1186,13 @@ void __audit_inode(const char *name, const struct inode *inode, unsigned flags) | |||
1171 | ++context->ino_count; | 1186 | ++context->ino_count; |
1172 | #endif | 1187 | #endif |
1173 | } | 1188 | } |
1189 | context->names[idx].ino = inode->i_ino; | ||
1174 | context->names[idx].dev = inode->i_sb->s_dev; | 1190 | context->names[idx].dev = inode->i_sb->s_dev; |
1175 | context->names[idx].mode = inode->i_mode; | 1191 | context->names[idx].mode = inode->i_mode; |
1176 | context->names[idx].uid = inode->i_uid; | 1192 | context->names[idx].uid = inode->i_uid; |
1177 | context->names[idx].gid = inode->i_gid; | 1193 | context->names[idx].gid = inode->i_gid; |
1178 | context->names[idx].rdev = inode->i_rdev; | 1194 | context->names[idx].rdev = inode->i_rdev; |
1179 | audit_inode_context(idx, inode); | 1195 | audit_inode_context(idx, inode); |
1180 | if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) && | ||
1181 | (strcmp(name, ".") != 0)) { | ||
1182 | context->names[idx].ino = (unsigned long)-1; | ||
1183 | context->names[idx].pino = inode->i_ino; | ||
1184 | } else { | ||
1185 | context->names[idx].ino = inode->i_ino; | ||
1186 | context->names[idx].pino = (unsigned long)-1; | ||
1187 | } | ||
1188 | } | 1196 | } |
1189 | 1197 | ||
1190 | /** | 1198 | /** |
@@ -1206,34 +1214,40 @@ void __audit_inode_child(const char *dname, const struct inode *inode, | |||
1206 | { | 1214 | { |
1207 | int idx; | 1215 | int idx; |
1208 | struct audit_context *context = current->audit_context; | 1216 | struct audit_context *context = current->audit_context; |
1217 | const char *found_name = NULL; | ||
1218 | int dirlen = 0; | ||
1209 | 1219 | ||
1210 | if (!context->in_syscall) | 1220 | if (!context->in_syscall) |
1211 | return; | 1221 | return; |
1212 | 1222 | ||
1213 | /* determine matching parent */ | 1223 | /* determine matching parent */ |
1214 | if (!dname) | 1224 | if (!dname) |
1215 | goto no_match; | 1225 | goto update_context; |
1216 | for (idx = 0; idx < context->name_count; idx++) | 1226 | for (idx = 0; idx < context->name_count; idx++) |
1217 | if (context->names[idx].pino == pino) { | 1227 | if (context->names[idx].ino == pino) { |
1218 | const char *name = context->names[idx].name; | 1228 | const char *name = context->names[idx].name; |
1219 | 1229 | ||
1220 | if (!name) | 1230 | if (!name) |
1221 | continue; | 1231 | continue; |
1222 | 1232 | ||
1223 | if (audit_compare_dname_path(dname, name) == 0) | 1233 | if (audit_compare_dname_path(dname, name, &dirlen) == 0) { |
1224 | goto update_context; | 1234 | context->names[idx].name_len = dirlen; |
1235 | found_name = name; | ||
1236 | break; | ||
1237 | } | ||
1225 | } | 1238 | } |
1226 | 1239 | ||
1227 | no_match: | 1240 | update_context: |
1228 | /* catch-all in case match not found */ | ||
1229 | idx = context->name_count++; | 1241 | idx = context->name_count++; |
1230 | context->names[idx].name = NULL; | ||
1231 | context->names[idx].pino = pino; | ||
1232 | #if AUDIT_DEBUG | 1242 | #if AUDIT_DEBUG |
1233 | context->ino_count++; | 1243 | context->ino_count++; |
1234 | #endif | 1244 | #endif |
1245 | /* Re-use the name belonging to the slot for a matching parent directory. | ||
1246 | * All names for this context are relinquished in audit_free_names() */ | ||
1247 | context->names[idx].name = found_name; | ||
1248 | context->names[idx].name_len = AUDIT_NAME_FULL; | ||
1249 | context->names[idx].name_put = 0; /* don't call __putname() */ | ||
1235 | 1250 | ||
1236 | update_context: | ||
1237 | if (inode) { | 1251 | if (inode) { |
1238 | context->names[idx].ino = inode->i_ino; | 1252 | context->names[idx].ino = inode->i_ino; |
1239 | context->names[idx].dev = inode->i_sb->s_dev; | 1253 | context->names[idx].dev = inode->i_sb->s_dev; |
@@ -1242,7 +1256,8 @@ update_context: | |||
1242 | context->names[idx].gid = inode->i_gid; | 1256 | context->names[idx].gid = inode->i_gid; |
1243 | context->names[idx].rdev = inode->i_rdev; | 1257 | context->names[idx].rdev = inode->i_rdev; |
1244 | audit_inode_context(idx, inode); | 1258 | audit_inode_context(idx, inode); |
1245 | } | 1259 | } else |
1260 | context->names[idx].ino = (unsigned long)-1; | ||
1246 | } | 1261 | } |
1247 | 1262 | ||
1248 | /** | 1263 | /** |