minor patch for 2.1.103 drivers/char/selection.c

Bill Hawes (whawes@star.net)
Thu, 28 May 1998 07:32:29 -0400


This is a multi-part message in MIME format.
--------------260ED74298EBAD72173A2BC5
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

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
--------------260ED74298EBAD72173A2BC5
Content-Type: text/plain; charset=us-ascii; name="char_select103-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="char_select103-patch"

--- 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;

--------------260ED74298EBAD72173A2BC5--

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