summaryrefslogtreecommitdiff
path: root/buckets
diff options
context:
space:
mode:
authorStefan Fritsch <sf@apache.org>2012-10-27 21:56:58 +0000
committerStefan Fritsch <sf@apache.org>2012-10-27 21:56:58 +0000
commit93d370f9d28010a3374f481d9cd198ec4833f7e2 (patch)
tree152e25293268eba58fc3367a3ac26890fda293c7 /buckets
parent84671572b4954da80e51b3da3a35ffed11e26516 (diff)
downloadapr-93d370f9d28010a3374f481d9cd198ec4833f7e2.tar.gz
Fix potential data corruption in apr_brigade_write() and friends if
the last bucket of the brigade is a heap bucket that has been split, and there are still references to the next part of the original bucket in use. git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1402897 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'buckets')
-rw-r--r--buckets/apr_brigade.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/buckets/apr_brigade.c b/buckets/apr_brigade.c
index a0fcd8781..b22e98220 100644
--- a/buckets/apr_brigade.c
+++ b/buckets/apr_brigade.c
@@ -448,7 +448,12 @@ APR_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b,
apr_size_t remaining = APR_BUCKET_BUFF_SIZE;
char *buf = NULL;
- if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)) {
+ /*
+ * If the last bucket is a heap bucket and its buffer is not shared with
+ * another bucket, we may write into that bucket.
+ */
+ if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
+ && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
apr_bucket_heap *h = e->data;
/* HEAP bucket start offsets are always in-memory, safe to cast */
@@ -538,10 +543,11 @@ APR_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b,
i = 0;
/* If there is a heap bucket at the end of the brigade
- * already, copy into the existing bucket.
+ * already, and its refcount is 1, copy into the existing bucket.
*/
e = APR_BRIGADE_LAST(b);
- if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)) {
+ if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
+ && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
apr_bucket_heap *h = e->data;
apr_size_t remaining = h->alloc_len -
(e->length + (apr_size_t)e->start);