It seems that no one must have tried to use the 'setkey' command in GRUB
before today. I finally got around to starting to put together my dvorak
keymap for it[1], I found a nasty bug.

The issues is the table that GRUB uses internally to store the key
names, combined with the nature of the grub_strcmp call.

Anyway, the backtrack for a setkey command is:

,----[ grub setkey backtrace ]
| grub> setkey a o
| Program received signal SIGSEGV, Segmentation fault.
| 0x804b57a in grub_strcmp (s1=0x40178c4f "a", s2=0x0) at char_io.c:1008
| 1008          if (*s1 < *s2)
| (gdb) where
| #0  0x804b57a in grub_strcmp (s1=0x40178c4f "a", s2=0x0) at char_io.c:1008
| #1  0x80556d0 in find_ascii_code (key=0x40178c4f "a") at builtins.c:3202
| #2  0x805573c in setkey_func (arg=0x40178c4f "a", flags=1) at builtins.c:3215
| #3  0x80566c1 in enter_cmdline (heap=0x40178c48 "setkey a", forever=1)
|     at cmdline.c:168
| #4  0x80527ca in cmain () at stage2.c:907
| #5  0x804a606 in init_bios_info () at common.c:282
| #6  0x80495da in doit () at asmstub.c:120
| #7  0x80497d2 in grub_stage2 () at asmstub.c:176
| #8  0x8049596 in main (argc=1, argv=0xbffff914) at main.c:238
| #9  0x40078b8c in __libc_start_main () from /lib/libc.so.6
| (gdb) quit
`----

The issue is that the 'keysym_table' structure uses a NULL (0) value in
the table to store a 'none' item. The code in the 'setkey' function does
not take this into account and blindly passes the NULL pointer into
'grub_strcmp'.

The strcmp routine then dereferences through the NULL pointer with,
well, predictable effects. I have not verified that this bug occurs with
the boot-time GRUB, just the Unix based grub shell.

Code inspection says that the issue would be present at that time also.
The attached patch is a fairly trivial change to the effected routine to
make it test for a NULL pointer before doing the strcmp.

I don't know if this is the right fix but it certainly removes the issue
locally.

        Daniel

Footnotes: 
[1]  Would there be interest in having this contributed back to GRUB
     when I have it - or the script to turn a Linux keymap into a GRUB
     keymap?

Index: builtins.c
===================================================================
RCS file: /home/cvs/grub/stage2/builtins.c,v
retrieving revision 1.87
diff -u -u -p -r1.87 builtins.c
--- builtins.c	2000/10/07 18:09:42	1.87
+++ builtins.c	2000/10/09 12:30:40
@@ -3182,9 +3182,11 @@ setkey_func (char *arg, int flags)
 
       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
 	{
-	  if (grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
+	  if (keysym_table[i].unshifted_name &&
+	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
 	    return keysym_table[i].keycode;
-	  else if (grub_strcmp (key, keysym_table[i].shifted_name) == 0)
+	  else if (keysym_table[i].shifted_name &&
+		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
 	    return keysym_table[i].keycode;
 	}
 
@@ -3197,9 +3199,11 @@ setkey_func (char *arg, int flags)
 
       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
 	{
-	  if (grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
+	  if (keysym_table[i].unshifted_name &&
+	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
 	    return keysym_table[i].unshifted_ascii;
-	  else if (grub_strcmp (key, keysym_table[i].shifted_name) == 0)
+	  else if (keysym_table[i].shifted_name &&
+		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
 	    return keysym_table[i].shifted_ascii;
 	}
       

-- 
Organization and method mean much, but contagious human characters mean more
in a university, where a few undisciplinables ... may be infinitely more
precious than a faculty full of orderly routinists.
        -- William James

Reply via email to