Skip to content

Commit

Permalink
Handle memory limit error during string reallocation correctly
Browse files Browse the repository at this point in the history
Do not decrement the refcount before allocating the new string,
as the allocation operation may bail out and cause a use-after-free
lateron. We can only decrement the refcount once the allocation
has succeeded.

Fixes oss-fuzz #25384.
  • Loading branch information
nikic committed Sep 3, 2020
1 parent 54dbd3e commit 573ad18
Showing 1 changed file with 12 additions and 8 deletions.
20 changes: 12 additions & 8 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,13 @@ static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_
ZSTR_LEN(ret) = len;
zend_string_forget_hash_val(ret);
return ret;
} else {
GC_DELREF(s);
}
}
ret = zend_string_alloc(len, persistent);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN(len, ZSTR_LEN(s)) + 1);
if (!ZSTR_IS_INTERNED(s)) {
GC_DELREF(s);
}
return ret;
}

Expand All @@ -206,12 +207,13 @@ static zend_always_inline zend_string *zend_string_extend(zend_string *s, size_t
ZSTR_LEN(ret) = len;
zend_string_forget_hash_val(ret);
return ret;
} else {
GC_DELREF(s);
}
}
ret = zend_string_alloc(len, persistent);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), ZSTR_LEN(s) + 1);
if (!ZSTR_IS_INTERNED(s)) {
GC_DELREF(s);
}
return ret;
}

Expand All @@ -226,12 +228,13 @@ static zend_always_inline zend_string *zend_string_truncate(zend_string *s, size
ZSTR_LEN(ret) = len;
zend_string_forget_hash_val(ret);
return ret;
} else {
GC_DELREF(s);
}
}
ret = zend_string_alloc(len, persistent);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), len + 1);
if (!ZSTR_IS_INTERNED(s)) {
GC_DELREF(s);
}
return ret;
}

Expand All @@ -245,12 +248,13 @@ static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s,
ZSTR_LEN(ret) = (n * m) + l;
zend_string_forget_hash_val(ret);
return ret;
} else {
GC_DELREF(s);
}
}
ret = zend_string_safe_alloc(n, m, l, persistent);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
if (!ZSTR_IS_INTERNED(s)) {
GC_DELREF(s);
}
return ret;
}

Expand Down

0 comments on commit 573ad18

Please sign in to comment.