Skip to content

Commit cab1c3b

Browse files
committed
Fixed bug #72479 - same as #72434
1 parent 1556191 commit cab1c3b

File tree

2 files changed

+84
-40
lines changed

2 files changed

+84
-40
lines changed

ext/snmp/snmp.c

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -475,15 +475,15 @@ static void php_snmp_session_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
475475
static void php_snmp_object_free_storage(void *object TSRMLS_DC)
476476
{
477477
php_snmp_object *intern = (php_snmp_object *)object;
478-
478+
479479
if (!intern) {
480480
return;
481481
}
482482

483483
netsnmp_session_free(&(intern->session));
484484

485485
zend_object_std_dtor(&intern->zo TSRMLS_CC);
486-
486+
487487
efree(intern);
488488
}
489489

@@ -503,7 +503,7 @@ static zend_object_value php_snmp_object_new(zend_class_entry *class_type TSRMLS
503503
retval.handlers = (zend_object_handlers *) &php_snmp_object_handlers;
504504

505505
return retval;
506-
506+
507507
}
508508

509509
/* {{{ php_snmp_error
@@ -556,7 +556,7 @@ static void php_snmp_getvalue(struct variable_list *vars, zval *snmpval TSRMLS_D
556556
char *dbuf = (char *)NULL;
557557
int buflen = sizeof(sbuf) - 1;
558558
int val_len = vars->val_len;
559-
559+
560560
/* use emalloc() for large values, use static array otherwize */
561561

562562
/* There is no way to know the size of buffer snprint_value() needs in order to print a value there.
@@ -702,7 +702,7 @@ static void php_snmp_getvalue(struct variable_list *vars, zval *snmpval TSRMLS_D
702702
* SNMP object fetcher/setter for all SNMP versions
703703
*
704704
*/
705-
static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
705+
static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
706706
struct snmp_session *session,
707707
struct objid_query *objid_query)
708708
{
@@ -721,7 +721,7 @@ static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
721721

722722
/* we start with retval=FALSE. If any actual data is acquired, retval will be set to appropriate type */
723723
RETVAL_FALSE;
724-
724+
725725
/* reset errno and errstr */
726726
php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_NOERROR, "");
727727

@@ -805,8 +805,8 @@ static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
805805
}
806806
for (vars = response->variables; vars; vars = vars->next_variable) {
807807
/* do not output errors as values */
808-
if ( vars->type == SNMP_ENDOFMIBVIEW ||
809-
vars->type == SNMP_NOSUCHOBJECT ||
808+
if ( vars->type == SNMP_ENDOFMIBVIEW ||
809+
vars->type == SNMP_NOSUCHOBJECT ||
810810
vars->type == SNMP_NOSUCHINSTANCE ) {
811811
if ((st & SNMP_CMD_WALK) && Z_TYPE_P(return_value) == IS_ARRAY) {
812812
break;
@@ -816,8 +816,8 @@ static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
816816
php_snmp_error(getThis(), NULL TSRMLS_CC, PHP_SNMP_ERRNO_ERROR_IN_REPLY, "Error in packet at '%s': %s", buf, buf2);
817817
continue;
818818
}
819-
820-
if ((st & SNMP_CMD_WALK) &&
819+
820+
if ((st & SNMP_CMD_WALK) &&
821821
(vars->name_length < rootlen || memcmp(root, vars->name, rootlen * sizeof(oid)))) { /* not part of this subtree */
822822
if (Z_TYPE_P(return_value) == IS_ARRAY) { /* some records are fetched already, shut down further lookup */
823823
keepwalking = 0;
@@ -1101,7 +1101,7 @@ static int php_snmp_parse_oid(zval *object, int st, struct objid_query *objid_qu
11011101
efree(objid_query->vars);
11021102
return FALSE;
11031103
}
1104-
} else {
1104+
} else {
11051105
memmove((char *)objid_query->vars[0].name, (char *)objid_mib, sizeof(objid_mib));
11061106
objid_query->vars[0].name_length = sizeof(objid_mib) / sizeof(oid);
11071107
}
@@ -1437,7 +1437,7 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version)
14371437
int session_less_mode = (getThis() == NULL);
14381438
php_snmp_object *snmp_object;
14391439
php_snmp_object glob_snmp_object;
1440-
1440+
14411441
objid_query.max_repetitions = -1;
14421442
objid_query.non_repeaters = 0;
14431443
objid_query.valueretrieval = SNMP_G(valueretrieval);
@@ -1550,7 +1550,7 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version)
15501550
}
15511551

15521552
php_snmp_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, st, session, &objid_query);
1553-
1553+
15541554
efree(objid_query.vars);
15551555

15561556
if (session_less_mode) {
@@ -1563,23 +1563,23 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version)
15631563
}
15641564
/* }}} */
15651565

