@@ -90,6 +90,7 @@ ZEND_GET_MODULE(sysvshm)
9090/* TODO: Make this thread-safe. */
9191sysvshm_module php_sysvshm ;
9292
93+ static bool php_check_shm_head (const sysvshm_chunk_head * ptr , zend_long shm_size );
9394static int php_put_shm_data (sysvshm_chunk_head * ptr , zend_long key , const char * data , zend_long len );
9495static zend_long php_check_shm_data (sysvshm_chunk_head * ptr , zend_long key );
9596static int php_remove_shm_data (sysvshm_chunk_head * ptr , zend_long shm_varpos );
@@ -196,6 +197,10 @@ PHP_FUNCTION(shm_attach)
196197 chunk_ptr -> end = chunk_ptr -> start ;
197198 chunk_ptr -> total = shm_size ;
198199 chunk_ptr -> free = shm_size - chunk_ptr -> end ;
200+ } else if (!php_check_shm_head (chunk_ptr , shm_size )) {
201+ php_error_docref (NULL , E_WARNING , "Failed for key 0x" ZEND_XLONG_FMT ": segment header is corrupted" , shm_key );
202+ shmdt (shm_ptr );
203+ RETURN_FALSE ;
199204 }
200205
201206 object_init_ex (return_value , sysvshm_ce );
@@ -309,6 +314,8 @@ PHP_FUNCTION(shm_get_var)
309314 sysvshm_shm * shm_list_ptr ;
310315 char * shm_data ;
311316 zend_long shm_varpos ;
317+ zend_long shm_avail ;
318+ zend_long shm_len ;
312319 sysvshm_chunk * shm_var ;
313320 php_unserialize_data_t var_hash ;
314321
@@ -331,10 +338,16 @@ PHP_FUNCTION(shm_get_var)
331338 RETURN_FALSE ;
332339 }
333340 shm_var = (sysvshm_chunk * ) ((char * )shm_list_ptr -> ptr + shm_varpos );
341+ shm_avail = shm_list_ptr -> ptr -> end - shm_varpos - (zend_long ) sizeof (sysvshm_chunk );
342+ if (shm_var -> length < 0 || shm_var -> length > shm_avail ) {
343+ php_error_docref (NULL , E_WARNING , "Variable data in shared memory is corrupted" );
344+ RETURN_FALSE ;
345+ }
346+ shm_len = shm_var -> length ;
334347 shm_data = & shm_var -> mem ;
335348
336349 PHP_VAR_UNSERIALIZE_INIT (var_hash );
337- int res = php_var_unserialize (return_value , (const unsigned char * * ) & shm_data , (unsigned char * ) shm_data + shm_var -> length , & var_hash );
350+ int res = php_var_unserialize (return_value , (const unsigned char * * ) & shm_data , (unsigned char * ) shm_data + shm_len , & var_hash );
338351 PHP_VAR_UNSERIALIZE_DESTROY (var_hash );
339352 if (res != 1 ) {
340353 php_error_docref (NULL , E_WARNING , "Variable data in shared memory is corrupted" );
@@ -388,11 +401,33 @@ PHP_FUNCTION(shm_remove_var)
388401 php_error_docref (NULL , E_WARNING , "Variable key " ZEND_LONG_FMT " doesn't exist" , shm_key );
389402 RETURN_FALSE ;
390403 }
391- php_remove_shm_data ((shm_list_ptr -> ptr ), shm_varpos );
404+ if (php_remove_shm_data ((shm_list_ptr -> ptr ), shm_varpos ) < 0 ) {
405+ php_error_docref (NULL , E_WARNING , "Variable data in shared memory is corrupted" );
406+ RETURN_FALSE ;
407+ }
392408 RETURN_TRUE ;
393409}
394410/* }}} */
395411
412+ /* {{{ php_check_shm_head */
413+ static bool php_check_shm_head (const sysvshm_chunk_head * ptr , zend_long shm_size )
414+ {
415+ if (ptr -> total < (zend_long ) sizeof (sysvshm_chunk_head ) || ptr -> total > shm_size ) {
416+ return false;
417+ }
418+ if (ptr -> start < (zend_long ) sizeof (sysvshm_chunk_head ) || ptr -> start > ptr -> total ) {
419+ return false;
420+ }
421+ if (ptr -> end < ptr -> start || ptr -> end > ptr -> total ) {
422+ return false;
423+ }
424+ if (ptr -> free < 0 || ptr -> free > ptr -> total - ptr -> end ) {
425+ return false;
426+ }
427+ return true;
428+ }
429+ /* }}} */
430+
396431/* {{{ php_put_shm_data
397432 * inserts an ascii-string into shared memory */
398433static int php_put_shm_data (sysvshm_chunk_head * ptr , zend_long key , const char * data , zend_long len )
@@ -433,7 +468,7 @@ static zend_long php_check_shm_data(sysvshm_chunk_head *ptr, zend_long key)
433468 pos = ptr -> start ;
434469
435470 for (;;) {
436- if (pos >= ptr -> end ) {
471+ if (ptr -> end - pos < ( zend_long ) sizeof ( sysvshm_chunk ) ) {
437472 return -1 ;
438473 }
439474 shm_var = (sysvshm_chunk * ) ((char * ) ptr + pos );
@@ -459,6 +494,11 @@ static int php_remove_shm_data(sysvshm_chunk_head *ptr, zend_long shm_varpos)
459494 ZEND_ASSERT (ptr );
460495
461496 chunk_ptr = (sysvshm_chunk * ) ((char * ) ptr + shm_varpos );
497+
498+ if (chunk_ptr -> next <= 0 || chunk_ptr -> next > ptr -> end - shm_varpos ) {
499+ return -1 ;
500+ }
501+
462502 next_chunk_ptr = (sysvshm_chunk * ) ((char * ) ptr + shm_varpos + chunk_ptr -> next );
463503
464504 memcpy_len = ptr -> end - shm_varpos - chunk_ptr -> next ;
0 commit comments