summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdike <jdike>2003-11-10 22:59:33 +0000
committerjdike <jdike>2003-11-10 22:59:33 +0000
commitbd6d2dc353665c0a5abeaf5f1597fd83b4b7fff6 (patch)
tree0fac43a5ee3c0934654b667b3b8c2687ce909a7f
parentfb9eb1d2d7a3dc2de0b48ee0fd6787b07796fe78 (diff)
downloaduml-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.c81
-rw-r--r--arch/um/include/line.h3
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);