xorl %eax, %eax

CVE-2008-4410: Linux kernel x86 Invalid LDT Access in VMI

leave a comment »

This is nothing really important. It’s just a typo reported by Zachary Amsden of VMware on 30 September 2008. It affects Linux kernel 2.6.26.5 and probably earlier releases. Here is the vulnerable function found at arch/x86/kernel/vmi_32.c:

233 static void vmi_write_ldt_entry(struct desc_struct *dt, int entry,
234                                const void *desc)
235 {
236        u32 *ldt_entry = (u32 *)desc;
237        vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
238 }

This cute little void function is used to set an operation of the cached VMI (Virtual Machine Interface) operations which are just a few function pointers:

60 /* Cached VMI operations */
61 static struct {
62        void (*cpuid)(void /* non-c */);
63        void (*_set_ldt)(u32 selector);
64        void (*set_tr)(u32 selector);
65        void (*write_idt_entry)(struct desc_struct *, int, u32, u32);
66        void (*write_gdt_entry)(struct desc_struct *, int, u32, u32);
67        void (*write_ldt_entry)(struct desc_struct *, int, u32, u32);
68        void (*set_kernel_stack)(u32 selector, u32 sp0);
69        void (*allocate_page)(u32, u32, u32, u32, u32);
70        void (*release_page)(u32, u32);
71        void (*set_pte)(pte_t, pte_t *, unsigned);
72        void (*update_pte)(pte_t *, unsigned);
73        void (*set_linear_mapping)(int, void *, u32, u32);
74        void (*_flush_tlb)(int);
75        void (*set_initial_ap_state)(int, int);
76        void (*halt)(void);
77        void (*set_lazy_mode)(int mode);
78 } vmi_ops;

As you can see, it correctly passes the new arguments to the function pointer operation but it’s storing them in the wrong one. It uses write_idt_entry() which is responsible for the IDT (Interrupt Descriptor Table) instead of write_ldt_entry() that its name implies it should. In addition, the function responsible for writing entries to IDT already exists:

220 static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
221 {
222        u32 *idt_entry = (u32 *)g;
223        vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[1]);
224 }

Well, of course the patch was to simply replace this function pointer with the correct one, the one for the LDT (Local Descriptor Table):

 {
        u32 *ldt_entry = (u32 *)desc;
-       vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
+       vmi_ops.write_ldt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
 }

But what can an attacker do with this? Well, to be honest I’m not sure. CVE Mitre has a “suggestion” that might be interesting…

allows local users to cause a denial of service (persistent application failure) 
via crafted function calls, related to the Java Runtime Environment (JRE) 
experiencing improper LDT selector state, a different vulnerability 
than CVE-2008-3247.

Obviously, this can lead to some OOPS or panic but anything more? Writing an entry to IDT when you shouldn’t sounds pretty evil to me. Anyway…

Written by xorl

April 7, 2009 at 13:59

Posted in bugs, linux

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s