aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.c54
-rw-r--r--kernel/audit.h3
-rw-r--r--kernel/auditfilter.c8
-rw-r--r--kernel/auditsc.c123
4 files changed, 127 insertions, 61 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index 0fbf1c116363..7dfac7031bd7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1051,20 +1051,53 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
1051 skb_put(skb, len << 1); /* new string is twice the old string */ 1051 skb_put(skb, len << 1); /* new string is twice the old string */
1052} 1052}
1053 1053
1054/*
1055 * Format a string of no more than slen characters into the audit buffer,
1056 * enclosed in quote marks.
1057 */
1058static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
1059 const char *string)
1060{
1061 int avail, new_len;
1062 unsigned char *ptr;
1063 struct sk_buff *skb;
1064
1065 BUG_ON(!ab->skb);
1066 skb = ab->skb;
1067 avail = skb_tailroom(skb);
1068 new_len = slen + 3; /* enclosing quotes + null terminator */
1069 if (new_len > avail) {
1070 avail = audit_expand(ab, new_len);
1071 if (!avail)
1072 return;
1073 }
1074 ptr = skb->tail;
1075 *ptr++ = '"';
1076 memcpy(ptr, string, slen);
1077 ptr += slen;
1078 *ptr++ = '"';
1079 *ptr = 0;
1080 skb_put(skb, slen + 2); /* don't include null terminator */
1081}
1082
1054/** 1083/**
1055 * audit_log_unstrustedstring - log a string that may contain random characters 1084 * audit_log_n_unstrustedstring - log a string that may contain random characters
1056 * @ab: audit_buffer 1085 * @ab: audit_buffer
1086 * @len: lenth of string (not including trailing null)
1057 * @string: string to be logged 1087 * @string: string to be logged
1058 * 1088 *
1059 * This code will escape a string that is passed to it if the string 1089 * This code will escape a string that is passed to it if the string
1060 * contains a control character, unprintable character, double quote mark, 1090 * contains a control character, unprintable character, double quote mark,
1061 * or a space. Unescaped strings will start and end with a double quote mark. 1091 * or a space. Unescaped strings will start and end with a double quote mark.
1062 * Strings that are escaped are printed in hex (2 digits per char). 1092 * Strings that are escaped are printed in hex (2 digits per char).
1093 *
1094 * The caller specifies the number of characters in the string to log, which may
1095 * or may not be the entire string.
1063 */ 1096 */
1064const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string) 1097const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
1098 const char *string)
1065{ 1099{
1066 const unsigned char *p = string; 1100 const unsigned char *p = string;
1067 size_t len = strlen(string);
1068 1101
1069 while (*p) { 1102 while (*p) {
1070 if (*p == '"' || *p < 0x21 || *p > 0x7f) { 1103 if (*p == '"' || *p < 0x21 || *p > 0x7f) {
@@ -1073,10 +1106,23 @@ const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *strin
1073 } 1106 }
1074 p++; 1107 p++;
1075 } 1108 }
1076 audit_log_format(ab, "\"%s\"", string); 1109 audit_log_n_string(ab, len, string);
1077 return p + 1; 1110 return p + 1;
1078} 1111}
1079 1112
1113/**
1114 * audit_log_unstrustedstring - log a string that may contain random characters
1115 * @ab: audit_buffer
1116 * @string: string to be logged
1117 *
1118 * Same as audit_log_n_unstrustedstring(), except that strlen is used to
1119 * determine string length.
1120 */
1121const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
1122{
1123 return audit_log_n_untrustedstring(ab, strlen(string), string);
1124}
1125
1080/* This is a helper-function to print the escaped d_path */ 1126/* This is a helper-function to print the escaped d_path */
1081void audit_log_d_path(struct audit_buffer *ab, const char *prefix, 1127void audit_log_d_path(struct audit_buffer *ab, const char *prefix,
1082 struct dentry *dentry, struct vfsmount *vfsmnt) 1128 struct dentry *dentry, struct vfsmount *vfsmnt)
diff --git a/kernel/audit.h b/kernel/audit.h
index 58fa44cb8d01..8323e4132a33 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -104,7 +104,8 @@ static inline int audit_hash_ino(u32 ino)
104} 104}
105 105
106extern int audit_comparator(const u32 left, const u32 op, const u32 right); 106extern int audit_comparator(const u32 left, const u32 op, const u32 right);
107extern int audit_compare_dname_path(const char *dname, const char *path); 107extern int audit_compare_dname_path(const char *dname, const char *path,
108 int *dirlen);
108extern struct sk_buff * audit_make_reply(int pid, int seq, int type, 109extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
109 int done, int multi, 110 int done, int multi,
110 void *payload, int size); 111 void *payload, int size);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index a536f7148bcd..4c99d2c586ed 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -787,7 +787,7 @@ static void audit_update_watch(struct audit_parent *parent,
787 787
788 mutex_lock(&audit_filter_mutex); 788 mutex_lock(&audit_filter_mutex);
789 list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { 789 list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
790 if (audit_compare_dname_path(dname, owatch->path)) 790 if (audit_compare_dname_path(dname, owatch->path, NULL))
791 continue; 791 continue;
792 792
793 /* If the update involves invalidating rules, do the inode-based 793 /* If the update involves invalidating rules, do the inode-based
@@ -1387,7 +1387,8 @@ int audit_comparator(const u32 left, const u32 op, const u32 right)
1387 1387
1388/* Compare given dentry name with last component in given path, 1388/* Compare given dentry name with last component in given path,
1389 * return of 0 indicates a match. */ 1389 * return of 0 indicates a match. */
1390int audit_compare_dname_path(const char *dname, const char *path) 1390int audit_compare_dname_path(const char *dname, const char *path,
1391 int *dirlen)
1391{ 1392{
1392 int dlen, plen; 1393 int dlen, plen;
1393 const char *p; 1394 const char *p;
@@ -1416,6 +1417,9 @@ int audit_compare_dname_path(const char *dname, const char *path)
1416 p++; 1417 p++;
1417 } 1418 }
1418 1419
1420 /* return length of path's directory component */
1421 if (dirlen)
1422 *dirlen = p - path;
1419 return strncmp(p, dname, dlen); 1423 return strncmp(p, dname, dlen);
1420} 1424}
1421 1425
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. */
90struct audit_names { 93struct 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 */
1148void __audit_inode(const char *name, const struct inode *inode, unsigned flags) 1163void __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
1227no_match: 1240update_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
1236update_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/**