Skip to content

Commit

Permalink
[PATCH] Fix tty layer DoS and comment relevant code
Browse files Browse the repository at this point in the history
Unlike the other tty comment patch this one has code changes.  Specifically
it limits the queue size for a tty to 64K characters (128Kbytes) worst case
even if the tty is ignoring tty->throttle.  This is because certain drivers
don't honour the throttle value correctly, although it is a useful
safeguard anyway.

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Alan-Cox authored and Linus Torvalds committed Aug 27, 2006
1 parent af9b897 commit 01da5fd
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 10 deletions.
89 changes: 79 additions & 10 deletions drivers/char/tty_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,17 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
*/


/**
* tty_buffer_free_all - free buffers used by a tty
* @tty: tty to free from
*
* Remove all the buffers pending on a tty whether queued with data
* or in the free ring. Must be called when the tty is no longer in use
*
* Locking: none
*/


/**
* tty_buffer_free_all - free buffers used by a tty
* @tty: tty to free from
Expand All @@ -287,19 +298,47 @@ static void tty_buffer_free_all(struct tty_struct *tty)
kfree(thead);
}
tty->buf.tail = NULL;
tty->buf.memory_used = 0;
}

/**
* tty_buffer_init - prepare a tty buffer structure
* @tty: tty to initialise
*
* Set up the initial state of the buffer management for a tty device.
* Must be called before the other tty buffer functions are used.
*
* Locking: none
*/

static void tty_buffer_init(struct tty_struct *tty)
{
spin_lock_init(&tty->buf.lock);
tty->buf.head = NULL;
tty->buf.tail = NULL;
tty->buf.free = NULL;
tty->buf.memory_used = 0;
}

static struct tty_buffer *tty_buffer_alloc(size_t size)
/**
* tty_buffer_alloc - allocate a tty buffer
* @tty: tty device
* @size: desired size (characters)
*
* Allocate a new tty buffer to hold the desired number of characters.
* Return NULL if out of memory or the allocation would exceed the
* per device queue
*
* Locking: Caller must hold tty->buf.lock
*/

static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
{
struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
struct tty_buffer *p;

if (tty->buf.memory_used + size > 65536)
return NULL;
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
if(p == NULL)
return NULL;
p->used = 0;
Expand All @@ -309,17 +348,27 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
p->read = 0;
p->char_buf_ptr = (char *)(p->data);
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
/* printk("Flip create %p\n", p); */
tty->buf.memory_used += size;
return p;
}

/* Must be called with the tty_read lock held. This needs to acquire strategy
code to decide if we should kfree or relink a given expired buffer */
/**
* tty_buffer_free - free a tty buffer
* @tty: tty owning the buffer
* @b: the buffer to free
*
* Free a tty buffer, or add it to the free list according to our
* internal strategy
*
* Locking: Caller must hold tty->buf.lock
*/

static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
{
/* Dumb strategy for now - should keep some stats */
/* printk("Flip dispose %p\n", b); */
tty->buf.memory_used -= b->size;
WARN_ON(tty->buf.memory_used < 0);

if(b->size >= 512)
kfree(b);
else {
Expand All @@ -328,6 +377,18 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
}
}

/**
* tty_buffer_find - find a free tty buffer
* @tty: tty owning the buffer
* @size: characters wanted
*
* Locate an existing suitable tty buffer or if we are lacking one then
* allocate a new one. We round our buffers off in 256 character chunks
* to get better allocation behaviour.
*
* Locking: Caller must hold tty->buf.lock
*/

static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
{
struct tty_buffer **tbh = &tty->buf.free;
Expand All @@ -339,20 +400,28 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
t->used = 0;
t->commit = 0;
t->read = 0;
/* DEBUG ONLY */
/* memset(t->data, '*', size); */
/* printk("Flip recycle %p\n", t); */
tty->buf.memory_used += t->size;
return t;
}
tbh = &((*tbh)->next);
}
/* Round the buffer size out */
size = (size + 0xFF) & ~ 0xFF;
return tty_buffer_alloc(size);
return tty_buffer_alloc(tty, size);
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}

/**
* tty_buffer_request_room - grow tty buffer if needed
* @tty: tty structure
* @size: size desired
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
*
* Locking: Takes tty->buf.lock
*/
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
struct tty_buffer *b, *n;
Expand Down
1 change: 1 addition & 0 deletions include/linux/tty.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct tty_bufhead {
struct tty_buffer *head; /* Queue head */
struct tty_buffer *tail; /* Active buffer */
struct tty_buffer *free; /* Free queue head */
int memory_used; /* Buffer space used excluding free queue */
};
/*
* The pty uses char_buf and flag_buf as a contiguous buffer
Expand Down

0 comments on commit 01da5fd

Please sign in to comment.