diff options
author | jdike <jdike> | 2003-11-10 22:59:33 +0000 |
---|---|---|
committer | jdike <jdike> | 2003-11-10 22:59:33 +0000 |
commit | bd6d2dc353665c0a5abeaf5f1597fd83b4b7fff6 (patch) | |
tree | 0fac43a5ee3c0934654b667b3b8c2687ce909a7f | |
parent | fb9eb1d2d7a3dc2de0b48ee0fd6787b07796fe78 (diff) | |
download | uml-history-bd6d2dc353665c0a5abeaf5f1597fd83b4b7fff6.tar.gz |
Fixed a buffer overrun.
Made some things static since they didn't need to be global.
-rw-r--r-- | arch/um/drivers/line.c | 81 | ||||
-rw-r--r-- | arch/um/include/line.h | 3 |
2 files changed, 49 insertions, 35 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 6215013..2524fa4 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -20,7 +20,7 @@ #define LINE_BUFSIZE 4096 -void line_interrupt(int irq, void *data, struct pt_regs *unused) +static void line_interrupt(int irq, void *data, struct pt_regs *unused) { struct line *dev = data; @@ -29,26 +29,41 @@ void line_interrupt(int irq, void *data, struct pt_regs *unused) dev); } -void line_timer_cb(void *arg) +static void line_timer_cb(void *arg) { struct line *dev = arg; line_interrupt(dev->driver->read_irq, dev, NULL); } -static void buffer_data(struct line *line, const char *buf, int len) +static int write_room(struct line *dev) { - int end; + int n; + + if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); + + n = dev->head - dev->tail; + if(n <= 0) n = LINE_BUFSIZE + n; + return(n - 1); +} + +static int buffer_data(struct line *line, const char *buf, int len) +{ + int end, room; if(line->buffer == NULL){ line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); if(line->buffer == NULL){ printk("buffer_data - atomic allocation failed\n"); - return; + return(0); } line->head = line->buffer; line->tail = line->buffer; } + + room = write_room(line); + len = (len > room) ? room : len; + end = line->buffer + LINE_BUFSIZE - line->tail; if(len < end){ memcpy(line->tail, buf, len); @@ -61,6 +76,8 @@ static void buffer_data(struct line *line, const char *buf, int len) memcpy(line->buffer, buf, len); line->tail = line->buffer + len; } + + return(len); } static int flush_buffer(struct line *line) @@ -96,7 +113,7 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, struct line *line; char *new; unsigned long flags; - int n, err, i; + int n, err, i, ret = 0; if(tty->stopped) return 0; @@ -105,11 +122,13 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, if(new == NULL) return(0); n = copy_from_user(new, buf, len); + buf = new; if(n == len){ len = -EFAULT; goto out_free; } - buf = new; + + len -= n; } i = minor(tty->device) - tty->driver.minor_start; @@ -118,7 +137,7 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, down(&line->sem); if(line->head != line->tail){ local_irq_save(flags); - buffer_data(line, buf, len); + ret += buffer_data(line, buf, len); err = flush_buffer(line); local_irq_restore(flags); if(err <= 0) @@ -128,11 +147,14 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, n = write_chan(&line->chan_list, buf, len, line->driver->write_irq); if(n < 0){ - len = n; + ret = n; goto out_up; } - if(n < len) - buffer_data(line, buf + n, len - n); + + len -= n; + ret += n; + if(len > 0) + ret += buffer_data(line, buf + n, len); } out_up: up(&line->sem); @@ -140,10 +162,10 @@ int line_write(struct line *lines, struct tty_struct *tty, int from_user, out_free: if(from_user) kfree(buf); - return(len); + return(ret); } -void line_write_interrupt(int irq, void *data, struct pt_regs *unused) +static void line_write_interrupt(int irq, void *data, struct pt_regs *unused) { struct line *dev = data; struct tty_struct *tty = dev->tty; @@ -173,18 +195,6 @@ void line_write_interrupt(int irq, void *data, struct pt_regs *unused) } -int line_write_room(struct tty_struct *tty) -{ - struct line *dev = tty->driver_data; - int n; - - if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); - - n = dev->head - dev->tail; - if(n <= 0) n = LINE_BUFSIZE + n; - return(n - 1); -} - int line_setup_irq(int fd, int input, int output, void *data) { struct line *line = data; @@ -312,7 +322,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) if(*end != '='){ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", init); - return(1); + return(0); } init = end; } @@ -320,12 +330,12 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) if((n >= 0) && (n >= num)){ printk("line_setup - %d out of range ((0 ... %d) allowed)\n", n, num); - return(1); + return(0); } else if(n >= 0){ if(lines[n].count > 0){ printk("line_setup - device %d is open\n", n); - return(1); + return(0); } if(lines[n].init_pri <= INIT_ONE){ lines[n].init_pri = INIT_ONE; @@ -339,7 +349,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) else if(!all_allowed){ printk("line_setup - can't configure all devices from " "mconsole\n"); - return(1); + return(0); } else { for(i = 0; i < num; i++){ @@ -353,7 +363,7 @@ int line_setup(struct line *lines, int num, char *init, int all_allowed) } } } - return(0); + return(1); } int line_config(struct line *lines, int num, char *str) @@ -364,7 +374,7 @@ int line_config(struct line *lines, int num, char *str) printk("line_config - uml_strdup failed\n"); return(-ENOMEM); } - return(line_setup(lines, num, new, 0)); + return(!line_setup(lines, num, new, 0)); } int line_get_config(char *name, struct line *lines, int num, char *str, @@ -403,7 +413,14 @@ int line_remove(struct line *lines, int num, char *str) char config[sizeof("conxxxx=none\0")]; sprintf(config, "%s=none", str); - return(line_setup(lines, num, config, 0)); + return(!line_setup(lines, num, config, 0)); +} + +static int line_write_room(struct tty_struct *tty) +{ + struct line *dev = tty->driver_data; + + return(write_room(dev)); } void line_register_devfs(struct lines *set, struct line_driver *line_driver, diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 0538f63..e148fb8 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -67,8 +67,6 @@ struct lines { #define LINES_INIT(n) { num : n } -extern void line_interrupt(int irq, void *data, struct pt_regs *unused); -extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused); extern void line_close(struct line *lines, struct tty_struct *tty); extern int line_open(struct line *lines, struct tty_struct *tty, struct chan_opts *opts); @@ -76,7 +74,6 @@ extern int line_setup(struct line *lines, int num, char *init, int all_allowed); extern int line_write(struct line *line, struct tty_struct *tty, int from_user, const char *buf, int len); -extern int line_write_room(struct tty_struct *tty); extern char *add_xterm_umid(char *base); extern int line_setup_irq(int fd, int input, int output, void *data); extern void line_close_chan(struct line *line); |