Segmentation fault during initialize for MD5 for SNMP++ 3.5.1 and Agent++4.6.1

Hi,

Do you have any ideas why we have “Segmentation fault” during initialize for MD5? I tried to increase DEBUG level but I only saw some instances of Adding User (unsecureUser). There was no instances of Adding User (MD5).

agent+±4.6.1\examples\multi_agent\src\agent.cpp

v3MP *v3mp = mib.get_request_list()->get_v3mp();
UsmUserTable *uut = new UsmUserTable(v3mp);

uut->addNewRow("unsecureUser",
               SNMP_AUTHPROTOCOL_NONE,
               SNMP_PRIVPROTOCOL_NONE, "", "", engineID, false);

uut->addNewRow("MD5",
               SNMP_AUTHPROTOCOL_HMACMD5,
               SNMP_PRIVPROTOCOL_NONE,
               "MD5UserAuthPassword", "", engineID, false);

Thanks,
Phuoc

I assume that you have not created the vSMP object, right?

Hi, I had created the vSMP. As far as I know, the SNMP++ 3.5.1 and Agent++ 4.6.1 are working fine on other servers. I only had “Segmentation fault” during initialize for MD5 on 1 server. I also tried to comment out all the MD5 and it could run. I looked at the SNMP++ API and AuthMD5::password_to_key will take the input password and the input engine_id to generate the key. I’m using the default constant password “MD5UserAuthPassword” from agent++ -4.6.1\examples\multi_agent\src\agent.cpp and it is working fine on other servers. So I think maybe there are some issues with the engine ID or something. From debug log, the engine_id is 13 bytes = 0x80, 0x00, 0x13, 0x70, 0x05, 0x61, 0x77, 0x73, 0x73, 0x69, 0x6D, 0x12, 0x62. Is it a good engine_id? I saw other working servers have 20 or 30 bytes for engine_id.

The engine ID is ok, I doubt that this could be the cause.
Is the binary compiled on the failing system?
Maybe the compiler settings between SNMP++ and AGENT++ are inconsistent?
Are you using autoconf or cmake?

Hi, I used cmake to compile both SNMP++ 3.5.1 and Agent++ 4.6.1 and ran all tests on 20 bytes engine ID server. I dropped the libsnmp++.so.35 and libagent++.so.46 into 30 bytes engine ID server and everything is working fine. However, when I dropped the same libsnmp++.so.35 and libagent++.so.46 into 13 bytes engine ID server, I had “Segmentation fault” during initialize for MD5. All 3 servers are linux Red Hat 8.x. I also tried to compile (cmake) both SNMP++ 3.5.1 and Agent++ 4.6.1 in GitLab linux Redhat 8.x runner and behavior is the same. I thought maybe there are some missing so files on 13 bytes engine ID server so I tried linux “ldd” command to verify but they are looking good.
ldd_snmp
ldd_agent
I don’t know what else I need to check or what might cause the MD5 Segmentation fault issue.

Hi,

I had a look at the function AuthMD5::password_to_key() and there is one possible cause for a segmentation fault: If the engine id violates the SNMP standard and is longer than 32 bytes.

To find out the reason for the crash you will have to enable debugging information (-g) when compiling snmp++/agent++ and your agent. So you will get the line number of the crash within auth_priv.cpp and you can print the content of each variable.

Best regards,
Jochen

Hi,
After enabled debugging -DCMAKE_BUILD_TYPE=Debug both SNMP++ 3.5.1 and Agent++ 4.6.1, somehow the debug log displays 20 bytes hex but backtrace shows engine_id=“\200” with correct engine_id_len=20. Seems like it was failed in MD5_PROCESS(&md5_hash_state, password_buf, 64);

We had debug log
password: MD5UserAuthPassword.
engineID: 80 00 13 70 05 64 65 76 73 69 6C 2D 6C 69 6E 2D 30 31 12 60

We had backtrace
#0 0x0000000000000000 in ?? ()

#1 0x00007fffee9d18ba in Snmp_pp::AuthMD5::password_to_key (this=0x7fff900020e0, password=0x7fff9002e550 “MD5UserAuthPassword”, password_len=19, engine_id=0x7fff90001390 “\200”, engine_id_len=20, key=0x7ffff7ee53e0 “”, key_len=0x7ffff7ee53dc) at auth_priv.cpp:1185

#2 0x00007fffee9d0932 in Snmp_pp::AuthPriv::password_to_key_auth (this=0x7fff90001f50, auth_prot=2, password=0x7fff9002e550 “MD5UserAuthPassword”, password_len=19, engine_id=0x7fff90001390 “\200”, engine_id_len=20, key=0x7ffff7ee53e0 “”, key_len=0x7ffff7ee53dc) at auth_priv.cpp:818

