lkml.org 
[lkml]   [1997]   [Feb]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectPATCH, FIX for: Reliable OOPS'es on 2.0.28/2.1.25 after modify_ldt
Hi Linus, Alan,

The below two patches fix a problem in ldt.c, that was reported by
Ion Badulescu <ionut@moisil.wal.rhno.columbia.edu> and was traced down
by Ramon <ramon@atlante.ieeesb.etsit.upm.es>:

Ramon <ramon@atlante.ieeesb.etsit.upm.es> wrote:
>
> Wine tells the operating system to free a selector that is being used
> in the %fs register. The kernel does it, but when trying to restore
> the registers to return from the system call, the processor generates
> a expection since it does not like place an unused selector in the
> %fs register.
>

Well, of course Wine could fix the problem, but the kernel shouldn't oops
anyway. The below patches were tested by Ion Badulescu and Wine seems
happy with the -EBUSY.

The 2.1.x patch also is needed, because (though the kernel doesn't use
%fs/%gs) the oops may happen on schedule.

Hans
<lermen@fgan.de>

-------------------------------FOR 2.0.x !!! ----------------------------
--- linux-2.0.28/arch/i386/kernel/ldt.c Tue Jan 14 21:08:40 1997
+++ linux/arch/i386/kernel/ldt.c Sun Feb 9 14:28:50 1997
@@ -11,6 +11,7 @@
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/ldt.h>
+#include <asm/ptrace.h>

static int read_ldt(void * ptr, unsigned long bytecount)
{
@@ -59,7 +60,7 @@
return (last >= first && last < TASK_SIZE);
}

-static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
+static int write_ldt(struct pt_regs * regs, void * ptr, unsigned long bytecount, int oldmode)
{
struct modify_ldt_ldt_s ldt_info;
unsigned long *lp;
@@ -101,6 +102,9 @@
&& ldt_info.limit_in_pages == 0
&& ldt_info.seg_not_present == 1
&& ldt_info.useable == 0 )) ) {
+ unsigned short sel =(ldt_info.entry_number <<3) | 7;
+ if (regs->fs == sel || regs->gs == sel)
+ return -EBUSY;
*lp = 0;
*(lp+1) = 0;
return 0;
@@ -125,8 +129,8 @@
if (func == 0)
return read_ldt(ptr, bytecount);
if (func == 1)
- return write_ldt(ptr, bytecount, 1);
+ return write_ldt((struct pt_regs *) &func, ptr, bytecount, 1);
if (func == 0x11)
- return write_ldt(ptr, bytecount, 0);
+ return write_ldt((struct pt_regs *) &func, ptr, bytecount, 0);
return -ENOSYS;
}
-------------------------------------------------------------------------
-------------------------------FOR 2.1.x !!! ----------------------------
--- linux-2.1.25/arch/i386/kernel/ldt.c Fri Jan 31 10:34:54 1997
+++ linux/arch/i386/kernel/ldt.c Fri Feb 7 12:29:40 1997
@@ -60,6 +60,7 @@

static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
{
+#define SEGREG(x) ({ unsigned short ret;__asm__("movw %%" #x ",%0": "=r" (ret)); ret;})
struct modify_ldt_ldt_s ldt_info;
unsigned long *lp;
int error, i;
@@ -98,6 +99,9 @@
&& ldt_info.limit_in_pages == 0
&& ldt_info.seg_not_present == 1
&& ldt_info.useable == 0 )) ) {
+ unsigned short seg = (ldt_info.entry_number << 3) | 7;
+ if (SEGREG(fs) == seg || SEGREG(gs) == seg)
+ return -EBUSY;
*lp = 0;
*(lp+1) = 0;
return 0;
-------------------------------------------------------------------------


\
 
 \ /
  Last update: 2005-03-22 13:38    [W:0.024 / U:0.216 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site