aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2006-08-27 04:24:02 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-08-27 14:01:34 -0400
commit01da5fd83d6b2c5e36b77539f6cbdd8f49849225 (patch)
tree70c1f1cb8325fe4801b952346bd2ef79d08882b5
parentaf9b897ee639d96b2bd29b65b50cd0a1f2b6d6c9 (diff)
[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>
-rw-r--r--drivers/char/tty_io.c89
-rw-r--r--include/linux/tty.h1
2 files changed, 80 insertions, 10 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 2cef982585f0..bb0d9199e994 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -275,6 +275,17 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
275 * Locking: none 275 * Locking: none
276 */ 276 */
277 277
278
279/**
280 * tty_buffer_free_all - free buffers used by a tty
281 * @tty: tty to free from
282 *
283 * Remove all the buffers pending on a tty whether queued with data
284 * or in the free ring. Must be called when the tty is no longer in use
285 *
286 * Locking: none
287 */
288
278static void tty_buffer_free_all(struct tty_struct *tty) 289static void tty_buffer_free_all(struct tty_struct *tty)
279{ 290{
280 struct tty_buffer *thead; 291 struct tty_buffer *thead;
@@ -287,19 +298,47 @@ static void tty_buffer_free_all(struct tty_struct *tty)
287 kfree(thead); 298 kfree(thead);
288 } 299 }
289 tty->buf.tail = NULL; 300 tty->buf.tail = NULL;
301 tty->buf.memory_used = 0;
290} 302}
291 303
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
292static void tty_buffer_init(struct tty_struct *tty) 314static void tty_buffer_init(struct tty_struct *tty)
293{ 315{
294 spin_lock_init(&tty->buf.lock); 316 spin_lock_init(&tty->buf.lock);
295 tty->buf.head = NULL; 317 tty->buf.head = NULL;
296 tty->buf.tail = NULL; 318 tty->buf.tail = NULL;
297 tty->buf.free = NULL; 319 tty->buf.free = NULL;
320 tty->buf.memory_used = 0;
298} 321}
299 322
300static 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
335static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
301{ 336{
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);
303 if(p == NULL) 342 if(p == NULL)
304 return NULL; 343 return NULL;
305 p->used = 0; 344 p->used = 0;
@@ -309,17 +348,27 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
309 p->read = 0; 348 p->read = 0;
310 p->char_buf_ptr = (char *)(p->data); 349 p->char_buf_ptr = (char *)(p->data);
311 p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; 350 p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
312/* printk("Flip create %p\n", p); */ 351 tty->buf.memory_used += size;
313 return p; 352 return p;
314} 353}
315 354
316/* Must be called with the tty_read lock held. This needs to acquire strategy 355/**
317 code to decide if we should kfree or relink a given expired buffer */ 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 */
318 365
319static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) 366static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
320{ 367{
321 /* Dumb strategy for now - should keep some stats */ 368 /* 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
323 if(b->size >= 512) 372 if(b->size >= 512)
324 kfree(b); 373 kfree(b);
325 else { 374 else {
@@ -328,6 +377,18 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
328 } 377 }
329} 378}
330 379
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
331static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) 392static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
332{ 393{
333 struct tty_buffer **tbh = &tty->buf.free; 394 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)
339 t->used = 0; 400 t->used = 0;
340 t->commit = 0; 401 t->commit = 0;
341 t->read = 0; 402 t->read = 0;
342 /* DEBUG ONLY */ 403 tty->buf.memory_used += t->size;
343/* memset(t->data, '*', size); */
344/* printk("Flip recycle %p\n", t); */
345 return t; 404 return t;
346 } 405 }
347 tbh = &((*tbh)->next); 406 tbh = &((*tbh)->next);
348 } 407 }
349 /* Round the buffer size out */ 408 /* Round the buffer size out */
350 size = (size + 0xFF) & ~ 0xFF; 409 size = (size + 0xFF) & ~ 0xFF;
351 return tty_buffer_alloc(size); 410 return tty_buffer_alloc(tty, size);
352 /* Should possibly check if this fails for the largest buffer we 411 /* Should possibly check if this fails for the largest buffer we
353 have queued and recycle that ? */ 412 have queued and recycle that ? */
354} 413}
355 414
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 */
356int tty_buffer_request_room(struct tty_struct *tty, size_t size) 425int tty_buffer_request_room(struct tty_struct *tty, size_t size)
357{ 426{
358 struct tty_buffer *b, *n; 427 struct tty_buffer *b, *n;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index e421d5e34818..04827ca65781 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -59,6 +59,7 @@ struct tty_bufhead {
59 struct tty_buffer *head; /* Queue head */ 59 struct tty_buffer *head; /* Queue head */
60 struct tty_buffer *tail; /* Active buffer */ 60 struct tty_buffer *tail; /* Active buffer */
61 struct tty_buffer *free; /* Free queue head */ 61 struct tty_buffer *free; /* Free queue head */
62 int memory_used; /* Buffer space used excluding free queue */
62}; 63};
63/* 64/*
64 * The pty uses char_buf and flag_buf as a contiguous buffer 65 * The pty uses char_buf and flag_buf as a contiguous buffer