php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #74539 use-after-free bug
Submitted: 2017-05-04 07:31 UTC Modified: 2017-06-23 15:46 UTC
From: yanhuacs at gmail dot com Assigned:
Status: Not a bug Package: opcache
PHP Version: 7.1.5RC1 OS: Ubuntu14.04
Private report: No CVE-ID: None
 [2017-05-04 07:31 UTC] yanhuacs at gmail dot com
Description:
------------
I'd like to report a potential double-free (a special case of use-after-free) bug as follows.

Step 1, function _zend_shared_memdup (defined in lines 349-365 in ext/opcache/zend_shared_alloc.c) frees "source" in line 362.
Step 2, function _zend_shared_memdup returns to its call site in function zend_persist_ast (defined in lines 247-278 in ext/opcache/zend_persist.c)
in line 253/258/267.
Step 3, "ast" is freed in line 267 (ext/opcache/zend_persist.c). Note that "ast" and "source" are pointer aliases due to parameter passing at line 253/258/267.

Below is code snippet.

/*--- ext/opcache/zend_shared_alloc.c ---*/
349: void *_zend_shared_memdup(void *source, size_t size, zend_bool free_source)
350: {
351: 	void *old_p, *retval;
352: 
353: 	if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), (zend_ulong)source)) != NULL) {
354: 		/* we already duplicated this pointer */
355: 		return old_p;
356: 	}
357: 	retval = ZCG(mem);
358: 	ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size));
359: 	memcpy(retval, source, size);
360: 	zend_shared_alloc_register_xlat_entry(source, retval);
361: 	if (free_source) {
362: 		efree(source); //////FREE the first time
363: 	}
364: 	return retval;
365: }


/*--- ext/opcache/zend_persist.c ---*/
247: static zend_ast *zend_persist_ast(zend_ast *ast)
248: {
249: 	uint32_t i;
250: 	zend_ast *node;
251: 
252: 	if (ast->kind == ZEND_AST_ZVAL) {
253: 		zend_ast_zval *copy = zend_accel_memdup(ast, sizeof(zend_ast_zval));
254: 		zend_persist_zval(&copy->val);
255: 		node = (zend_ast *) copy;
256: 	} else if (zend_ast_is_list(ast)) {
257: 		zend_ast_list *list = zend_ast_get_list(ast);
258: 		zend_ast_list *copy = zend_accel_memdup(ast,
259: 			sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children);
260:		for (i = 0; i < list->children; i++) {
261:			if (copy->child[i]) {
262:				copy->child[i] = zend_persist_ast(copy->child[i]);
263:			}
264:		}
265:		node = (zend_ast *) copy;
266:	} else {
267:		uint32_t children = zend_ast_get_num_children(ast);
268:		node = zend_accel_memdup(ast, sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children);
269:		for (i = 0; i < children; i++) {
270:			if (node->child[i]) {
271:				node->child[i] = zend_persist_ast(node->child[i]);
272:			}
273:		}
274:	}
275:
276:	efree(ast); //////FREE AGAIN
277:	return node;
278: }


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-05-09 02:50 UTC] laruence@php.net
I am not sure what the problem is here, zend_accel_memdup calls _zend_shared_memdup with free_source 0(false)
 [2017-05-14 19:31 UTC] andrew dot nester dot de at gmail dot com
Agree that there is no use-after-free bug here
Here you can see that it's called with free_source=0
https://github.com/php/php-src/blob/master/ext/opcache/zend_persist.c#L34

That's why it's not double-freed
 [2017-06-23 15:46 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2017-06-23 15:46 UTC] nikic@php.net
Closing this as not a bug, per the above comments.
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Fri Aug 07 13:01:24 2020 UTC