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