lkml.org 
[lkml]   [1998]   [May]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
SubjectRe: 2.1.103: Still "Ugh at c0111691"
From
Date
deas@uni-hamburg.de (Andreas Steffan) writes:

> Ok, here it is - all in one:
>
> Using `/System.map' to map addresses to symbols.
>
> May 28 19:02:12 mortimer kernel: Ugh at c0111b34
> May 28 19:02:12 mortimer kernel: Ugh: process mgetty touched user space while interrupts disabled
> >>EIP: c0111b48 <do_page_fault+80/3cc>
> Trace: c0111b48 <do_page_fault+80/3cc>
> Trace: c01a8c7d <bad_pmd_string+1a1/320>
> Trace: c0111b34 <do_page_fault+6c/3cc>
> Trace: c014154b <inode_getblk+47/1b8>
> Trace: c010a060 <error_code+30/40>
> Trace: c01a3a6d <__get_user_1+d/14>
> Trace: c48222c2
> Trace: c481ea11
> Trace: c0177562 <write_chan+17e/224>
> Trace: c01732f9 <tty_write+115/164>
> Trace: c0177562 <write_chan+17e/224>
> Trace: c01298ad <sys_write+131/1b0>
> Trace: c01732f9 <tty_write+115/164>
> Trace: c0109ee8 <system_call+38/40>
>
> Hope this helps. Please let me know, if you need more.
>
> -- Andreas

If I understand the output right, the sequence is:
system_call -> sys_write -> write_chan -> tty_write ->
write_chan -> ?? -> ?? -> __get_user (page fault) ->
do_pagefault.
The last two seems to be bogus output generated by generate_ugh_trace.
I'm not sure about inode_get_block and the first tty_write, but the
interesting points seem to be the two module addresses between
write_chan and __get_user. Can you load your modules with the '-m'
option to generate a load map that allows to map addresses to symbols
(or compile your kernel without using modules)?

Or is there an easier way to do that (especially after the trace is
generated)?

...

My guess is that the responsible module is the isdn module (Maybe you
can verify this using the maps generated by insmod -m or by compiling
the isdn stuff into the kernel). If you look at
/drivers/char/isdn/isdn_tty.c you can read:

cli();
while (1) {
...
if (from_user)
copy_from_user(&(info->xmit_buf[info->xmit_count
...
restore_flags(flags);
Somehow I thought this was fixed in a current version of the ISDN
subsystem, but either it wasn't or the fixes are not in the current
kernel.

Another place where such bug still exists is drivers/char/esp.c. All
character drivers seem to use the same scheme to implement its
.*_write functions. They usually disable interrupts, copy data from or
to user space and enable interrupts again. There is a great chance
that all drivers are raising pagefaults(Ugh).
I haven't looked at all drivers but here are some examples:

***********
esp.c:
static int rs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
save_flags(flags);
while (1) {
cli();
if (from_user) {
c -= copy_from_user(tmp_buf, buf, c);
restore_flags(flags);
}
}
***********
istallion.c
static int stli_write(struct tty_struct *tty, int from_user, const unsigned char
*buf, int count)
{
if (from_user) {
save_flags(flags);
cli();
copy_from_user(stli_tmpwritebuf, chbuf, count);
restore_flags(flags);
}
}
static ssize_t stli_memwrite(struct file *fp, const char *buf, size_t count, lof
f_t *offp)
{
cli();
EBRDENABLE(brdp);
while (size > 0) {
copy_from_user(memptr, chbuf, n);
}
EBRDDISABLE(brdp);
restore_flags(flags);
}
***********
cyclade.c
static int
cy_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
save_flags(flags);
while (1) {
cli();
if (from_user) {
copy_from_user(tmp_buf, buf, c);
restore_flags(flags);
} /* cy_write */
***********
epca.c
static int pc_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int bytesAvailable)
{ /* Begin pc_write */
if (from_user)
{ /* Begin from_user */
save_flags(flags);
cli();
copy_from_user(ch->tmp_buf, buf, bytesAvailable)
restore_flags(flags);

} /* End from_user */
}
***********
pcxx.c
static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned cha
r *buf, int count)
{
if (from_user) {
save_flags(flags);
cli();
if (count) {
if (verify_area(VERIFY_READ, (char*)buf, count))
count=0;
else copy_from_user(ch->tmp_buf, buf, count);
}
restore_flags(flags);
}
}
Other files (riscom8.c, rocket.c, specialix.c, stallion.c) are
following the same scheme. Maybe all drivers should be fixed using the
model of serial.c. It had the same bug in some previous version and
seems to be correct now.

Some of the isdn files have the same problem:

**************
isdn_common.c
static int
isdn_set_allcfg(char *src)
{
save_flags(flags);
cli();
src += sizeof(int);
while (i) {
if ((ret = copy_from_user((char *) &cfg, src, sizeof(cfg)))) {
restore_flags(flags);
return ret;
}
restore_flags(flags);
}
static int
isdn_get_allcfg(char *dest)
the same
***************
Unfortunatly I won't be able to fix these problems but I hope I have
provided enough hints for the driver maintainers, so that they can fix
it (maybe they have already done that).

Jean

--
I get up each morning, gather my wits.
Pick up the paper, read the obits.
if I'm not there I know I'm not dead.
So I eat a good breakfast and go back to bed. Peete Seeger

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu

\
 
 \ /
  Last update: 2005-03-22 13:42    [from the cache]
©2003-2014 Jasper Spaans. Advertise on this site