Skip to contentSkip to conversation

repeatable 2.4.8-ac7, 2.4.7-ac6 just run xdos

OOPS Andi Kleen 4 participants 9 messages Aug 22, 2001 – Aug 23, 2001 1 message not in the archive

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Andi Kleen

author
#1 lore raw
Quoted 8 lines · Brian Gerst
Quoted 8 lines
CPU:    0
EIP:    0010:[<c0180a18>]

Using defaults from ksymoops -t elf32-i386 -a i386
EFLAGS: 00010002
eax: 00001000 ebx: c4562368 ecx: 00000000 edx: 00000001
esi: c4562368 edi: c4a954d4 ebp: 00000001 esp: c6887d88
ds: 008 es: 0000 ss: 0018

Quoted 5 lines
                ^^^^

Here is your problem. %es is set to the null segment. I had my suspicions about the segment reload optimisation in the -ac kernels, and this proves it. Try backing out the changes to arch/i386/kernel/entry.S and include/asm-i386/hw_irq.h and see if that fixes the problem.

This patch should fix the problem. One assumption coded into the reload optimization is violated by vm86 mode. Please test.

include/asm-i386/hw_irq.h renamed from include/asm-i386/hw_irq.h-SEG2 +3 -1
@@ -114,8 +114,10 @@
 	"cmpl %eax,7*4(%esp)\n\t"  \
 	"je 1f\n\t"  \
 	"movl %eax,%ds\n\t" \
+	"1: cmpl %eax,8*4(%esp)\n\t" \
+	"je 2f\n\t" \
 	"movl %eax,%es\n\t" \
-	"1:\n\t"
+	"2:\n\t"
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)

-Andi

#2 lore raw
In reply to a message not in the archive
Quoted 11 lines · Andi Kleen
Quoted 8 lines · Brian Gerst
Quoted 8 lines
CPU:    0
EIP:    0010:[<c0180a18>]

Using defaults from ksymoops -t elf32-i386 -a i386
EFLAGS: 00010002
eax: 00001000 ebx: c4562368 ecx: 00000000 edx: 00000001
esi: c4562368 edi: c4a954d4 ebp: 00000001 esp: c6887d88
ds: 008 es: 0000 ss: 0018

Quoted 8 lines
Quoted 5 lines
                ^^^^

Here is your problem. %es is set to the null segment. I had my suspicions about the segment reload optimisation in the -ac kernels, and this proves it. Try backing out the changes to arch/i386/kernel/entry.S and include/asm-i386/hw_irq.h and see if that fixes the problem.

This patch should fix the problem. One assumption coded into the reload optimization is violated by vm86 mode. Please test.

Yes. What happened here is that %ds and %es were not being updated atomically. Under normal operation, this would just leave %es with USER_DS, which is sufficiently equivalent to KERNEL_DS to not cause a fault. Coming out of vm86 mode however forces the data segment registers to null after saving the real mode values on the stack. If an interrupt happened between setting %ds and %es (what are the odds?) then that assumption would fail and leave %es null, causing the next string instruction to go boom. The same fix should be applied to entry.S as well.

Signature · 1 line
						Brian Gerst
author
#3 lore raw
In reply to a message not in the archive
Quoted 9 lines · Brian Gerst

Yes. What happened here is that %ds and %es were not being updated atomically. Under normal operation, this would just leave %es with USER_DS, which is sufficiently equivalent to KERNEL_DS to not cause a fault. Coming out of vm86 mode however forces the data segment registers to null after saving the real mode values on the stack. If an interrupt happened between setting %ds and %es (what are the odds?) then that assumption would fail and leave %es null, causing the next string instruction to go boom. The same fix should be applied to entry.S as well.

No that's not the problem. interrupt gates come in with interrupts off, so there are no other interrupts that could race here. The syscall entry always updates %ds/%es unconditionally and %ds first, so there is no race.

It was much simpler. It assumed that __KERNEL_DS could not be loaded from user space because of the segment register priviledge checking; and that was obviously not true from vm86 mode.

-Andi

#4 lore raw
In reply to a message not in the archive
Quoted 17 lines · Andi Kleen
Quoted 9 lines · Brian Gerst

