Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions ext/snmp/snmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ static bool snmp_session_set_sec_level(struct snmp_session *s, zend_string *leve
/* }}} */

/* {{{ Set the authentication protocol in the snmpv3 session */
static bool snmp_session_set_auth_protocol(struct snmp_session *s, zend_string *prot)
static ZEND_ATTRIBUTE_NONNULL bool snmp_session_set_auth_protocol(struct snmp_session *s, zend_string *prot)
{
#ifndef DISABLE_MD5
if (zend_string_equals_literal_ci(prot, "MD5")) {
Expand Down Expand Up @@ -1054,7 +1054,7 @@ static bool snmp_session_set_auth_protocol(struct snmp_session *s, zend_string *
/* }}} */

/* {{{ Set the security protocol in the snmpv3 session */
static bool snmp_session_set_sec_protocol(struct snmp_session *s, zend_string *prot)
static ZEND_ATTRIBUTE_NONNULL bool snmp_session_set_sec_protocol(struct snmp_session *s, zend_string *prot)
{
#ifndef NETSNMP_DISABLE_DES
if (zend_string_equals_literal_ci(prot, "DES")) {
Expand Down Expand Up @@ -1091,9 +1091,10 @@ static bool snmp_session_set_sec_protocol(struct snmp_session *s, zend_string *p
/* }}} */

/* {{{ Make key from pass phrase in the snmpv3 session */
static bool snmp_session_gen_auth_key(struct snmp_session *s, zend_string *pass)
static ZEND_ATTRIBUTE_NONNULL bool snmp_session_gen_auth_key(struct snmp_session *s, zend_string *pass)
{
int snmp_errno;

s->securityAuthKeyLen = USM_AUTH_KU_LEN;
if ((snmp_errno = generate_Ku(s->securityAuthProto, s->securityAuthProtoLen,
(uint8_t *) ZSTR_VAL(pass), ZSTR_LEN(pass),
Expand All @@ -1106,7 +1107,7 @@ static bool snmp_session_gen_auth_key(struct snmp_session *s, zend_string *pass)
/* }}} */

/* {{{ Make key from pass phrase in the snmpv3 session */
static bool snmp_session_gen_sec_key(struct snmp_session *s, zend_string *pass)
static ZEND_ATTRIBUTE_NONNULL bool snmp_session_gen_sec_key(struct snmp_session *s, zend_string *pass)
{
int snmp_errno;

Expand Down Expand Up @@ -1145,9 +1146,10 @@ static bool snmp_session_set_contextEngineID(struct snmp_session *s, zend_string
/* }}} */

/* {{{ Set all snmpv3-related security options */
static bool snmp_session_set_security(struct snmp_session *session, zend_string *sec_level,
static ZEND_ATTRIBUTE_NONNULL_ARGS(2) bool snmp_session_set_security(struct snmp_session *session, zend_string *sec_level,
zend_string *auth_protocol, zend_string *auth_passphrase, zend_string *priv_protocol,
zend_string *priv_passphrase, zend_string *contextName, zend_string *contextEngineID)
zend_string *priv_passphrase, zend_string *contextName, zend_string *contextEngineID,
uint32_t auth_protocol_argnum)
{

/* Setting the security level. */
Expand All @@ -1158,25 +1160,46 @@ static bool snmp_session_set_security(struct snmp_session *session, zend_string

if (session->securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {

if (!auth_protocol) {
zend_argument_value_error(auth_protocol_argnum, "cannot be null when security level is \"authNoPriv\" or \"authPriv\"");
return false;
}

/* Setting the authentication protocol. */
if (!snmp_session_set_auth_protocol(session, auth_protocol)) {
/* ValueError already generated, just bail out */
return false;
}

if (!auth_passphrase) {
zend_argument_value_error(auth_protocol_argnum + 1, "cannot be null when security level is \"authNoPriv\" or \"authPriv\"");
return false;
}

/* Setting the authentication passphrase. */
if (!snmp_session_gen_auth_key(session, auth_passphrase)) {
/* Warning message sent already, just bail out */
return false;
}

if (session->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {

if (!priv_protocol) {
zend_argument_value_error(auth_protocol_argnum + 2, "cannot be null when security level is \"authPriv\"");
return false;
}

/* Setting the security protocol. */
if (!snmp_session_set_sec_protocol(session, priv_protocol)) {
/* ValueError already generated, just bail out */
return false;
}

if (!priv_passphrase) {
zend_argument_value_error(auth_protocol_argnum + 3, "cannot be null when security level is \"authPriv\"");
return false;
}

/* Setting the security protocol passphrase. */
if (!snmp_session_gen_sec_key(session, priv_passphrase)) {
/* Warning message sent already, just bail out */
Expand Down Expand Up @@ -1346,7 +1369,7 @@ static void php_snmp(INTERNAL_FUNCTION_PARAMETERS, int st, int version)
snmp_session_free(&session);
RETURN_FALSE;
}
if (version == SNMP_VERSION_3 && !snmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL)) {
if (version == SNMP_VERSION_3 && !snmp_session_set_security(session, a3, a4, a5, a6, a7, NULL, NULL, 4)) {
php_free_objid_query(&objid_query, oid_ht, value_ht, st);
snmp_session_free(&session);
/* Warning message sent already, just bail out */
Expand Down Expand Up @@ -1721,7 +1744,7 @@ PHP_METHOD(SNMP, setSecurity)
RETURN_THROWS();
}

if (!snmp_session_set_security(snmp_object->session, a1, a2, a3, a4, a5, a6, a7)) {
if (!snmp_session_set_security(snmp_object->session, a1, a2, a3, a4, a5, a6, a7, 2)) {
/* Warning message sent already, just bail out */
RETURN_FALSE;
}
Expand Down
41 changes: 41 additions & 0 deletions ext/snmp/tests/gh21336.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
GH-21336 (undefined behavior in snmp - NULL pointer dereference in setSecurity)
--EXTENSIONS--
snmp
--FILE--
<?php
$session = new SNMP(SNMP::VERSION_3, 'localhost', 'user');

// auth protocol NULL
try {
$session->setSecurity('authPriv');
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}

// auth passphrase NULL
try {
$session->setSecurity('authNoPriv', 'MD5');
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}

// priv protocol NULL
try {
$session->setSecurity('authPriv', 'MD5', 'test12345');
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}

// priv passphrase NULL
try {
$session->setSecurity('authPriv', 'MD5', 'test12345', 'AES');
} catch (ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
?>
--EXPECT--
SNMP::setSecurity(): Argument #2 ($authProtocol) cannot be null when security level is "authNoPriv" or "authPriv"
SNMP::setSecurity(): Argument #3 ($authPassphrase) cannot be null when security level is "authNoPriv" or "authPriv"
SNMP::setSecurity(): Argument #4 ($privacyProtocol) cannot be null when security level is "authPriv"
SNMP::setSecurity(): Argument #5 ($privacyPassphrase) cannot be null when security level is "authPriv"