Skip to content

Commit 01da5fd

Browse files
Alan-CoxLinus Torvalds
authored andcommitted
[PATCH] Fix tty layer DoS and comment relevant code
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>
1 parent af9b897 commit 01da5fd

File tree

2 files changed

+80
-10
lines changed

2 files changed

+80
-10
lines changed

drivers/char/tty_io.c

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,17 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
265265
*/
266266

267267

268+
/**
269+
* tty_buffer_free_all - free buffers used by a tty
270+
* @tty: tty to free from
271+
*
272+
* Remove all the buffers pending on a tty whether queued with data
273+
* or in the free ring. Must be called when the tty is no longer in use
274+
*
275+
* Locking: none
276+
*/
277+
278+
268279
/**
269280
* tty_buffer_free_all - free buffers used by a tty
270281
* @tty: tty to free from
@@ -287,19 +298,47 @@ static void tty_buffer_free_all(struct tty_struct *tty)
287298
kfree(thead);
288299
}
289300
tty->buf.tail = NULL;
301+
tty->buf.memory_used = 0;
290302
}
291303

304+
/**
305+
* tty_buffer_init - prepare a tty buffer structure
306+
* @tty: tty to initialise
307+
*
308+
* Set up the initial state of the buffer management for a tty device.
309+
* Must be called before the other tty buffer functions are used.
310+
*
311+
* Locking: none
312+
*/
313+
292314
static void tty_buffer_init(struct tty_struct *tty)
293315
{
294316
spin_lock_init(&tty->buf.lock);
295317
tty->buf.head = NULL;
296318
tty->buf.tail = NULL;
297319
tty->buf.free = NULL;
320+
tty->buf.memory_used = 0;
298321
}
299322

300-
static struct tty_buffer *tty_buffer_alloc(size_t size)
323+
/**
324+
* tty_buffer_alloc - allocate a tty buffer
325+
* @tty: tty device
326+
* @size: desired size (characters)
327+
*
328+
* Allocate a new tty buffer to hold the desired number of characters.
329+
* Return NULL if out of memory or the allocation would exceed the
330+
* per device queue
331+
*
332+
* Locking: Caller must hold tty->buf.lock
333+
*/
334+
335+
static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
301336
{
302-
struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
337+
struct tty_buffer *p;
338+
339+
if (tty->buf.memory_used + size > 65536)
340+
return NULL;
341+
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
303342
if(p == NULL)
304343
return NULL;
305344
p->used = 0;
@@ -309,17 +348,27 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
309348
p->read = 0;
310349
p->char_buf_ptr = (char *)(p->data);
311350
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
312-
/* printk("Flip create %p\n", p); */
351+
tty->buf.memory_used += size;
313352
return p;
314353
}
315354

316-
/* Must be called with the tty_read lock held. This needs to acquire strategy
317-
code to decide if we should kfree or relink a given expired buffer */
355+
/**
356+
* tty_buffer_free - free a tty buffer
357+
* @tty: tty owning the buffer
358+
* @b: the buffer to free
359+
*
360+
* Free a tty buffer, or add it to the free list according to our
361+
* internal strategy
362+
*
363+
* Locking: Caller must hold tty->buf.lock
364+
*/
318365

319366
static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
320367
{
321368
/* Dumb strategy for now - should keep some stats */
322-
/* printk("Flip dispose %p\n", b); */
369+
tty->buf.memory_used -= b->size;
370+
WARN_ON(tty->buf.memory_used < 0);
371+
323372
if(b->size >= 512)
324373
kfree(b);
325374
else {
@@ -328,6 +377,18 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
328377
}
329378
}
330379

380+
/**
381+
* tty_buffer_find - find a free tty buffer
382+
* @tty: tty owning the buffer
383+
* @size: characters wanted
384+
*
385+
* Locate an existing suitable tty buffer or if we are lacking one then
386+
* allocate a new one. We round our buffers off in 256 character chunks
387+
* to get better allocation behaviour.
388+
*
389+
* Locking: Caller must hold tty->buf.lock
390+
*/
391+
331392
static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
332393
{
333394
struct tty_buffer **tbh = &tty->buf.free;
@@ -339,20 +400,28 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
339400
t->used = 0;
340401
t->commit = 0;
341402
t->read = 0;
342-
/* DEBUG ONLY */
343-
/* memset(t->data, '*', size); */
344-
/* printk("Flip recycle %p\n", t); */
403+
tty->buf.memory_used += t->size;
345404
return t;
346405
}
347406
tbh = &((*tbh)->next);
348407
}
349408
/* Round the buffer size out */
350409
size = (size + 0xFF) & ~ 0xFF;
351-
return tty_buffer_alloc(size);
410+
return tty_buffer_alloc(tty, size);
352411
/* Should possibly check if this fails for the largest buffer we
353412
have queued and recycle that ? */
354413
}
355414

415+
/**
416+
* tty_buffer_request_room - grow tty buffer if needed
417+
* @tty: tty structure
418+
* @size: size desired
419+
*
420+
* Make at least size bytes of linear space available for the tty
421+
* buffer. If we fail return the size we managed to find.
422+
*
423+
* Locking: Takes tty->buf.lock
424+
*/
356425
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
357426
{
358427
struct tty_buffer *b, *n;

include/linux/tty.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ struct tty_bufhead {
5959
struct tty_buffer *head; /* Queue head */
6060
struct tty_buffer *tail; /* Active buffer */
6161
struct tty_buffer *free; /* Free queue head */
62+
int memory_used; /* Buffer space used excluding free queue */
6263
};
6364
/*
6465
* The pty uses char_buf and flag_buf as a contiguous buffer

0 commit comments

Comments
 (0)