Re: Kernel oops with 2.6.26, padlock and ipsec: probably problem with fpu state changes

Wolfgang Walter
2008-08-08T19:10:05Z

Am Freitag, 8. August 2008 12:36 schrieb Wolfgang Walter:
> Am Donnerstag, 7. August 2008 18:23 schrieb Wolfgang Walter:
> > =======================================================
> > diff -ur ../linux-2.6.26/drivers/crypto/padlock-aes.c
> > ./drivers/crypto/padlock-aes.c ---
> > ../linux-2.6.26/drivers/crypto/padlock-aes.c 2008-07-15
> > 11:29:32.000000000 +0200 +++ ./drivers/crypto/padlock-aes.c 2008-08-07
> > 17:46:55.000000000 +0200 @@ -16,6 +16,7 @@
> > #include <linux/interrupt.h>
> > #include <linux/kernel.h>
> > #include <asm/byteorder.h>
> > +#include <asm/i387.h>
> > #include "padlock.h"
> >
> > /* Control word. */
> > @@ -144,9 +145,11 @@
> > static inline void padlock_xcrypt(const u8 *input, u8 *output, void
> > *key, void *control_word)
> > {
> > + kernel_fpu_begin();
> > asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */
> >
> > : "+S"(input), "+D"(output)
> > : "d"(control_word), "b"(key), "c"(1));
> >
> > + kernel_fpu_end();
> > }
> >
> > static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword
> > *cword) @@ -179,6 +182,7 @@
> > return;
> > }
> >
> > + kernel_fpu_begin();
> > asm volatile ("test $1, %%cl;"
> > "je 1f;"
> > "lea -1(%%ecx), %%eax;"
> > @@ -190,15 +194,18 @@
> >
> > : "+S"(input), "+D"(output)
> > : "d"(control_word), "b"(key), "c"(count)
> > : "ax");
> >
> > + kernel_fpu_end();
> > }
> >
> > static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void
> > *key, u8 *iv, void *control_word, u32 count)
> > {
> > /* rep xcryptcbc */
> > + kernel_fpu_begin();
> > asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
> >
> > : "+S" (input), "+D" (output), "+a" (iv)
> > : "d" (control_word), "b" (key), "c" (count));
> >
> > + kernel_fpu_end();
> > return iv;
> > }
> >
> > =============================================================
> >
> > I found that kernel_fpu_begin(); kernel_fpu_begin(); is used with
> > MMX and/or SSE:
> >
> > include/asm/xor_32.h
> > drivers/md/raid6mmx.c
> > drivers/md/raid6sse1.c
> > drivers/md/raid6sse2.c
> >
> >
> > With this change I its a little bit more stable, I needed more then 5
> > minutes to crash the kernel (repeated it several times). If I read
> > the code correctly this disables preemption for the time the padlock cmd
> > is executing.
>
> Forget that - I booted the wrong kernel.
>
> I now really test this modification and it seems to be stable. The router
> now runs for 45 minutes without oops.

It now runs for 8 hours.

So how to proceed?

Here a summary:

1) 2.6.25.x works

2) 2.6.26 without padlock works

3a) 2.6.26 using padlock and ipsec chrashes.

Always the same reason:

__switch_to() wants to fxsave but there is no memory allocated

which means that TS_USEDFPU has been set.

3b) 2.6.26 with padlock code from 2.6.25: using padlock and ipsec chrashes.

4) Reverting the fpu patches (from 2.6.25 to 2.6.26) fixes the problem.

5) Protecting the padlock cmds with kernel_fpu_begin(); kernel_fpu_begin();
fixes the problem.

Some thoughts:

4) probably fixes the problem because memory for fxsave is always allocated.

Maybe this is also the reason why 2.6.25 and earlier work.

5) is interesting:

kernel_fpu_begin() will save the fpu state if TS_USEDFPU is set - exactly as
__unlazy_fpu in __switch_to would do. So when the crypto code calls padlock
the world is ok: if TS_USEDFPU is set then memory has been allocated.

This makes me rather sure that there is no memory corruption by the network
code and/or crypto code itself overwriting the task_info stucture and setting
TS_USEDFPU.

I don't know though why kernel_fpu_begin exactly fixes the problem:

Maybe preemption must be disabled when padlocks RNG, ACE, Hash-engine etc. is
used. Maybe just some barrier is needed which preempt_disable provides.

The padlock programming guide states that padlock's RNG, ACE, ... internally
use SSE. Especially "it temporary enables SSE until no further SSE
instruction or XSTORE, ... is seen". Further it may overlap with execution of
non-SSE instructions.

Probably it is the best to treat the padlock opcodes as SSE instructions.

What should I do now?

Regards,
--
Wolfgang Walter
Studentenwerk München
Anstalt des öffentlichen Rechts