Dave Jones reported that he was able to provoke a machine check on ppc32 with his scrashme program, apparently as a result of missing access_ok checks on the arguments to the sys_debug_setcontext system call. In signal_32.c and signal_64.c there were other similar issues. Some of them are pretty serious. One of them will let an unprivileged user program read any kernel memory on ppc64 systems with Altivec. Both 32-bit and 64-bit kernels are affected and some of the problems go back to the 2.4 days. It appears that some of the people that did the original ppc64 port liked to do ret = put_user(&p->a); ret |= __put_user(&p->b); if (ret) return -EFAULT; which is of course *not* a good idea, although if (put_user(&p->a) || __put_user(&p->b)) return -EFAULT; is OK on ppc64 because of the large gap between TASK_SIZE and KERNELBASE.
Paul Mackerras revised his initial post and mentioned that those of the bogosities found that are in the 32-bit compatibility code for 64-bit kernels aren't actually security holes, since it isn't possible for a 32-bit process to generate a kernel address. That leaves: - a hole in the 64-bit kernel that lets unprivileged processes read (but not write) arbitrary kernel memory on systems that have Altivec. - a hole that lets processes on a 32-bit kernel restore their register set from an arbitrary kernel address (on signal return or with the sys_swapcontext or sys_debug_setcontext system calls). That only reads kernel memory and would be hard to exploit as a method of reading kernel memory since the program counter would be set to some hard-to-predict value. It could be used to crash the system though.
The arch/powerpc/kernel/signal_32.c changes from the patch map to ppc64/kernel/signal32.c in the RHEL4 kernel. In sys32_rt_sigaction() we see the same problems addressed in the upstream patch. The do_setcontext32() function is missing a verify_area() call. In sys32_swapcontext() the RHEL4 kernel has the needed verify_area() call already. So it seems this one got removed upstream during the PowerPC re-organization. The verify_area() call in arch/ppc64/kernel/signal.c for the Altivec specific issue is missing.
Of which, the only one which actually matters is the last, because the rest will all be limited to 32-bit addresses anyway. There's also a suspect read from regs->rip in fix_alignment(), in some circumstances.
Created attachment 130744 [details] RHEL4 patch
The final upstream patch can be found here: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7c85d1f9d358b24c5b05c3a2783a78423775a080
------- Additional Comments From holtmann 2006-06-12 03:11 EST ------- For reference the upstream fix can be found here: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7c85d1f9d358b24c5b05c3a2783a78423775a080
Created attachment 130940 [details] Updated minimal and correct patch The part in fix_alignment() in the previous patch was not necessary. Also, revert to using access_ok() as in the original upstream patch, having corrected the length. This is the version which was tested.
committed in stream U4 build 39.2. A test kernel with this patch is available from http://people.redhat.com/~jbaron/rhel4/
An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on the solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHSA-2006-0575.html