1566-
/* {{{ proto mixed snmpget(string host, string community, mixed object_id [, int timeout [, int retries]])
1566+
/* {{{ proto mixed snmpget(string host, string community, mixed object_id [, int timeout [, int retries]])
15671567
Fetch a SNMP object */
15681568
PHP_FUNCTION(snmpget)
15691569
{
15701570
php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_1);
15711571
}
15721572
/* }}} */
15731573

1574-
/* {{{ proto mixed snmpgetnext(string host, string community, mixed object_id [, int timeout [, int retries]])
1574+
/* {{{ proto mixed snmpgetnext(string host, string community, mixed object_id [, int timeout [, int retries]])
15751575
Fetch a SNMP object */
15761576
PHP_FUNCTION(snmpgetnext)
15771577
{
15781578
php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_1);
15791579
}
15801580
/* }}} */
15811581

1582-
/* {{{ proto mixed snmpwalk(string host, string community, mixed object_id [, int timeout [, int retries]])
1582+
/* {{{ proto mixed snmpwalk(string host, string community, mixed object_id [, int timeout [, int retries]])
15831583
Return all objects under the specified object id */
15841584
PHP_FUNCTION(snmpwalk)
15851585
{
@@ -1595,7 +1595,7 @@ PHP_FUNCTION(snmprealwalk)
15951595
}
15961596
/* }}} */
15971597

1598-
/* {{{ proto bool snmpset(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]])
1598+
/* {{{ proto bool snmpset(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]])
15991599
Set the value of a SNMP object */
16001600
PHP_FUNCTION(snmpset)
16011601
{
@@ -1642,7 +1642,7 @@ PHP_FUNCTION(snmp_set_enum_print)
16421642

16431643
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM, (int) a1);
16441644
RETURN_TRUE;
1645-
}
1645+
}
16461646
/* }}} */
16471647

16481648
/* {{{ proto bool snmp_set_oid_output_format(int oid_format)
@@ -1670,26 +1670,26 @@ PHP_FUNCTION(snmp_set_oid_output_format)
16701670
RETURN_FALSE;
16711671
break;
16721672
}
1673-
}
1673+
}
16741674
/* }}} */
16751675

1676-
/* {{{ proto mixed snmp2_get(string host, string community, mixed object_id [, int timeout [, int retries]])
1676+
/* {{{ proto mixed snmp2_get(string host, string community, mixed object_id [, int timeout [, int retries]])
16771677
Fetch a SNMP object */
16781678
PHP_FUNCTION(snmp2_get)
16791679
{
16801680
php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GET, SNMP_VERSION_2c);
16811681
}
16821682
/* }}} */
16831683

1684-
/* {{{ proto mixed snmp2_getnext(string host, string community, mixed object_id [, int timeout [, int retries]])
1684+
/* {{{ proto mixed snmp2_getnext(string host, string community, mixed object_id [, int timeout [, int retries]])
16851685
Fetch a SNMP object */
16861686
PHP_FUNCTION(snmp2_getnext)
16871687
{
16881688
php_snmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, SNMP_CMD_GETNEXT, SNMP_VERSION_2c);
16891689
}
16901690
/* }}} */
16911691

1692-
/* {{{ proto mixed snmp2_walk(string host, string community, mixed object_id [, int timeout [, int retries]])
1692+
/* {{{ proto mixed snmp2_walk(string host, string community, mixed object_id [, int timeout [, int retries]])
16931693
Return all objects under the specified object id */
16941694
PHP_FUNCTION(snmp2_walk)
16951695
{
@@ -1705,7 +1705,7 @@ PHP_FUNCTION(snmp2_real_walk)
17051705
}
17061706
/* }}} */
17071707