Yes. What happened here is that %ds and %es were not being updated atomically. Under normal operation, this would just leave %es with USER_DS, which is sufficiently equivalent to KERNEL_DS to not cause a fault. Coming out of vm86 mode however forces the data segment registers to null after saving the real mode values on the stack. If an interrupt happened between setting %ds and %es (what are the odds?) then that assumption would fail and leave %es null, causing the next string instruction to go boom. The same fix should be applied to entry.S as well.

No that's not the problem. interrupt gates come in with interrupts off, so there are no other interrupts that could race here. The syscall entry always updates %ds/%es unconditionally and %ds first, so there is no race.

Quoted 5 lines

It was much simpler. It assumed that __KERNEL_DS could not be loaded from user space because of the segment register priviledge checking; and that was obviously not true from vm86 mode.

-Andi

The kernel was initially entered throught the general protection fault trap gate, with interupts on. The syscall entry was left on the stack because of the way sys_vm86 works.

Signature · 1 line
						Brian Gerst
author
#5 lore raw
In reply to a message not in the archive
Quoted 22 lines · Brian Gerst
Quoted 21 lines · Andi Kleen
Quoted 9 lines · Brian Gerst

Yes. What happened here is that %ds and %es were not being updated atomically. Under normal operation, this would just leave %es with USER_DS, which is sufficiently equivalent to KERNEL_DS to not cause a fault. Coming out of vm86 mode however forces the data segment registers to null after saving the real mode values on the stack. If an interrupt happened between setting %ds and %es (what are the odds?) then that assumption would fail and leave %es null, causing the next string instruction to go boom. The same fix should be applied to entry.S as well.

No that's not the problem. interrupt gates come in with interrupts off, so there are no other interrupts that could race here. The syscall entry always updates %ds/%es unconditionally and %ds first, so there is no race.

It was much simpler. It assumed that __KERNEL_DS could not be loaded from user space because of the segment register priviledge checking; and that was obviously not true from vm86 mode.

Quoted 5 lines
Quoted 1 line

-Andi

The kernel was initially entered throught the general protection fault trap gate, with interupts on. The syscall entry was left on the stack because of the way sys_vm86 works.

The GPF handler first sets %ds then %es. Interrupt checks %ds first. I don't see any race, as soon as %ds is changed the interrupt handler does the right thing (not reloading), and before that also.

The check I added with the previous patch for ds and es being out of sync however was also missing from exception handler entry. That probably caused the crash.

Here is a new patch with both checks.

asm-i386/hw_irq.h renamed from asm-i386/hw_irq.h-SEG2 +3 -1
@@ -114,8 +114,10 @@
 	"cmpl %eax,7*4(%esp)\n\t"  \
 	"je 1f\n\t"  \
 	"movl %eax,%ds\n\t" \
+	"1: cmpl %eax,8*4(%esp)\n\t" \
+	"je 2f\n\t" \
 	"movl %eax,%es\n\t" \
-	"1:\n\t"
+	"2:\n\t"
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
i386/kernel/entry.S renamed from i386/kernel/entry.S-SEG2 +4 -1
@@ -292,8 +292,11 @@
 	cmpl %edx,%ecx
 	jz	1f
 	movl %edx,%ds
+1:	movl %ds,%ecx
+	cmpl $(__KERNEL_DS),%edx
+	jz   2f	
 	movl %edx,%es
-1:	GET_CURRENT(%ebx)
+2:	GET_CURRENT(%ebx)
 	call *%edi
 	addl $8,%esp
 	jmp ret_from_exception

-Andi

#6 lore raw
In reply to a message not in the archive
Quoted 3 lines · Andi Kleen <[email protected]>, on Wed Aug 22, 2001 [03:22:03 PM] said:

Here is a new patch with both checks.

	Dear Andi;

	Well, with this patch, the kernel doesnt oops, but vm86

seems to be busted now. save_v86_state() pops out:
'vm86: could not access userspace vm86_info'
and gives dosemu a segv.

Paul
[email protected]

Quoted 33 lines
asm-i386/hw_irq.h renamed from asm-i386/hw_irq.h-SEG2 +3 -1
@@ -114,8 +114,10 @@
 	"cmpl %eax,7*4(%esp)\n\t"  \
 	"je 1f\n\t"  \
 	"movl %eax,%ds\n\t" \
+	"1: cmpl %eax,8*4(%esp)\n\t" \
+	"je 2f\n\t" \
 	"movl %eax,%es\n\t" \
