mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-17 22:56:18 +03:00
Add a check for the definition MOVE_REQUEST_CHAIN_TO_MODSEC, whenever it is set the chain will be moved into the brigade. If it was not set the chain will be only copied. Moving was causing segfaults on the following regression tests: #15 - SecRequestBodyInMemoryLimit #16 - SecRequestBodyInMemoryLimit (greater) #19 - SecRequestBodyLimitAction ProcessPartial (multipart/greater - chunked) (from: regression/config/10-request-directives.t)
284 lines
7.1 KiB
C
284 lines
7.1 KiB
C
|
|
#include <apr_bucket_nginx.h>
|
|
|
|
static apr_status_t nginx_bucket_read(apr_bucket *b, const char **str,
|
|
apr_size_t *len, apr_read_type_e block);
|
|
static void nginx_bucket_destroy(void *data);
|
|
|
|
static const apr_bucket_type_t apr_bucket_type_nginx = {
|
|
"NGINX", 5, APR_BUCKET_DATA,
|
|
nginx_bucket_destroy,
|
|
nginx_bucket_read,
|
|
apr_bucket_setaside_noop,
|
|
apr_bucket_shared_split,
|
|
apr_bucket_shared_copy
|
|
};
|
|
|
|
|
|
typedef struct apr_bucket_nginx {
|
|
apr_bucket_refcount refcount;
|
|
ngx_buf_t *buf;
|
|
} apr_bucket_nginx;
|
|
|
|
/* ngx_buf_t to apr_bucket */
|
|
apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
|
|
apr_pool_t *p,
|
|
apr_bucket_alloc_t *list)
|
|
{
|
|
|
|
apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
|
|
|
|
APR_BUCKET_INIT(b); /* link */
|
|
b->free = apr_bucket_free;
|
|
b->list = list;
|
|
return apr_bucket_nginx_make(b, buf, p);
|
|
}
|
|
|
|
apr_bucket * apr_bucket_nginx_make(apr_bucket *b, ngx_buf_t *buf,
|
|
apr_pool_t *pool)
|
|
{
|
|
apr_bucket_nginx *n;
|
|
|
|
n = apr_bucket_alloc(sizeof(*n), b->list);
|
|
|
|
n->buf = buf;
|
|
|
|
b = apr_bucket_shared_make(b, n, 0, ngx_buf_size(buf));
|
|
b->type = &apr_bucket_type_nginx;
|
|
return b;
|
|
}
|
|
|
|
static apr_status_t nginx_bucket_read(apr_bucket *b, const char **str,
|
|
apr_size_t *len, apr_read_type_e block)
|
|
{
|
|
apr_bucket_nginx *n = b->data;
|
|
ngx_buf_t *buf = n->buf;
|
|
u_char *data;
|
|
ssize_t size;
|
|
|
|
if (buf->pos == NULL && ngx_buf_size(buf) != 0) {
|
|
data = apr_bucket_alloc(ngx_buf_size(buf), b->list);
|
|
if (data == NULL) {
|
|
return APR_EGENERAL;
|
|
}
|
|
|
|
size = ngx_read_file(buf->file, data, ngx_buf_size(buf), buf->file_pos);
|
|
if (size != ngx_buf_size(buf)) {
|
|
apr_bucket_free(data);
|
|
return APR_EGENERAL;
|
|
}
|
|
buf->pos = data;
|
|
}
|
|
|
|
*str = (char *)buf->pos + b->start;
|
|
*len = b->length;
|
|
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
|
|
static void nginx_bucket_destroy(void *data)
|
|
{
|
|
apr_bucket_nginx *n = data;
|
|
ngx_buf_t *buf = n->buf;
|
|
|
|
if (apr_bucket_shared_destroy(n)) {
|
|
if (!ngx_buf_in_memory(buf) && buf->pos != NULL) {
|
|
apr_bucket_free(buf->pos);
|
|
buf->pos = NULL;
|
|
}
|
|
apr_bucket_free(n);
|
|
}
|
|
}
|
|
|
|
ngx_buf_t * apr_bucket_to_ngx_buf(apr_bucket *e, ngx_pool_t *pool) {
|
|
ngx_buf_t *buf, *b;
|
|
apr_bucket_nginx *n;
|
|
ngx_uint_t len;
|
|
u_char *data;
|
|
|
|
if (e->type->is_metadata) {
|
|
return NULL;
|
|
}
|
|
|
|
if (e->type == &apr_bucket_type_nginx) {
|
|
n = e->data;
|
|
b = n->buf;
|
|
|
|
/* whole buf */
|
|
if (e->length == (apr_size_t)ngx_buf_size(b)) {
|
|
b->last_buf = 0;
|
|
return b;
|
|
}
|
|
|
|
buf = ngx_palloc(pool, sizeof(ngx_buf_t));
|
|
if (buf == NULL) {
|
|
return NULL;
|
|
}
|
|
ngx_memcpy(buf, b, sizeof(ngx_buf_t));
|
|
|
|
if (ngx_buf_in_memory(buf)) {
|
|
buf->start = buf->pos = buf->pos + e->start;
|
|
buf->end = buf->last = buf->pos + e->length;
|
|
} else {
|
|
buf->pos = NULL;
|
|
buf->file_pos += e->start;
|
|
buf->file_last = buf->file_pos + e->length;
|
|
}
|
|
|
|
buf->last_buf = 0;
|
|
return buf;
|
|
}
|
|
|
|
if (apr_bucket_read(e, (const char **)&data,
|
|
&len, APR_BLOCK_READ) != APR_SUCCESS) {
|
|
return NULL;
|
|
}
|
|
|
|
buf = ngx_calloc_buf(pool);
|
|
if (buf == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (e->type == &apr_bucket_type_pool) {
|
|
buf->start = data;
|
|
} else if (len != 0) {
|
|
buf->start = ngx_palloc(pool, len);
|
|
ngx_memcpy(buf->start, data, len);
|
|
}
|
|
|
|
buf->pos = buf->start;
|
|
buf->end = buf->last = buf->start + len;
|
|
buf->temporary = 1;
|
|
return buf;
|
|
}
|
|
|
|
ngx_int_t
|
|
copy_chain_to_brigade(ngx_chain_t *chain_orig, apr_bucket_brigade *bb, ngx_pool_t *pool, ngx_int_t last_buf) {
|
|
apr_bucket *e;
|
|
|
|
ngx_chain_t *chain = chain_orig;
|
|
while (chain) {
|
|
e = ngx_buf_to_apr_bucket(chain->buf, bb->p, bb->bucket_alloc);
|
|
if (e == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
APR_BRIGADE_INSERT_TAIL(bb, e);
|
|
if (chain->buf->last_buf) {
|
|
e = apr_bucket_eos_create(bb->bucket_alloc);
|
|
APR_BRIGADE_INSERT_TAIL(bb, e);
|
|
return NGX_OK;
|
|
}
|
|
chain = chain->next;
|
|
}
|
|
|
|
if (last_buf) {
|
|
e = apr_bucket_eos_create(bb->bucket_alloc);
|
|
APR_BRIGADE_INSERT_TAIL(bb, e);
|
|
return NGX_OK;
|
|
}
|
|
|
|
return NGX_AGAIN;
|
|
}
|
|
|
|
|
|
ngx_int_t
|
|
move_chain_to_brigade(ngx_chain_t *chain_orig, apr_bucket_brigade *bb, ngx_pool_t *pool, ngx_int_t last_buf) {
|
|
apr_bucket *e;
|
|
ngx_chain_t *cl;
|
|
|
|
ngx_chain_t *chain = chain_orig;
|
|
|
|
while (chain) {
|
|
e = ngx_buf_to_apr_bucket(chain->buf, bb->p, bb->bucket_alloc);
|
|
if (e == NULL) {
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
APR_BRIGADE_INSERT_TAIL(bb, e);
|
|
if (chain->buf->last_buf) {
|
|
e = apr_bucket_eos_create(bb->bucket_alloc);
|
|
APR_BRIGADE_INSERT_TAIL(bb, e);
|
|
return NGX_OK;
|
|
}
|
|
cl = chain;
|
|
chain = chain->next;
|
|
ngx_free_chain(pool, cl);
|
|
}
|
|
|
|
if (last_buf) {
|
|
e = apr_bucket_eos_create(bb->bucket_alloc);
|
|
APR_BRIGADE_INSERT_TAIL(bb, e);
|
|
return NGX_OK;
|
|
}
|
|
return NGX_AGAIN;
|
|
}
|
|
|
|
ngx_int_t
|
|
move_brigade_to_chain(apr_bucket_brigade *bb, ngx_chain_t **ll, ngx_pool_t *pool) {
|
|
apr_bucket *e;
|
|
ngx_buf_t *buf;
|
|
ngx_chain_t *cl;
|
|
|
|
cl = NULL;
|
|
|
|
if (APR_BRIGADE_EMPTY(bb)) {
|
|
*ll = NULL;
|
|
return NGX_OK;
|
|
}
|
|
|
|
for (e = APR_BRIGADE_FIRST(bb);
|
|
e != APR_BRIGADE_SENTINEL(bb);
|
|
e = APR_BUCKET_NEXT(e)) {
|
|
|
|
if (APR_BUCKET_IS_EOS(e)) {
|
|
if (cl == NULL) {
|
|
cl = ngx_alloc_chain_link(pool);
|
|
if (cl == NULL) {
|
|
break;
|
|
}
|
|
|
|
cl->buf = ngx_calloc_buf(pool);
|
|
if (cl->buf == NULL) {
|
|
break;
|
|
}
|
|
|
|
cl->buf->last_buf = 1;
|
|
cl->next = NULL;
|
|
*ll = cl;
|
|
} else {
|
|
cl->next = NULL;
|
|
cl->buf->last_buf = 1;
|
|
}
|
|
apr_brigade_cleanup(bb);
|
|
return NGX_OK;
|
|
}
|
|
|
|
if (APR_BUCKET_IS_METADATA(e)) {
|
|
continue;
|
|
}
|
|
|
|
buf = apr_bucket_to_ngx_buf(e, pool);
|
|
if (buf == NULL) {
|
|
break;
|
|
}
|
|
|
|
cl = ngx_alloc_chain_link(pool);
|
|
if (cl == NULL) {
|
|
break;
|
|
}
|
|
|
|
cl->buf = buf;
|
|
cl->next = NULL;
|
|
*ll = cl;
|
|
ll = &cl->next;
|
|
}
|
|
|
|
|
|
apr_brigade_cleanup(bb);
|
|
/* no eos or error */
|
|
return NGX_ERROR;
|
|
}
|
|
|