|
|
ceb09b |
diff --git a/server/protocol.c b/server/protocol.c
|
|
|
ceb09b |
index 9e23325..8428129 100644
|
|
|
ceb09b |
--- a/server/protocol.c
|
|
|
ceb09b |
+++ b/server/protocol.c
|
|
|
ceb09b |
@@ -222,6 +222,12 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
int fold = flags & AP_GETLINE_FOLD;
|
|
|
ceb09b |
int crlf = flags & AP_GETLINE_CRLF;
|
|
|
ceb09b |
|
|
|
ceb09b |
+ if (!n) {
|
|
|
ceb09b |
+ /* Needs room for NUL byte at least */
|
|
|
ceb09b |
+ *read = 0;
|
|
|
ceb09b |
+ return APR_BADARG;
|
|
|
ceb09b |
+ }
|
|
|
ceb09b |
+
|
|
|
ceb09b |
/*
|
|
|
ceb09b |
* Initialize last_char as otherwise a random value will be compared
|
|
|
ceb09b |
* against APR_ASCII_LF at the end of the loop if bb only contains
|
|
|
ceb09b |
@@ -235,14 +241,15 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_GETLINE,
|
|
|
ceb09b |
APR_BLOCK_READ, 0);
|
|
|
ceb09b |
if (rv != APR_SUCCESS) {
|
|
|
ceb09b |
- return rv;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
/* Something horribly wrong happened. Someone didn't block!
|
|
|
ceb09b |
* (this also happens at the end of each keepalive connection)
|
|
|
ceb09b |
*/
|
|
|
ceb09b |
if (APR_BRIGADE_EMPTY(bb)) {
|
|
|
ceb09b |
- return APR_EGENERAL;
|
|
|
ceb09b |
+ rv = APR_EGENERAL;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
for (e = APR_BRIGADE_FIRST(bb);
|
|
|
ceb09b |
@@ -260,7 +267,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
|
|
|
ceb09b |
rv = apr_bucket_read(e, &str, &len, APR_BLOCK_READ);
|
|
|
ceb09b |
if (rv != APR_SUCCESS) {
|
|
|
ceb09b |
- return rv;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
if (len == 0) {
|
|
|
ceb09b |
@@ -273,17 +280,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
|
|
|
ceb09b |
/* Would this overrun our buffer? If so, we'll die. */
|
|
|
ceb09b |
if (n < bytes_handled + len) {
|
|
|
ceb09b |
- *read = bytes_handled;
|
|
|
ceb09b |
- if (*s) {
|
|
|
ceb09b |
- /* ensure this string is NUL terminated */
|
|
|
ceb09b |
- if (bytes_handled > 0) {
|
|
|
ceb09b |
- (*s)[bytes_handled-1] = '\0';
|
|
|
ceb09b |
- }
|
|
|
ceb09b |
- else {
|
|
|
ceb09b |
- (*s)[0] = '\0';
|
|
|
ceb09b |
- }
|
|
|
ceb09b |
- }
|
|
|
ceb09b |
- return APR_ENOSPC;
|
|
|
ceb09b |
+ rv = APR_ENOSPC;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
/* Do we have to handle the allocation ourselves? */
|
|
|
ceb09b |
@@ -291,7 +289,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
/* We'll assume the common case where one bucket is enough. */
|
|
|
ceb09b |
if (!*s) {
|
|
|
ceb09b |
current_alloc = len;
|
|
|
ceb09b |
- *s = apr_palloc(r->pool, current_alloc);
|
|
|
ceb09b |
+ *s = apr_palloc(r->pool, current_alloc + 1);
|
|
|
ceb09b |
}
|
|
|
ceb09b |
else if (bytes_handled + len > current_alloc) {
|
|
|
ceb09b |
/* Increase the buffer size */
|
|
|
ceb09b |
@@ -302,7 +300,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
new_size = (bytes_handled + len) * 2;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
- new_buffer = apr_palloc(r->pool, new_size);
|
|
|
ceb09b |
+ new_buffer = apr_palloc(r->pool, new_size + 1);
|
|
|
ceb09b |
|
|
|
ceb09b |
/* Copy what we already had. */
|
|
|
ceb09b |
memcpy(new_buffer, *s, bytes_handled);
|
|
|
ceb09b |
@@ -326,19 +324,15 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
}
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
- if (crlf && (last_char <= *s || last_char[-1] != APR_ASCII_CR)) {
|
|
|
ceb09b |
- *last_char = '\0';
|
|
|
ceb09b |
- bytes_handled = last_char - *s;
|
|
|
ceb09b |
- *read = bytes_handled;
|
|
|
ceb09b |
- return APR_EINVAL;
|
|
|
ceb09b |
- }
|
|
|
ceb09b |
-
|
|
|
ceb09b |
- /* Now NUL-terminate the string at the end of the line;
|
|
|
ceb09b |
+ /* Now terminate the string at the end of the line;
|
|
|
ceb09b |
* if the last-but-one character is a CR, terminate there */
|
|
|
ceb09b |
if (last_char > *s && last_char[-1] == APR_ASCII_CR) {
|
|
|
ceb09b |
last_char--;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
- *last_char = '\0';
|
|
|
ceb09b |
+ else if (crlf) {
|
|
|
ceb09b |
+ rv = APR_EINVAL;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
+ }
|
|
|
ceb09b |
bytes_handled = last_char - *s;
|
|
|
ceb09b |
|
|
|
ceb09b |
/* If we're folding, we have more work to do.
|
|
|
ceb09b |
@@ -358,7 +352,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_SPECULATIVE,
|
|
|
ceb09b |
APR_BLOCK_READ, 1);
|
|
|
ceb09b |
if (rv != APR_SUCCESS) {
|
|
|
ceb09b |
- return rv;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
if (APR_BRIGADE_EMPTY(bb)) {
|
|
|
ceb09b |
@@ -375,7 +369,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
rv = apr_bucket_read(e, &str, &len, APR_BLOCK_READ);
|
|
|
ceb09b |
if (rv != APR_SUCCESS) {
|
|
|
ceb09b |
apr_brigade_cleanup(bb);
|
|
|
ceb09b |
- return rv;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
/* Found one, so call ourselves again to get the next line.
|
|
|
ceb09b |
@@ -392,10 +386,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
if (c == APR_ASCII_BLANK || c == APR_ASCII_TAB) {
|
|
|
ceb09b |
/* Do we have enough space? We may be full now. */
|
|
|
ceb09b |
if (bytes_handled >= n) {
|
|
|
ceb09b |
- *read = n;
|
|
|
ceb09b |
- /* ensure this string is terminated */
|
|
|
ceb09b |
- (*s)[n-1] = '\0';
|
|
|
ceb09b |
- return APR_ENOSPC;
|
|
|
ceb09b |
+ rv = APR_ENOSPC;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
else {
|
|
|
ceb09b |
apr_size_t next_size, next_len;
|
|
|
ceb09b |
@@ -408,7 +400,6 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
tmp = NULL;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
else {
|
|
|
ceb09b |
- /* We're null terminated. */
|
|
|
ceb09b |
tmp = last_char;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
@@ -417,7 +408,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
rv = ap_rgetline_core(&tmp, next_size,
|
|
|
ceb09b |
&next_len, r, 0, bb);
|
|
|
ceb09b |
if (rv != APR_SUCCESS) {
|
|
|
ceb09b |
- return rv;
|
|
|
ceb09b |
+ goto cleanup;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
if (do_alloc && next_len > 0) {
|
|
|
ceb09b |
@@ -431,7 +422,7 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
memcpy(new_buffer, *s, bytes_handled);
|
|
|
ceb09b |
|
|
|
ceb09b |
/* copy the new line, including the trailing null */
|
|
|
ceb09b |
- memcpy(new_buffer + bytes_handled, tmp, next_len + 1);
|
|
|
ceb09b |
+ memcpy(new_buffer + bytes_handled, tmp, next_len);
|
|
|
ceb09b |
*s = new_buffer;
|
|
|
ceb09b |
}
|
|
|
ceb09b |
|
|
|
ceb09b |
@@ -444,8 +435,21 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
|
|
|
ceb09b |
}
|
|
|
ceb09b |
}
|
|
|
ceb09b |
}
|
|
|
ceb09b |
+
|
|
|
ceb09b |
+cleanup:
|
|
|
ceb09b |
+ if (bytes_handled >= n) {
|
|
|
ceb09b |
+ bytes_handled = n - 1;
|
|
|
ceb09b |
+ }
|
|
|
ceb09b |
+ if (*s) {
|
|
|
ceb09b |
+ /* ensure the string is NUL terminated */
|
|
|
ceb09b |
+ (*s)[bytes_handled] = '\0';
|
|
|
ceb09b |
+ }
|
|
|
ceb09b |
*read = bytes_handled;
|
|
|
ceb09b |
|
|
|
ceb09b |
+ if (rv != APR_SUCCESS) {
|
|
|
ceb09b |
+ return rv;
|
|
|
ceb09b |
+ }
|
|
|
ceb09b |
+
|
|
|
ceb09b |
/* PR#43039: We shouldn't accept NULL bytes within the line */
|
|
|
ceb09b |
if (strlen(*s) < bytes_handled) {
|
|
|
ceb09b |
return APR_EINVAL;
|
|
|
ceb09b |
@@ -484,6 +488,11 @@ AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags)
|
|
|
ceb09b |
apr_size_t len;
|
|
|
ceb09b |
apr_bucket_brigade *tmp_bb;
|
|
|
ceb09b |
|
|
|
ceb09b |
+ if (n < 1) {
|
|
|
ceb09b |
+ /* Can't work since we always NUL terminate */
|
|
|
ceb09b |
+ return -1;
|
|
|
ceb09b |
+ }
|
|
|
ceb09b |
+
|
|
|
ceb09b |
tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
|
|
ceb09b |
rv = ap_rgetline(&tmp_s, n, &len, r, flags, tmp_bb);
|
|
|
ceb09b |
apr_brigade_destroy(tmp_bb);
|