aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2007-07-19 04:48:15 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:45 -0400
commitbdf4c48af20a3b0f01671799ace345e3d49576da (patch)
tree7c3b903d2de1cba6e212ad6f347bc8742b08035a
parentb111757c50ee30dad162192df6168e270a90c252 (diff)
audit: rework execve audit
The purpose of audit_bprm() is to log the argv array to a userspace daemon at the end of the execve system call. Since user-space hasn't had time to run, this array is still in pristine state on the process' stack; so no need to copy it, we can just grab it from there. In order to minimize the damage to audit_log_*() copy each string into a temporary kernel buffer first. Currently the audit code requires that the full argument vector fits in a single packet. So currently it does clip the argv size to a (sysctl) limit, but only when execve auditing is enabled. If the audit protocol gets extended to allow for multiple packets this check can be removed. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Ollie Wild <aaw@google.com> Cc: <linux-audit@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/filesystems/proc.txt7
-rw-r--r--fs/exec.c3
-rw-r--r--include/linux/binfmts.h1
-rw-r--r--kernel/auditsc.c84
-rw-r--r--kernel/sysctl.c11
5 files changed, 85 insertions, 21 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index ebffdffb3d99..72e247ef6fa2 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1065,6 +1065,13 @@ check the amount of free space (value is in seconds). Default settings are: 4,
1065resume it if we have a value of 3 or more percent; consider information about 1065resume it if we have a value of 3 or more percent; consider information about
1066the amount of free space valid for 30 seconds 1066the amount of free space valid for 30 seconds
1067 1067
1068audit_argv_kb
1069-------------
1070
1071The file contains a single value denoting the limit on the argv array size
1072for execve (in KiB). This limit is only applied when system call auditing for
1073execve is enabled, otherwise the value is ignored.
1074
1068ctrl-alt-del 1075ctrl-alt-del
1069------------ 1076------------
1070 1077
diff --git a/fs/exec.c b/fs/exec.c
index f20561ff4528..2e3f7950c185 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1154,6 +1154,7 @@ int do_execve(char * filename,
1154{ 1154{
1155 struct linux_binprm *bprm; 1155 struct linux_binprm *bprm;
1156 struct file *file; 1156 struct file *file;
1157 unsigned long env_p;
1157 int retval; 1158 int retval;
1158 int i; 1159 int i;
1159 1160
@@ -1208,9 +1209,11 @@ int do_execve(char * filename,
1208 if (retval < 0) 1209 if (retval < 0)
1209 goto out; 1210 goto out;
1210 1211
1212 env_p = bprm->p;
1211 retval = copy_strings(bprm->argc, argv, bprm); 1213 retval = copy_strings(bprm->argc, argv, bprm);
1212 if (retval < 0) 1214 if (retval < 0)
1213 goto out; 1215 goto out;
1216 bprm->argv_len = env_p - bprm->p;
1214 1217
1215 retval = search_binary_handler(bprm,regs); 1218 retval = search_binary_handler(bprm,regs);
1216 if (retval >= 0) { 1219 if (retval >= 0) {
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index e1a708337be3..a0b209cd5761 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -40,6 +40,7 @@ struct linux_binprm{
40 unsigned interp_flags; 40 unsigned interp_flags;
41 unsigned interp_data; 41 unsigned interp_data;
42 unsigned long loader, exec; 42 unsigned long loader, exec;
43 unsigned long argv_len;
43}; 44};
44 45
45#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0 46#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b7640a5f382a..535586fc498b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -153,7 +153,7 @@ struct audit_aux_data_execve {
153 struct audit_aux_data d; 153 struct audit_aux_data d;
154 int argc; 154 int argc;
155 int envc; 155 int envc;
156 char mem[0]; 156 struct mm_struct *mm;
157}; 157};
158 158
159struct audit_aux_data_socketcall { 159struct audit_aux_data_socketcall {
@@ -831,6 +831,55 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
831 return rc; 831 return rc;
832} 832}
833 833
834static void audit_log_execve_info(struct audit_buffer *ab,
835 struct audit_aux_data_execve *axi)
836{
837 int i;
838 long len, ret;
839 const char __user *p = (const char __user *)axi->mm->arg_start;
840 char *buf;
841
842 if (axi->mm != current->mm)
843 return; /* execve failed, no additional info */
844
845 for (i = 0; i < axi->argc; i++, p += len) {
846 len = strnlen_user(p, MAX_ARG_PAGES*PAGE_SIZE);
847 /*
848 * We just created this mm, if we can't find the strings
849 * we just copied into it something is _very_ wrong. Similar
850 * for strings that are too long, we should not have created
851 * any.
852 */
853 if (!len || len > MAX_ARG_STRLEN) {
854 WARN_ON(1);
855 send_sig(SIGKILL, current, 0);
856 }
857
858 buf = kmalloc(len, GFP_KERNEL);
859 if (!buf) {
860 audit_panic("out of memory for argv string\n");
861 break;
862 }
863
864 ret = copy_from_user(buf, p, len);
865 /*
866 * There is no reason for this copy to be short. We just
867 * copied them here, and the mm hasn't been exposed to user-
868 * space yet.
869 */
870 if (!ret) {
871 WARN_ON(1);
872 send_sig(SIGKILL, current, 0);
873 }
874
875 audit_log_format(ab, "a%d=", i);
876 audit_log_untrustedstring(ab, buf);
877 audit_log_format(ab, "\n");
878
879 kfree(buf);
880 }
881}
882
834static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) 883static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
835{ 884{
836 int i, call_panic = 0; 885 int i, call_panic = 0;
@@ -971,13 +1020,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
971 1020
972 case AUDIT_EXECVE: { 1021 case AUDIT_EXECVE: {
973 struct audit_aux_data_execve *axi = (void *)aux; 1022 struct audit_aux_data_execve *axi = (void *)aux;
974 int i; 1023 audit_log_execve_info(ab, axi);
975 const char *p;
976 for (i = 0, p = axi->mem; i < axi->argc; i++) {
977 audit_log_format(ab, "a%d=", i);
978 p = audit_log_untrustedstring(ab, p);
979 audit_log_format(ab, "\n");
980 }
981 break; } 1024 break; }
982 1025
983 case AUDIT_SOCKETCALL: { 1026 case AUDIT_SOCKETCALL: {
@@ -1821,32 +1864,31 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode
1821 return 0; 1864 return 0;
1822} 1865}
1823 1866
1867int audit_argv_kb = 32;
1868
1824int audit_bprm(struct linux_binprm *bprm) 1869int audit_bprm(struct linux_binprm *bprm)
1825{ 1870{
1826 struct audit_aux_data_execve *ax; 1871 struct audit_aux_data_execve *ax;
1827 struct audit_context *context = current->audit_context; 1872 struct audit_context *context = current->audit_context;
1828 unsigned long p, next;
1829 void *to;
1830 1873
1831 if (likely(!audit_enabled || !context || context->dummy)) 1874 if (likely(!audit_enabled || !context || context->dummy))
1832 return 0; 1875 return 0;
1833 1876
1834 ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p, 1877 /*
1835 GFP_KERNEL); 1878 * Even though the stack code doesn't limit the arg+env size any more,
1879 * the audit code requires that _all_ arguments be logged in a single
1880 * netlink skb. Hence cap it :-(
1881 */
1882 if (bprm->argv_len > (audit_argv_kb << 10))
1883 return -E2BIG;
1884
1885 ax = kmalloc(sizeof(*ax), GFP_KERNEL);
1836 if (!ax) 1886 if (!ax)
1837 return -ENOMEM; 1887 return -ENOMEM;
1838 1888
1839 ax->argc = bprm->argc; 1889 ax->argc = bprm->argc;
1840 ax->envc = bprm->envc; 1890 ax->envc = bprm->envc;
1841 for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) { 1891 ax->mm = bprm->mm;
1842 struct page *page = bprm->page[p / PAGE_SIZE];
1843 void *kaddr = kmap(page);
1844 next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1);
1845 memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p);
1846 to += next - p;
1847 kunmap(page);
1848 }
1849
1850 ax->d.type = AUDIT_EXECVE; 1892 ax->d.type = AUDIT_EXECVE;
1851 ax->d.next = context->aux; 1893 ax->d.next = context->aux;
1852 context->aux = (void *)ax; 1894 context->aux = (void *)ax;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 3ed4912bf183..8db41764e2a1 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -78,6 +78,7 @@ extern int percpu_pagelist_fraction;
78extern int compat_log; 78extern int compat_log;
79extern int maps_protect; 79extern int maps_protect;
80extern int sysctl_stat_interval; 80extern int sysctl_stat_interval;
81extern int audit_argv_kb;
81 82
82/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ 83/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
83static int maxolduid = 65535; 84static int maxolduid = 65535;
@@ -306,6 +307,16 @@ static ctl_table kern_table[] = {
306 .mode = 0644, 307 .mode = 0644,
307 .proc_handler = &proc_dointvec, 308 .proc_handler = &proc_dointvec,
308 }, 309 },
310#ifdef CONFIG_AUDITSYSCALL
311 {
312 .ctl_name = CTL_UNNUMBERED,
313 .procname = "audit_argv_kb",
314 .data = &audit_argv_kb,
315 .maxlen = sizeof(int),
316 .mode = 0644,
317 .proc_handler = &proc_dointvec,
318 },
319#endif
309 { 320 {
310 .ctl_name = KERN_CORE_PATTERN, 321 .ctl_name = KERN_CORE_PATTERN,
311 .procname = "core_pattern", 322 .procname = "core_pattern",