general: Fix memory Corruption in __ast_string_field_ptr_build_va.

If the space left in a stringfield is between 0 and
(alignof(ast_string_field_allocation)-1) adding new data would cause
memory corruption, because we would assume enough space (unsigned
underrun).

Thanks Arnd Schmitter for reporting and finding out the cause!

ASTERISK-23508 #close
Reported by: Arnd Schmitter
Tested by: Arnd Schmitter, JoshE

Review: https://reviewboard.asterisk.org/r/3898/
........

Merged revisions 420680 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 420715 from http://svn.asterisk.org/svn/asterisk/branches/11
........

Merged revisions 420716 from http://svn.asterisk.org/svn/asterisk/branches/12
........

Merged revisions 420717 from http://svn.asterisk.org/svn/asterisk/branches/13


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@420718 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Walter Doekes
2014-08-11 10:41:07 +00:00
parent b2afbc48e4
commit 1e0846167b

View File

@@ -2001,6 +2001,7 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
size_t needed; size_t needed;
size_t available; size_t available;
size_t space = (*pool_head)->size - (*pool_head)->used; size_t space = (*pool_head)->size - (*pool_head)->used;
int res;
ssize_t grow; ssize_t grow;
char *target; char *target;
va_list ap2; va_list ap2;
@@ -2020,13 +2021,23 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
* so we don't need to re-align anything here. * so we don't need to re-align anything here.
*/ */
target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation); target = (*pool_head)->base + (*pool_head)->used + ast_alignof(ast_string_field_allocation);
available = space - ast_alignof(ast_string_field_allocation); if (space > ast_alignof(ast_string_field_allocation)) {
available = space - ast_alignof(ast_string_field_allocation);
} else {
available = 0;
}
} }
va_copy(ap2, ap); va_copy(ap2, ap);
needed = vsnprintf(target, available, format, ap2) + 1; res = vsnprintf(target, available, format, ap2);
va_end(ap2); va_end(ap2);
if (res < 0) {
/* Are we out of memory? */
return;
}
needed = (size_t)res + 1; /* NUL byte */
if (needed > available) { if (needed > available) {
/* the allocation could not be satisfied using the field's current allocation /* the allocation could not be satisfied using the field's current allocation
(if it has one), or the space available in the pool (if it does not). allocate (if it has one), or the space available in the pool (if it does not). allocate
@@ -2045,7 +2056,8 @@ void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
*/ */
__ast_string_field_release_active(*pool_head, *ptr); __ast_string_field_release_active(*pool_head, *ptr);
mgr->last_alloc = *ptr = target; mgr->last_alloc = *ptr = target;
AST_STRING_FIELD_ALLOCATION(target) = needed; ast_assert(needed < (ast_string_field_allocation)-1);
AST_STRING_FIELD_ALLOCATION(target) = (ast_string_field_allocation)needed;
(*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation); (*pool_head)->used += ast_make_room_for(needed, ast_string_field_allocation);
(*pool_head)->active += needed; (*pool_head)->active += needed;
} else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) { } else if ((grow = (needed - AST_STRING_FIELD_ALLOCATION(*ptr))) > 0) {