#3 0x00007fffee264cd9 in Agentpp::UsmUserTable::addNewRow (this=0x7fff9002ced0, userName=…, securityName=…, authProtocol=2, privProtocol=1, authPassword=…, privPassword=…, engineID=…, addPassWordsToUSM=false) at v3_mib.cpp:661
#4 0x00007fffcb2ca179 in init(Agentpp::Mib&, Snmp_pp::OctetStr const&, Snmp_pp::UdpAddress const&) ()

Note:
auth_priv.cpp:1185
MD5_PROCESS(&md5_hash_state, password_buf, 64);

auth_priv.cpp:818
int res = a->password_to_key(password, password_len,
engine_id, engine_id_len,
key, key_len);

v3_mib.cpp:661
int res = usm->get_auth_priv()->password_to_key_auth(
authProtocol,
authPassword.data(),
authPassword.len(),
engineID.data(), engineID.len(),
authKey, &authKeyLength);

Hi, now my guess would be that something is different for the used Openssl libraries (e.g. FIPS mode). Can you verify that on both servers the used /lib64/libssl.so.1.1 and /lib64/libcrypto.so.1.1 are identical? Do openssl version -a or openssl dgst -list show any differences?

The function in #0 should be EVP_DigestUpdate() from Openssl, so this looks strange. In #1, does the var md5_hash_state look ok? What are the values for count and password_index?

Can you modify the function to include the following line and print out, if the returned value is NULL or not:
const EVP_MD *test_val = EVP_md5();

Best regards,
Jochen

Hi, the libssl.so.1.1 and the libcrypto.so.1.1 are identical since I’m using only 1 container image on all servers. I already verified them using your commands.

test_val returned a valid pointer.
(gdb) print test_val
$1 = (const EVP_MD *) 0x7fffee96ea00
(gdb) x/16x test_val
0x7fffee96ea00: 0x00000004 0x00000008 0x00000010 0x00000000
0x7fffee96ea10: 0x00000000 0x00000000 0xee61e900 0x00007fff
0x7fffee96ea20: 0xee61e8d0 0x00007fff 0xee61e8b0 0x00007fff
0x7fffee96ea30: 0x00000000 0x00000000 0x00000000 0x00000000

The value for count is 0 and the value for password_index is 64
(gdb) info local
cp = 0x7ffff7f29230 “\240\375\002\240\377\177”
test_val = 0x7fffee96ea00
md5_hash_state = 0x7fffa002f6a0
password_buf = “MD5UserAuthPasswordMD5UserAuthPasswordMD5UserAuthPasswordMD5User\240”
password_index = 64
count = 0

The variable md5_hash_state is NOT NULL but behaviors are different on NOT working server.
Before MD5_INT, md5_hash_state memory address has !0x00000000 on NOT working server
(gdb) print md5_hash_state
$2 = (Snmp_pp::MD5HashStateType) 0x7ffff7f29280
(gdb) x/16x md5_hash_state
0x7ffff7f29280: 0xeec1f238 0x00007fff 0x00000004 0x00000000
0x7ffff7f29290: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff7f292a0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff7f292b0: 0x00000000 0x00007f2e 0x00000001 0x00000001

During MD5_INIT(&md5_hash_state); /* initialize MD5 */
int evpAllocAndInit(EVP_MD_CTX **ctx, const EVP_MD *md)
{
*ctx = EVP_MD_CTX_new();
return EVP_DigestInit(*ctx, md);
}
(gdb) print ctx
$3 = (EVP_MD_CTX **) 0x7ffff7f29238
(gdb) x/16x ctx
0x7ffff7f29238: 0xa002f6a0 0x00007fff 0xeec1f238 0x00007fff
0x7ffff7f29248: 0x00000004 0x00000000 0x00000000 0x00000000
0x7ffff7f29258: 0x00000000 0x00000000 0x00000000 0x00000000
0x7ffff7f29268: 0x00000000 0x00007f00 0xf7f29950 0x00007fff
(gdb) print md
$4 = (const EVP_MD *) 0x7fffee96ea00
(gdb) x/16x md
0x7fffee96ea00: 0x00000004 0x00000008 0x00000010 0x00000000
0x7fffee96ea10: 0x00000000 0x00000000 0xee61e900 0x00007fff
0x7fffee96ea20: 0xee61e8d0 0x00007fff 0xee61e8b0 0x00007fff
0x7fffee96ea30: 0x00000000 0x00000000 0x00000000 0x00000000

