Skip to contentSkip to conversation

i386 Linux kernel DoS (clarification)

DISCUSSION Petr Vandrovec 3 participants 4 messages Nov 13, 2002 – Nov 14, 2002

lore
Share & tools
lore
#0 lore raw
Quoted 3 lines · Alan Cox

Try this

(In the Linus Torvalds tradition its not tested)

I'll test it, but before kernel compiles...

i386/kernel/entry.S 2002-11-13 21:29:47.000000000 +0000 line 129

Quoted 7 lines
i386/kernel/entry.S 2002-11-13 21:29:47.000000000 +0000 renamed from i386/kernel/entry.S~ 2002-11-13 21:30:37.000000000 +0000 +1 -0
@@ -126,6 +126,7 @@
 ENTRY(lcall7)
    pushfl          # We get a different stack layout with call
                # gates, which has to be cleaned up later..
+   andl $~0x4500, (%esp)   # Clear NT since we are doing an iret

this will clear 'D' and 'T' in caller after we do iret (if lcall7 returns, of course). I'm not sure that callers expect that.

i386/kernel/entry.S 2002-11-13 21:29:47.000000000 +0000 line 397

Quoted 7 lines
i386/kernel/entry.S 2002-11-13 21:29:47.000000000 +0000 renamed from i386/kernel/entry.S~ 2002-11-13 21:30:37.000000000 +0000 +3 -0
@@ -390,6 +392,9 @@
    pushl $do_divide_error
    ALIGN
 error_code:
+   pushfl
+   andl $~0x4500, (%esp)       # NT must be clear, do a cld for free
+   popfl

I believe that NT should be automagically cleared by int.
Best regards,
Petr Vandrovec [email protected]

#1 lore raw
Quoted 6 lines · Petr Vandrovec
Quoted 3 lines

pushfl # We get a different stack layout with call
# gates, which has to be cleaned up later..
+ andl $~0x4500, (%esp) # Clear NT since we are doing an iret

this will clear 'D' and 'T' in caller after we do iret (if lcall7 returns, of course). I'm not sure that callers

You can adjust that if you want, I copied it about - clearing D is fine, in fact it may let us avoid the cld

Quoted 6 lines

Review

Quoted 4 lines

error_code:

(quoted diff) +3 -0
+   pushfl
+   andl $~0x4500, (%esp)       # NT must be clear, do a cld for free
+   popfl

I believe that NT should be automagically cleared by int.

Apparently so - you are I think 100% correct that this isnt needed

#2 lore raw
Quoted 10 lines · Alan Cox
Quoted 6 lines · Petr Vandrovec
Quoted 3 lines

pushfl # We get a different stack layout with call
# gates, which has to be cleaned up later..
+ andl $~0x4500, (%esp) # Clear NT since we are doing an iret

this will clear 'D' and 'T' in caller after we do iret (if lcall7 returns, of course). I'm not sure that callers

You can adjust that if you want, I copied it about - clearing D is fine, in fact it may let us avoid the cld

Hi,
your original code just behaved as my old code: run modprobe successfully,
and then die. Problem is that copy of eflags on stack is totally unimportant to us: current value in eflags is what matters. So this is minimal patch which works here: NT, DF and TF are now cleared only for kernel, and when we return back from lcall, userspace has its old values.

Optimization left to readed is creating SAVE_ALL_NOCLD, and using this
one in lcall7 and lcall27.

With patch below my machine survived test. Unfortunately I do not
have patched kernel with linux-abi to test whether lcall7 still works correctly.
Best regards,
Petr Vandrovec [email protected]

arch/i386/kernel/entry.S +8 -0
@@ -66,7 +66,9 @@
 OLDSS		= 0x38
 
 CF_MASK		= 0x00000001
+TF_MASK		= 0x00000100
 IF_MASK		= 0x00000200
+DF_MASK		= 0x00000400
 NT_MASK		= 0x00004000
 VM_MASK		= 0x00020000
 
@@ -132,6 +134,9 @@
 	movl CS(%esp), %edx	# this is eip..
 	movl EFLAGS(%esp), %ecx	# and this is cs..
 	movl %eax,EFLAGS(%esp)	#
+	andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+	pushl %eax
+	popfl
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
 	movl %esp, %ebx
@@ -154,6 +159,9 @@
 	movl CS(%esp), %edx	# this is eip..
 	movl EFLAGS(%esp), %ecx	# and this is cs..
 	movl %eax,EFLAGS(%esp)	#
+	andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+	pushl %eax
+	popfl
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
 	movl %esp, %ebx
#3 lore raw
Quoted 53 lines · Petr Vandrovec
Quoted 10 lines · Alan Cox
Quoted 6 lines · Petr Vandrovec
Quoted 3 lines

pushfl # We get a different stack layout with call
# gates, which has to be cleaned up later..
+ andl $~0x4500, (%esp) # Clear NT since we are doing an iret

this will clear 'D' and 'T' in caller after we do iret (if lcall7 returns, of course). I'm not sure that callers

You can adjust that if you want, I copied it about - clearing D is fine, in fact it may let us avoid the cld

Hi,
your original code just behaved as my old code: run modprobe successfully,
and then die. Problem is that copy of eflags on stack is totally unimportant to us: current value in eflags is what matters. So this is minimal patch which works here: NT, DF and TF are now cleared only for kernel, and when we return back from lcall, userspace has its old values.

Optimization left to readed is creating SAVE_ALL_NOCLD, and using this
one in lcall7 and lcall27.

With patch below my machine survived test. Unfortunately I do not
have patched kernel with linux-abi to test whether lcall7 still works correctly.
Best regards,
Petr Vandrovec [email protected]

arch/i386/kernel/entry.S +5 -0
@@ -66,7 +66,9 @@
 OLDSS		= 0x38
 
 CF_MASK		= 0x00000001
+TF_MASK		= 0x00000100
 IF_MASK		= 0x00000200
+DF_MASK		= 0x00000400
 NT_MASK		= 0x00004000
 VM_MASK		= 0x00020000
 
@@ -132,6 +134,9 @@
 	movl CS(%esp), %edx	# this is eip..
 	movl EFLAGS(%esp), %ecx	# and this is cs..
 	movl %eax,EFLAGS(%esp)	#
+	andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+	pushl %eax
+	popfl
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
 	movl %esp, %ebx

arch/i386/kernel/entry.S line 167

Quoted 9 lines
arch/i386/kernel/entry.S +3 -0
@@ -154,6 +159,9 @@
 	movl CS(%esp), %edx	# this is eip..
 	movl EFLAGS(%esp), %ecx	# and this is cs..
 	movl %eax,EFLAGS(%esp)	#
+	andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+	pushl %eax
+	popfl
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
 	movl %esp, %ebx

this is needed too in addition to the patch I posted in the other thread to avoid lcall to set NT (my patch only avoids ptrace to set NT and we need both of them to forbid nt to be set while running in kernel space).

Andrea