-	"1:\n\t"
+	"2:\n\t"
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
i386/kernel/entry.S renamed from i386/kernel/entry.S-SEG2 +4 -2
@@ -292,8 +292,11 @@
 	cmpl %edx,%ecx
 	jz	1f
 	movl %edx,%ds
+1:	movl %ds,%ecx
+	cmpl $(__KERNEL_DS),%edx
+	jz   2f	
 	movl %edx,%es
-1:	GET_CURRENT(%ebx)
+2:	GET_CURRENT(%ebx)
 	call *%edi
 	addl $8,%esp
 	jmp ret_from_exception
 
 
-Andi
author
#7 lore raw
In reply to a message not in the archive
Quoted 11 lines · Paul
Quoted 3 lines · Andi Kleen <[email protected]>, on Wed Aug 22, 2001 [03:22:03 PM] said:

Here is a new patch with both checks.

	Dear Andi;

	Well, with this patch, the kernel doesnt oops, but vm86

seems to be busted now. save_v86_state() pops out:
'vm86: could not access userspace vm86_info'
and gives dosemu a segv.

I found the problem in the previous patch. Here is an updated one. Please test again. Again against -ac7 (or later if Alan hasn't applied the earlier patch)

-Andi

asm-i386/hw_irq.h renamed from asm-i386/hw_irq.h-SEG2 +3 -1
@@ -114,8 +114,10 @@
 	"cmpl %eax,7*4(%esp)\n\t"  \
 	"je 1f\n\t"  \
 	"movl %eax,%ds\n\t" \
+	"1: cmpl %eax,8*4(%esp)\n\t" \
+	"je 2f\n\t" \
 	"movl %eax,%es\n\t" \
-	"1:\n\t"
+	"2:\n\t"
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
i386/kernel/entry.S renamed from i386/kernel/entry.S-SEG2 +4 -2
@@ -291,9 +291,11 @@
 	movl $(__KERNEL_DS),%edx
 	cmpl %edx,%ecx
 	jz	1f
-	movl %edx,%ds
 	movl %edx,%es
-1:	GET_CURRENT(%ebx)
+1:	cmpl %edx,9*4(%esp)	# check ds on the stack
+	jz   2f	
+	movl %edx,%ds
+2:	GET_CURRENT(%ebx)
 	call *%edi
 	addl $8,%esp
 	jmp ret_from_exception
#8 lore raw
In reply to a message not in the archive
Quoted 8 lines · Andi Kleen <[email protected]>, on Thu Aug 23, 2001 [03:34:19 PM] said:

I found the problem in the previous patch. Here is an updated one. Please test again. Again against -ac7 (or later if Alan hasn't applied the earlier patch)

-Andi

Good! I have beaten on this a bit, and it is holding up
for me, and there are no problems using dosemu. My thanks to everyone who responded to this bug.

Paul
[email protected]

Quoted 32 lines
asm-i386/hw_irq.h renamed from asm-i386/hw_irq.h-SEG2 +3 -1
@@ -114,8 +114,10 @@
 	"cmpl %eax,7*4(%esp)\n\t"  \
 	"je 1f\n\t"  \
 	"movl %eax,%ds\n\t" \
+	"1: cmpl %eax,8*4(%esp)\n\t" \
+	"je 2f\n\t" \
 	"movl %eax,%es\n\t" \
-	"1:\n\t"
+	"2:\n\t"
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
i386/kernel/entry.S renamed from i386/kernel/entry.S-SEG2 +4 -2
@@ -291,9 +291,11 @@
 	movl $(__KERNEL_DS),%edx
 	cmpl %edx,%ecx
 	jz	1f
-	movl %edx,%ds
 	movl %edx,%es
-1:	GET_CURRENT(%ebx)
+1:	cmpl %edx,9*4(%esp)	# check ds on the stack
+	jz   2f	
+	movl %edx,%ds
+2:	GET_CURRENT(%ebx)
 	call *%edi
 	addl $8,%esp
 	jmp ret_from_exception
#9 lore raw
Quoted 3 lines · you

Good! I have beaten on this a bit, and it is holding up
for me, and there are no problems using dosemu. My thanks to everyone who responded to this bug.

FWIW, "me too" on 2.4.8-ac9. dos -X would lock the machine after about 15 minutes (Alt-Sysrq-B would work), with this patch it is gone.

Wayne