lkml.org 
[lkml]   [1998]   [May]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectminor patch for 2.1.103 drivers/char/selection.c
The attached patch fixes a couple of race conditions in selection.c. The
buffer for the selection was being freed first, then kmalloc'ed, leaving
a stale reference to th old buffer if the kmalloc blocked. This is fixed
by allocating the new buffer first.

In the paste code the buffer reference and length were being carried
across a schedule() call if the tty was throttled. I've fixed this by
refreshing the buffer and length reference for eash iteration.

Probably the only bad thing that could happen with these problems would
be a few garbage characters on the screen, but it seems like we should
fix it anyway.

Regards,
Bill--- linux-2.1.103/drivers/char/selection.c.old Sat Feb 21 09:24:53 1998
+++ linux-2.1.103/drivers/char/selection.c Wed May 27 17:59:00 1998
@@ -91,12 +91,11 @@
/* set inwordLut contents. Invoked by ioctl(). */
int sel_loadlut(const unsigned long arg)
{
- int err;
+ int err = -EFAULT;

- err = copy_from_user(inwordLut, (u32 *)(arg+4), 32);
- if (err)
- return -EFAULT;
- return 0;
+ if (!copy_from_user(inwordLut, (u32 *)(arg+4), 32))
+ err = 0;
+ return err;
}

/* does screen address p correspond to character at LH/RH edge of screen? */
@@ -226,7 +225,7 @@

/* select to end of line if on trailing space */
if (new_sel_end > new_sel_start &&
- !atedge(new_sel_end, size_row) && isspace(sel_pos(new_sel_end))) {
+ !atedge(new_sel_end, size_row) && isspace(sel_pos(new_sel_end))) {
for (pe = new_sel_end + 2; ; pe += 2)
if (!isspace(sel_pos(pe)) || atedge(pe, size_row))
break;
@@ -259,16 +258,18 @@
sel_start = new_sel_start;
sel_end = new_sel_end;

- if (sel_buffer)
- kfree(sel_buffer);
- sel_buffer = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
- if (!sel_buffer) {
- printk("selection: kmalloc() failed\n");
+ /* Allocate a new buffer before freeing the old one ... */
+ bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
+ if (!bp) {
+ printk(KERN_WARNING "selection: kmalloc() failed\n");
clear_selection();
return -ENOMEM;
}
+ if (sel_buffer)
+ kfree(sel_buffer);
+ sel_buffer = bp;

- obp = bp = sel_buffer;
+ obp = bp;
for (i = sel_start; i <= sel_end; i += 2) {
*bp = sel_pos(i);
if (!isspace(*bp++))
@@ -287,31 +288,29 @@
return 0;
}

-/* Insert the contents of the selection buffer into the queue of the
- tty associated with the current console. Invoked by ioctl(). */
+/* Insert the contents of the selection buffer into the
+ * queue of the tty associated with the current console.
+ * Invoked by ioctl().
+ */
int paste_selection(struct tty_struct *tty)
{
- struct wait_queue wait = { current, NULL };
- char *bp = sel_buffer;
- int c = sel_buffer_lth;
- int l;
struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
+ int pasted = 0, count;
+ struct wait_queue wait = { current, NULL };

- if (!bp || !c)
- return 0;
poke_blanked_console();
add_wait_queue(&vt->paste_wait, &wait);
- do {
+ while (sel_buffer && sel_buffer_lth > pasted) {
current->state = TASK_INTERRUPTIBLE;
if (test_bit(TTY_THROTTLED, &tty->flags)) {
schedule();
continue;
}
- l = MIN(c, tty->ldisc.receive_room(tty));
- tty->ldisc.receive_buf(tty, bp, 0, l);
- c -= l;
- bp += l;
- } while (c);
+ count = sel_buffer_lth - pasted;
+ count = MIN(count, tty->ldisc.receive_room(tty));
+ tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count);
+ pasted += count;
+ }
remove_wait_queue(&vt->paste_wait, &wait);
current->state = TASK_RUNNING;
return 0;
\
 
 \ /
  Last update: 2005-03-22 13:42    [W:0.032 / U:0.984 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site