kern/98460 : [kernel] [patch] fpu_clean_state() cannot be
disabled for not AMD processors, those are not vulnerable to
FreeBSD-SA-06:14.fpu
Rostislav Krasny
rosti.bsd at gmail.com
Fri Jun 16 05:00:55 UTC 2006
The following reply was made to PR kern/98460; it has been noted by GNATS.
From: Rostislav Krasny <rosti.bsd at gmail.com>
To: Bruce Evans <bde at zeta.org.au>
Cc: freebsd-gnats-submit at freebsd.org
Subject: Re: kern/98460 : [kernel] [patch] fpu_clean_state() cannot be
disabled for not AMD processors, those are not vulnerable to
FreeBSD-SA-06:14.fpu
Date: Fri, 16 Jun 2006 02:04:47 +0300
On Sat, 10 Jun 2006 11:26:20 +1000 (EST)
Bruce Evans <bde at zeta.org.au> wrote:
> On Fri, 9 Jun 2006, Rostislav Krasny wrote:
>
> > On Wed, 7 Jun 2006 12:09:10 +1000 (EST)
> > Bruce Evans <bde at zeta.org.au> wrote:
> >
> >>> And then you want to call the fpu_clean_state() function conditionally,
> >>> like in following example?
> >>>
> >>> if (cpu_fxsr & CPU_FXSR_NEEDCLEAN)
> >>> fpu_clean_state();
> >>
> >> Not quite like that. In my version there is no function call -- the code
> >> is excecuted in the one place where it is needed, so there is no function
> >> call overhead or possible branch prediction oferhead for the function call.
> >
> > Could you please explain in more detail how that can be done?
>
> Just do it. The easiest way is define the new function as inline.
> This just works because the function is defined before it is used.
>
> [snipped]
But you still check cpu_fxsr, so a branch misprediction on a good few
CPUs is still possible. The only solution is a self-modified code with
a direct jump. I made following userland example of such a code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
void fu(int n)
{
mprotect(&&lab0, 1, PROT_READ|PROT_WRITE|PROT_EXEC);
lab0:
asm volatile (" \n\
.byte 0xE9; \n\
l0: .long 0x00000000 \n\
l1: bt $0,%%ax; \n\
jnc l2; \n\
movl $l4,%%eax; \n\
subl $l1,%%eax; \n\
movl %%eax,l0; \n\
movl $0,%%eax; \n\
jmp l4; \n\
l2: movl $l3,%%eax; \n\
subl $l1,%%eax; \n\
movl %%eax,l0; \n\
movl $0,%%eax; \n\
jmp l4; \n\
l3: addl $0x0A,%%eax; \n\
l4: \n\
" : "=a"(n) : "a"(n));
printf("%d\n", n);
}
int main(int argc, char *argv[])
{
int n;
if (argc > 1)
n = atoi(argv[1]);
fu(n);
fu(n);
fu(n);
return 0;
}
For a demonstration purpose I made the fu() so that the first call of it
will printf 0, to show when code modification is done. All further calls
of fu() will print n or n+10, according to the first n.
I think there should be no need in mprotect() in the kernel. That
technique could be combined with an assembly version of fpu_clean_state()
from following article. See the '"FXRSTOR-centric" method':
http://security.freebsd.org/advisories/FreeBSD-SA-06:14-amd.txt
That might be tricky, I know. But why one should pay a performance
penalty because of a CPU he/she didn't buy?
More information about the freebsd-bugs
mailing list