After MD5_INIT, somehow md5_hash_state memory address has 0x00000000 on NOT working server
gdb) print md5_hash_state
$5 = (Snmp_pp::MD5HashStateType) 0x7fffa002f6a0
(gdb) x/16x md5_hash_state
0x7fffa002f6a0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffa002f6b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffa002f6c0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffa002f6d0: 0xa002f501 0x00007fff 0x00000105 0x00000000

Note: After MD5_INIT, the md5_hash_state memory address has some !0x00000000 values in working servers. I did step through auth_priv.cpp the code and saw it called the same function.
int evpAllocAndInit(EVP_MD_CTX **ctx, const EVP_MD *md)
{
*ctx = EVP_MD_CTX_new();
return EVP_DigestInit(*ctx, md);
}
(gdb) print md5_hash_state
$5 = (Snmp_pp::MD5HashStateType) 0x7f8e1c0301a0
(gdb) x/16x md5_hash_state
0x7f8e1c0301a0: 0x74d13a00 0x00007f8e 0x00000000 0x00000000
0x7f8e1c0301b0: 0x00000000 0x00000000 0x1c024b50 0x00007f8e
0x7f8e1c0301c0: 0x00000000 0x00000000 0x749c38d0 0x00007f8e
0x7f8e1c0301d0: 0x1c030001 0x00007f8e 0x00000105 0x00000000

I don’t know it was failed “Segmentation fault” in MD5_PROCESS(&md5_hash_state, password_buf, 64); as (gdb) x/16x md5_hash_state 0x7fffa002f6a0: 0x00000000 0x00000000 0x00000000 0x00000000 or something else.

Hi, as you wrote that snmp++/agent++ is running inside a container, this is getting really strange. MD5 seems to be enabled in OpenSSL. To further analyze this, please change the call to MD5_INIT(s); (which is in fact a call to evpAllocAndInit(s, EVP_md5()) to int init_result = MD5_INIT(s);. Does this call return 1 for success?

If it returns success, I would like to know if the SHA1 hashing is working. Add the following code somewhere before the users are created:

     USM *usm = v3_MP->get_usm();
     AuthPriv *auth_priv = usm->get_auth_priv();
     unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
     OctetStr input = "abc"; 

     Auth *auth = auth_priv->get_auth(SNMP_AUTHPROTOCOL_HMACSHA);
     debugprintf(0, "Name of auth protocol: %s", auth->get_id_string());
     auth->hash(input.data(), input.len(), digest);
     debughexcprintf(1, "Hash", digest, auth->get_hash_len()); // "a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d"

     auth = auth_priv->get_auth(SNMP_AUTHPROTOCOL_HMACMD5);
     debugprintf(0, "Name of auth protocol: %s", auth->get_id_string());
     auth->hash(input.data(), input.len(), digest);
     debughexcprintf(1, "Hash", digest, auth->get_hash_len()); // Output: "900150983cd24fb0d6963f7d28e17f72"

Best regards,
Jochen

Hi,
int init_result = MD5_INIT(s); → return 0

SHA1 is working fine.
20241119.18:10:09: 140737353402112: (1)DEBUG : Name of auth protocol: HMAC-SHA
20241119.18:10:09: 140737353402112: (1)DEBUG : Hash (length 20):
20241119.18:10:09: 140737353402112: (1)DEBUG : A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C
20241119.18:10:09: 140737353402112: (1)DEBUG : 9C D0 D8 9D

MD5 got “Segmentation fault” at line 1318: MD5_PROCESS(&md5_hash_state, data, data_len); in int AuthMD5::hash(const unsigned char *data, const unsigned int data_len, unsigned char *digest) const
20241119.18:10:09: 140737353402112: (1)DEBUG : Name of auth protocol: HMAC-MD5
#0 0x0000000000000000 in ?? ()
#1 0x00007fffee9d2528 in Snmp_pp::AuthMD5::hash (this=0x7fffac002d70, data=0x7fffac02cb80 “abc\377\a”, data_len=3,
digest=0x7ffff7f29570 “\251\231>6G\006\201j\272>%qxP\302l\234\320\330\235”)
at /auth_priv.cpp:1318
#2 0x00007fffcb2cd4d1 in init(Agentpp::Mib&, Snmp_pp::OctetStr const&, Snmp_pp::UdpAddress const&) ()

Hi,

if init_result is 0, then OpenSSL failed to initialize the structure and so the later usage will crash the application. So I will check all calls of auth_priv.cpp to OpenSSL and return errors instead of crashing. But this does not solve your issue.

To sum up:

  • Three servers, all use the same container image
  • Two of them are working and one fails to initialize MD5 hash structure but can initialize SHA1.
  • OpenSSL version used: I guessed from libssl.so.1.1 that it is a 1.1.x

Maybe you can use ERR_get_error() to get the OpenSSL error code and maybe it shows the reason.

Best regards,
Jochen