summaryrefslogtreecommitdiff
path: root/buffer.c
diff options
context:
space:
mode:
authordjm <djm>2006-04-23 02:06:03 +0000
committerdjm <djm>2006-04-23 02:06:03 +0000
commit77599c1e373f8f16622cf64c61eeecfdd0fd8bd3 (patch)
tree77a0bedbe0f30e5571a95b31ef97f23cdc79d27d /buffer.c
parentb38fe98626fe196d9e4129962755559fc01bda4b (diff)
downloadopenssh-77599c1e373f8f16622cf64c61eeecfdd0fd8bd3.tar.gz
- djm@cvs.openbsd.org 2006/04/16 00:48:52
[buffer.c buffer.h channels.c] Fix condition where we could exit with a fatal error when an input buffer became too large and the remote end had advertised a big window. The problem was a mismatch in the backoff math between the channels code and the buffer code, so make a buffer_check_alloc() function that the channels code can use to propsectivly check whether an incremental allocation will succeed. bz #1131, debugged with the assistance of cove AT wildpackets.com; ok dtucker@ deraadt@
Diffstat (limited to 'buffer.c')
-rw-r--r--buffer.c61
1 files changed, 48 insertions, 13 deletions
diff --git a/buffer.c b/buffer.c
index de404e60..ba718daf 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: buffer.c,v 1.26 2006/03/25 13:17:01 djm Exp $ */
+/* $OpenBSD: buffer.c,v 1.27 2006/04/16 00:48:52 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -18,6 +18,10 @@
#include "buffer.h"
#include "log.h"
+#define BUFFER_MAX_CHUNK 0x100000
+#define BUFFER_MAX_LEN 0xa00000
+#define BUFFER_ALLOCSZ 0x008000
+
/* Initializes the buffer structure. */
void
@@ -66,6 +70,23 @@ buffer_append(Buffer *buffer, const void *data, u_int len)
memcpy(p, data, len);
}
+static int
+buffer_compact(Buffer *buffer)
+{
+ /*
+ * If the buffer is quite empty, but all data is at the end, move the
+ * data to the beginning.
+ */
+ if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
+ memmove(buffer->buf, buffer->buf + buffer->offset,
+ buffer->end - buffer->offset);
+ buffer->end -= buffer->offset;
+ buffer->offset = 0;
+ return (1);
+ }
+ return (0);
+}
+
/*
* Appends space to the buffer, expanding the buffer if necessary. This does
* not actually copy the data into the buffer, but instead returns a pointer
@@ -93,20 +114,13 @@ restart:
buffer->end += len;
return p;
}
- /*
- * If the buffer is quite empty, but all data is at the end, move the
- * data to the beginning and retry.
- */
- if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
- memmove(buffer->buf, buffer->buf + buffer->offset,
- buffer->end - buffer->offset);
- buffer->end -= buffer->offset;
- buffer->offset = 0;
+
+ /* Compact data back to the start of the buffer if necessary */
+ if (buffer_compact(buffer))
goto restart;
- }
- /* Increase the size of the buffer and retry. */
- newlen = buffer->alloc + len + 32768;
+ /* Increase the size of the buffer and retry. */
+ newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ);
if (newlen > BUFFER_MAX_LEN)
fatal("buffer_append_space: alloc %u not supported",
newlen);
@@ -116,6 +130,27 @@ restart:
/* NOTREACHED */
}
+/*
+ * Check whether an allocation of 'len' will fit in the buffer
+ * This must follow the same math as buffer_append_space
+ */
+int
+buffer_check_alloc(Buffer *buffer, u_int len)
+{
+ if (buffer->offset == buffer->end) {
+ buffer->offset = 0;
+ buffer->end = 0;
+ }
+ restart:
+ if (buffer->end + len < buffer->alloc)
+ return (1);
+ if (buffer_compact(buffer))
+ goto restart;
+ if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN)
+ return (1);
+ return (0);
+}
+
/* Returns the number of bytes of data in the buffer. */
u_int