1708-
/* {{{ proto bool snmp2_set(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]])
1708+
/* {{{ proto bool snmp2_set(string host, string community, mixed object_id, mixed type, mixed value [, int timeout [, int retries]])
17091709
Set the value of a SNMP object */
17101710
PHP_FUNCTION(snmp2_set)
17111711
{
@@ -1821,7 +1821,7 @@ PHP_METHOD(snmp, __construct)
18211821

18221822
snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
18231823
zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
1824-
1824+
18251825
if (zend_parse_parameters(argc TSRMLS_CC, "lss|ll", &version, &a1, &a1_len, &a2, &a2_len, &timeout, &retries) == FAILURE) {
18261826
zend_restore_error_handling(&error_handling TSRMLS_CC);
18271827
return;
@@ -1843,7 +1843,7 @@ PHP_METHOD(snmp, __construct)
18431843
if (snmp_object->session) {
18441844
netsnmp_session_free(&(snmp_object->session));
18451845
}
1846-
1846+
18471847
if (netsnmp_session_init(&(snmp_object->session), version, a1, a2, timeout, retries TSRMLS_CC)) {
18481848
return;
18491849
}
@@ -1857,7 +1857,7 @@ PHP_METHOD(snmp, __construct)
18571857
}
18581858
/* }}} */
18591859

1860-
/* {{{ proto bool SNMP::close()
1860+
/* {{{ proto bool SNMP::close()
18611861
Close SNMP session */
18621862
PHP_METHOD(snmp, close)
18631863
{
@@ -1900,7 +1900,7 @@ PHP_METHOD(snmp, walk)
19001900
}
19011901
/* }}} */
19021902

1903-
/* {{{ proto bool SNMP::set(mixed object_id, mixed type, mixed value)
1903+
/* {{{ proto bool SNMP::set(mixed object_id, mixed type, mixed value)
19041904
Set the value of a SNMP object */
19051905
PHP_METHOD(snmp, set)
19061906
{
@@ -1918,7 +1918,7 @@ PHP_METHOD(snmp, setSecurity)
19181918
int argc = ZEND_NUM_ARGS();
19191919

19201920
snmp_object = (php_snmp_object *)zend_object_store_get_object(object TSRMLS_CC);
1921-
1921+
19221922
if (zend_parse_parameters(argc TSRMLS_CC, "s|ssssss", &a1, &a1_len, &a2, &a2_len, &a3, &a3_len,
19231923
&a4, &a4_len, &a5, &a5_len, &a6, &a6_len, &a7, &a7_len) == FAILURE) {
19241924
RETURN_FALSE;
@@ -1932,7 +1932,7 @@ PHP_METHOD(snmp, setSecurity)
19321932
}
19331933
/* }}} */
19341934

1935-
/* {{{ proto long SNMP::getErrno()
1935+
/* {{{ proto long SNMP::getErrno()
19361936
Get last error code number */
19371937
PHP_METHOD(snmp, getErrno)
19381938
{
@@ -1946,7 +1946,7 @@ PHP_METHOD(snmp, getErrno)
19461946
}
19471947
/* }}} */
19481948

1949-
/* {{{ proto long SNMP::getError()
1949+
/* {{{ proto long SNMP::getError()
19501950
Get last error message */
19511951
PHP_METHOD(snmp, getError)
19521952
{
@@ -2095,6 +2095,14 @@ static int php_snmp_has_property(zval *object, zval *member, int has_set_exists,
20952095
}
20962096
/* }}} */
20972097

2098+
static HashTable *php_snmp_get_gc(zval *object, zval ***gc_data, int *gc_data_count TSRMLS_DC) /* {{{ */
2099+
{
2100+
*gc_data = NULL;
2101+
*gc_data_count = 0;
2102+
return zend_std_get_properties(object TSRMLS_CC);
2103+
}
2104+
/* }}} */
2105+
20982106
/* {{{ php_snmp_get_properties(zval *object)
20992107
Returns all object properties. Injects SNMP properties into object on first call */
21002108
static HashTable *php_snmp_get_properties(zval *object TSRMLS_DC)
@@ -2137,23 +2145,23 @@ static int php_snmp_read_info(php_snmp_object *snmp_object, zval **retval TSRMLS
21372145
if (snmp_object->session == NULL) {
21382146
return SUCCESS;
21392147
}
2140-
2148+
21412149
MAKE_STD_ZVAL(val);
21422150
ZVAL_STRINGL(val, snmp_object->session->peername, strlen(snmp_object->session->peername), 1);
21432151
add_assoc_zval(*retval, "hostname", val);
2144-
2152+
21452153
MAKE_STD_ZVAL(val);
21462154
ZVAL_LONG(val, snmp_object->session->remote_port);
21472155
add_assoc_zval(*retval, "port", val);
2148-
2156+
21492157
MAKE_STD_ZVAL(val);
21502158
ZVAL_LONG(val, snmp_object->session->timeout);
21512159
add_assoc_zval(*retval, "timeout", val);
2152-
2160+
21532161
MAKE_STD_ZVAL(val);
21542162
ZVAL_LONG(val, snmp_object->session->retries);
21552163
add_assoc_zval(*retval, "retries", val);
2156-
2164+
21572165
return SUCCESS;
21582166
}
21592167
/* }}} */
@@ -2226,7 +2234,7 @@ static int php_snmp_write_max_oids(php_snmp_object *snmp_object, zval *newval TS
22262234
} else {
22272235
php_error_docref(NULL TSRMLS_CC, E_WARNING, "max_oids should be positive integer or NULL, got %ld", Z_LVAL_P(newval));
22282236
}
2229-
2237+
22302238
if (newval == &ztmp) {
22312239
zval_dtor(newval);
22322240
}
@@ -2254,7 +2262,7 @@ static int php_snmp_write_valueretrieval(php_snmp_object *snmp_object, zval *new
22542262
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown SNMP value retrieval method '%ld'", Z_LVAL_P(newval));
22552263
ret = FAILURE;
22562264
}
2257-
2265+
22582266
if (newval == &ztmp) {
22592267
zval_dtor(newval);
22602268
}
@@ -2297,7 +2305,7 @@ static int php_snmp_write_oid_output_format(php_snmp_object *snmp_object, zval *
22972305
convert_to_long(&ztmp);
22982306
newval = &ztmp;
22992307
}
2300-
2308+
23012309
switch(Z_LVAL_P(newval)) {
23022310
case NETSNMP_OID_OUTPUT_SUFFIX:
23032311
case NETSNMP_OID_OUTPUT_MODULE:
@@ -2332,7 +2340,7 @@ static int php_snmp_write_exceptions_enabled(php_snmp_object *snmp_object, zval
23322340
newval = &ztmp;
23332341
}
23342342

2335-
snmp_object->exceptions_enabled = Z_LVAL_P(newval);
2343+
snmp_object->exceptions_enabled = Z_LVAL_P(newval);
23362344

23372345
if (newval == &ztmp) {
23382346
zval_dtor(newval);
@@ -2401,6 +2409,7 @@ PHP_MINIT_FUNCTION(snmp)
24012409
php_snmp_object_handlers.write_property = php_snmp_write_property;
24022410
php_snmp_object_handlers.has_property = php_snmp_has_property;
24032411
php_snmp_object_handlers.get_properties = php_snmp_get_properties;
2412+
php_snmp_object_handlers.get_gc = php_snmp_get_gc;
24042413

24052414
/* Register SNMP Class */
24062415
INIT_CLASS_ENTRY(ce, "SNMP", php_snmp_class_methods);
@@ -2467,7 +2476,7 @@ PHP_MINIT_FUNCTION(snmp)
24672476
PHP_MSHUTDOWN_FUNCTION(snmp)
24682477
{
24692478
snmp_shutdown("snmpapp");
2470-
2479+
24712480
zend_hash_destroy(&php_snmp_properties);
24722481

24732482
return SUCCESS;

ext/snmp/tests/bug72479.phpt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Bug #72479: Use After Free Vulnerability in SNMP with GC and unserialize()
3+
--SKIPIF--
4+
<?php
5+
require_once(dirname(__FILE__).'/skipif.inc');
6+
?>
7+
--FILE--
8+
<?php
9+
$arr = [1, [1, 2, 3, 4, 5], 3, 4, 5];
10+
$poc = 'a:3:{i:1;N;i:2;O:4:"snmp":1:{s:11:"quick_print";'.serialize($arr).'}i:1;R:7;}';
11+
$out = unserialize($poc);
12+
gc_collect_cycles();
13+
$fakezval = ptr2str(1122334455);
14+
$fakezval .= ptr2str(0);
15+
$fakezval .= "\x00\x00\x00\x00";
16+
$fakezval .= "\x01";
17+
$fakezval .= "\x00";
18+
$fakezval .= "\x00\x00";
19+
for ($i = 0; $i < 5; $i++) {
20+
$v[$i] = $fakezval.$i;
21+
}
22+
var_dump($out[1]);
23+
24+
function ptr2str($ptr)
25+
{
26+
$out = '';
27+
for ($i = 0; $i < 8; $i++) {
28+
$out .= chr($ptr & 0xff);
29+
$ptr >>= 8;
30+
}
31+
return $out;
32+
}
33+
?>
34+
--EXPECT--
35+
int(1)

0 commit comments

Comments
 (0)