aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorWilliam Roberts <bill.c.roberts@gmail.com>2014-02-11 13:12:01 -0500
committerEric Paris <eparis@redhat.com>2014-03-20 10:10:52 -0400
commit3f1c82502c299da08b7b7f08b435212e51166ed9 (patch)
tree227bb78a5ab4b90c7293920e79e7b3d13add855e /kernel
parent21a6457a79a02908dc8e60fe820828b2cc72d13a (diff)
audit: Audit proc/<pid>/cmdline aka proctitle
During an audit event, cache and print the value of the process's proctitle value (proc/<pid>/cmdline). This is useful in situations where processes are started via fork'd virtual machines where the comm field is incorrect. Often times, setting the comm field still is insufficient as the comm width is not very wide and most virtual machine "package names" do not fit. Also, during execution, many threads have their comm field set as well. By tying it back to the global cmdline value for the process, audit records will be more complete in systems with these properties. An example of where this is useful and applicable is in the realm of Android. With Android, their is no fork/exec for VM instances. The bare, preloaded Dalvik VM listens for a fork and specialize request. When this request comes in, the VM forks, and the loads the specific application (specializing). This was done to take advantage of COW and to not require a load of basic packages by the VM on very app spawn. When this spawn occurs, the package name is set via setproctitle() and shows up in procfs. Many of these package names are longer then 16 bytes, the historical width of task->comm. Having the cmdline in the audit records will couple the application back to the record directly. Also, on my Debian development box, some audit records were more useful then what was printed under comm. The cached proctitle is tied to the life-cycle of the audit_context structure and is built on demand. Proctitle is controllable by userspace, and thus should not be trusted. It is meant as an aid to assist in debugging. The proctitle event is emitted during syscall audits, and can be filtered with auditctl. Example: type=AVC msg=audit(1391217013.924:386): avc: denied { getattr } for pid=1971 comm="mkdir" name="/" dev="selinuxfs" ino=1 scontext=system_u:system_r:consolekit_t:s0-s0:c0.c255 tcontext=system_u:object_r:security_t:s0 tclass=filesystem type=SYSCALL msg=audit(1391217013.924:386): arch=c000003e syscall=137 success=yes exit=0 a0=7f019dfc8bd7 a1=7fffa6aed2c0 a2=fffffffffff4bd25 a3=7fffa6aed050 items=0 ppid=1967 pid=1971 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="mkdir" exe="/bin/mkdir" subj=system_u:system_r:consolekit_t:s0-s0:c0.c255 key=(null) type=UNKNOWN[1327] msg=audit(1391217013.924:386): proctitle=6D6B646972002D70002F7661722F72756E2F636F6E736F6C65 Acked-by: Steve Grubb <sgrubb@redhat.com> (wrt record formating) Signed-off-by: William Roberts <wroberts@tresys.com> Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.h6
-rw-r--r--kernel/auditsc.c67
2 files changed, 73 insertions, 0 deletions
diff --git a/kernel/audit.h b/kernel/audit.h
index 57cc64d67718..38c967d28de5 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -106,6 +106,11 @@ struct audit_names {
106 bool should_free; 106 bool should_free;
107}; 107};
108 108
109struct audit_proctitle {
110 int len; /* length of the cmdline field. */
111 char *value; /* the cmdline field */
112};
113
109/* The per-task audit context. */ 114/* The per-task audit context. */
110struct audit_context { 115struct audit_context {
111 int dummy; /* must be the first element */ 116 int dummy; /* must be the first element */
@@ -202,6 +207,7 @@ struct audit_context {
202 } execve; 207 } execve;
203 }; 208 };
204 int fds[2]; 209 int fds[2];
210 struct audit_proctitle proctitle;
205 211
206#if AUDIT_DEBUG 212#if AUDIT_DEBUG
207 int put_count; 213 int put_count;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 6874c1fd453d..043d1ef9362f 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -70,6 +70,7 @@
70#include <linux/capability.h> 70#include <linux/capability.h>
71#include <linux/fs_struct.h> 71#include <linux/fs_struct.h>
72#include <linux/compat.h> 72#include <linux/compat.h>
73#include <linux/ctype.h>
73 74
74#include "audit.h" 75#include "audit.h"
75 76
@@ -81,6 +82,9 @@
81/* no execve audit message should be longer than this (userspace limits) */ 82/* no execve audit message should be longer than this (userspace limits) */
82#define MAX_EXECVE_AUDIT_LEN 7500 83#define MAX_EXECVE_AUDIT_LEN 7500
83 84
85/* max length to print of cmdline/proctitle value during audit */
86#define MAX_PROCTITLE_AUDIT_LEN 128
87
84/* number of audit rules */ 88/* number of audit rules */
85int audit_n_rules; 89int audit_n_rules;
86 90
@@ -844,6 +848,13 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
844 return context; 848 return context;
845} 849}
846 850
851static inline void audit_proctitle_free(struct audit_context *context)
852{
853 kfree(context->proctitle.value);
854 context->proctitle.value = NULL;
855 context->proctitle.len = 0;
856}
857
847static inline void audit_free_names(struct audit_context *context) 858static inline void audit_free_names(struct audit_context *context)
848{ 859{
849 struct audit_names *n, *next; 860 struct audit_names *n, *next;
@@ -956,6 +967,7 @@ static inline void audit_free_context(struct audit_context *context)
956 audit_free_aux(context); 967 audit_free_aux(context);
957 kfree(context->filterkey); 968 kfree(context->filterkey);
958 kfree(context->sockaddr); 969 kfree(context->sockaddr);
970 audit_proctitle_free(context);
959 kfree(context); 971 kfree(context);
960} 972}
961 973
@@ -1272,6 +1284,59 @@ static void show_special(struct audit_context *context, int *call_panic)
1272 audit_log_end(ab); 1284 audit_log_end(ab);
1273} 1285}
1274 1286
1287static inline int audit_proctitle_rtrim(char *proctitle, int len)
1288{
1289 char *end = proctitle + len - 1;
1290 while (end > proctitle && !isprint(*end))
1291 end--;
1292
1293 /* catch the case where proctitle is only 1 non-print character */
1294 len = end - proctitle + 1;
1295 len -= isprint(proctitle[len-1]) == 0;
1296 return len;
1297}
1298
1299static void audit_log_proctitle(struct task_struct *tsk,
1300 struct audit_context *context)
1301{
1302 int res;
1303 char *buf;
1304 char *msg = "(null)";
1305 int len = strlen(msg);
1306 struct audit_buffer *ab;
1307
1308 ab = audit_log_start(context, GFP_KERNEL, AUDIT_PROCTITLE);
1309 if (!ab)
1310 return; /* audit_panic or being filtered */
1311
1312 audit_log_format(ab, "proctitle=");
1313
1314 /* Not cached */
1315 if (!context->proctitle.value) {
1316 buf = kmalloc(MAX_PROCTITLE_AUDIT_LEN, GFP_KERNEL);
1317 if (!buf)
1318 goto out;
1319 /* Historically called this from procfs naming */
1320 res = get_cmdline(tsk, buf, MAX_PROCTITLE_AUDIT_LEN);
1321 if (res == 0) {
1322 kfree(buf);
1323 goto out;
1324 }
1325 res = audit_proctitle_rtrim(buf, res);
1326 if (res == 0) {
1327 kfree(buf);
1328 goto out;
1329 }
1330 context->proctitle.value = buf;
1331 context->proctitle.len = res;
1332 }
1333 msg = context->proctitle.value;
1334 len = context->proctitle.len;
1335out:
1336 audit_log_n_untrustedstring(ab, msg, len);
1337 audit_log_end(ab);
1338}
1339
1275static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) 1340static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
1276{ 1341{
1277 int i, call_panic = 0; 1342 int i, call_panic = 0;
@@ -1389,6 +1454,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
1389 audit_log_name(context, n, NULL, i++, &call_panic); 1454 audit_log_name(context, n, NULL, i++, &call_panic);
1390 } 1455 }
1391 1456
1457 audit_log_proctitle(tsk, context);
1458
1392 /* Send end of event record to help user space know we are finished */ 1459 /* Send end of event record to help user space know we are finished */
1393 ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); 1460 ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
1394 if (ab) 1461 if (ab)