Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 144866 - Kernel: IA64 Local denial of service vulnerability (CVE-2006-3635)
Summary: Kernel: IA64 Local denial of service vulnerability (CVE-2006-3635)
Status: RESOLVED INVALID
Alias: None
Product: Gentoo Security
Classification: Unclassified
Component: Kernel (show other bugs)
Hardware: All Linux
: High normal (vote)
Assignee: Gentoo Security
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-08-23 08:56 UTC by Sune Kloppenborg Jeppesen (RETIRED)
Modified: 2006-12-27 01:19 UTC (History)
0 users

See Also:
Package list:
Runtime testing required: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2006-08-23 08:56:18 UTC
Author: Tony Luck <tony.luck@intel.com>
Date:   Mon Aug 14 10:50:51 2006 -0700

    [IA64] Workaround for RSE issue
    
    Problem: An application violating the architectural rules regarding
    operation dependencies and having specific Register Stack Engine (RSE)
    state at the time of the violation, may result in an illegal operation
    fault and invalid RSE state.  Such faults may initiate a cascade of
    repeated illegal operation faults within OS interruption handlers.
    The specific behavior is OS dependent.
    
    Implication: An application causing an illegal operation fault with
    specific RSE state may result in a series of illegal operation faults
    and an eventual OS stack overflow condition.
    
    Workaround: OS interruption handlers that switch to kernel backing
    store implement a check for invalid RSE state to avoid the series
    of illegal operation faults.
    
    The core of the workaround is the RSE_WORKAROUND code sequence
    inserted into each invocation of the SAVE_MIN_WITH_COVER and
    SAVE_MIN_WITH_COVER_R19 macros.  This sequence includes hard-coded
    constants that depend on the number of stacked physical registers
    being 96.  The rest of this patch consists of code to disable this
    workaround should this not be the case (with the presumption that
    if a future Itanium processor increases the number of registers, it
    would also remove the need for this patch).
Comment 1 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2006-08-23 08:57:03 UTC
diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h
index c9ac8ba..950cc9a 100644
--- a/arch/ia64/kernel/minstate.h
+++ b/arch/ia64/kernel/minstate.h
@@ -3,6 +3,9 @@ #include <asm/cache.h>
 
 #include "entry.h"
 
+.section ".data.patch.rse", "a"
+.previous
+
 /*
  * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves
  * the minimum state necessary that allows us to turn psr.ic back
@@ -28,7 +31,8 @@ #include "entry.h"
  * Note that psr.ic is NOT turned on by this macro.  This is so that
  * we can pass interruption state as arguments to a handler.
  */
-#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA)                                                      \
+#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA,WORKAROUND)                                           \
+3:                                                                                             \
        mov r16=IA64_KR(CURRENT);       /* M */                                                 \
        mov r27=ar.rsc;                 /* M */                                                 \
        mov r20=r1;                     /* A */                                                 \
@@ -75,6 +79,7 @@ (pUStk)       mov ar.rsc=0x3;         /* set eager mo
        tbit.nz p15,p0=r29,IA64_PSR_I_BIT;                                                      \
        mov r29=b0                                                                              \
        ;;                                                                                      \
+       WORKAROUND;                                                                             \
        adds r16=PT(R8),r1;     /* initialize first base pointer */                             \
        adds r17=PT(R9),r1;     /* initialize second base pointer */                            \
 (pKStk)        mov r18=r0;             /* make sure r18 isn't NaT */                                   \
@@ -192,6 +197,34 @@ #define SAVE_REST                          \
        st8 [r25]=r10;          /* ar.ssd */    \
        ;;
 
-#define SAVE_MIN_WITH_COVER    DO_SAVE_MIN(cover, mov r30=cr.ifs,)
-#define SAVE_MIN_WITH_COVER_R19        DO_SAVE_MIN(cover, mov r30=cr.ifs, mov r15=r19)
-#define SAVE_MIN               DO_SAVE_MIN(     , mov r30=r0, )
+#define RSE_WORKAROUND                         \
+(pUStk) extr.u r17=r18,3,6;                    \
+(pUStk)        sub r16=r18,r22;                        \
+[1:](pKStk)    br.cond.sptk.many 1f;           \
+       .xdata4 ".data.patch.rse",1b-.          \
+       ;;                                      \
+       cmp.ge p6,p7 = 32,r17;                  \
+       ;;                                      \
+(p6)   mov r17=0x310;                          \
+(p7)   mov r17=0x308;                          \
+       ;;                                      \
+       cmp.leu p1,p0=r16,r17;                  \
+(p1)   br.cond.sptk.many 1f;                   \
+       dep.z r17=r26,0,62;                     \
+       movl r16=2f;                            \
+       ;;                                      \
+       mov ar.pfs=r17;                         \
+       dep r27=r0,r27,16,14;                   \
+       mov b0=r16;                             \
+       ;;                                      \
+       br.ret.sptk b0;                         \
+       ;;                                      \
+2:                                             \
+       mov ar.rsc=r0                           \
+       ;;                                      \
+       flushrs;                                \
+1:
+
+#define SAVE_MIN_WITH_COVER    DO_SAVE_MIN(cover, mov r30=cr.ifs, , RSE_WORKAROUND)
+#define SAVE_MIN_WITH_COVER_R19        DO_SAVE_MIN(cover, mov r30=cr.ifs, mov r15=r19, RSE_WORKAROUND)
+#define SAVE_MIN                       DO_SAVE_MIN(     , mov r30=r0, , )
diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c
index bc11bb0..e34c962 100644
--- a/arch/ia64/kernel/patch.c
+++ b/arch/ia64/kernel/patch.c
@@ -115,6 +115,29 @@ ia64_patch_vtop (unsigned long start, un
        ia64_srlz_i();
 }
 
