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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: yanhuacs at gmail dot com
New email:
PHP Version: OS:

 

 [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

Pull Requests

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-2024 The PHP Group
All rights reserved.
Last updated: Sun Dec 22 11:01:30 2024 UTC