+/*
+ * Disable the RSE workaround by turning the conditional branch
+ * that we tagged in each place the workaround was used into an
+ * unconditional branch.
+ */
+void __init
+ia64_patch_rse (unsigned long start, unsigned long end)
+{
+       s32 *offp = (s32 *) start;
+       u64 ip, *b;
+
+       while (offp < (s32 *) end) {
+               ip = (u64) offp + *offp;
+
+               b = (u64 *)(ip & -16);
+               b[1] &= ~0xf800000L;
+               ia64_fc((void *) ip);
+               ++offp;
+       }
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+
 void __init
 ia64_patch_mckinley_e9 (unsigned long start, unsigned long end)
 {
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 7ad0d9c..0c2cfeb 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -436,6 +436,17 @@ #endif /* CONFIG_APCI_BOOT */
        /* process SAL system table: */
        ia64_sal_init(__va(efi.sal_systab));
 
+#ifdef CONFIG_ITANIUM
+       ia64_patch_rse((u64) __start___rse_patchlist, (u64) __end___rse_patchlist);
+#else
+       {
+               u64 num_phys_stacked;
+
+               if (ia64_pal_rse_info(&num_phys_stacked, 0) == 0 && num_phys_stacked > 96)
+                       ia64_patch_rse((u64) __start___rse_patchlist, (u64) __end___rse_patchlist);
+       }
+#endif
+
        ia64_setup_printk_clock();
 
 #ifdef CONFIG_SMP
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 5b0d5f6..5b4b641 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -145,6 +145,13 @@ #endif
          __end___vtop_patchlist = .;
        }
 
+  .data.patch.rse : AT(ADDR(.data.patch.rse) - LOAD_OFFSET)
+       {
+         __start___rse_patchlist = .;
+         *(.data.patch.rse)
+         __end___rse_patchlist = .;
+       }
+
   .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET)
        {
          __start___mckinley_e9_bundles = .;
diff --git a/include/asm-ia64/patch.h b/include/asm-ia64/patch.h
index 4797f35..c9f0f36 100644
--- a/include/asm-ia64/patch.h
+++ b/include/asm-ia64/patch.h
@@ -20,6 +20,7 @@ extern void ia64_patch_imm60 (u64 insn_a
 
 extern void ia64_patch_mckinley_e9 (unsigned long start, unsigned long end);
 extern void ia64_patch_vtop (unsigned long start, unsigned long end);
+extern void ia64_patch_rse (unsigned long start, unsigned long end);
 extern void ia64_patch_gate (void);
 
 #endif /* _ASM_IA64_PATCH_H */
diff --git a/include/asm-ia64/sections.h b/include/asm-ia64/sections.h
index e9eb7f6..ffcd842 100644
--- a/include/asm-ia64/sections.h
+++ b/include/asm-ia64/sections.h
@@ -10,6 +10,7 @@ #include <asm-generic/sections.h>
 
 extern char __per_cpu_start[], __per_cpu_end[], __phys_per_cpu_start[];
 extern char __start___vtop_patchlist[], __end___vtop_patchlist[];
+extern char __start___rse_patchlist[], __end___rse_patchlist[];
 extern char __start___mckinley_e9_bundles[], __end___mckinley_e9_bundles[];
 extern char __start_gate_section[];
 extern char __start_gate_mckinley_e9_patchlist[], __end_gate_mckinley_e9_patchlist[];
Comment 2 Tim Yamin (RETIRED) gentoo-dev 2006-08-23 08:58:42 UTC
Patch doesn't work correctly supposedly -- they're working on a new one. This only affects gentoo-sources and I'm tracking the issue on v-s so I'll close this bug down.