Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
slplink: fix buffer overflow vulnerability
The issue stems from the fact that the body of an SLP message can have a different length than what the header claims. You make the check if (msg->msnslp_header.total_size < msg->msnslp_header.length) which uses declared length of the packet in the SLP header; however, the variable len does not originate from msg->msnslp_header.length, but is rather computed in msn_message_parse_payload and msn_message_parse_slp_body. No checks are made to ensure that msg->body_len == msg->msnslp_header.length. Thus, the vulnerability in question revolves around the situation in which len == msg->body_len > msg->msnslp_header.length As such, a malicious program can construct a SLP message sequence in the following manner: Send a new incomplete SLP message in which msnslp_header.session_id=SESSION_ID, msnslp_header.id=MESSAGE_ID, msnslp_header.offset = 0, and msnslp_header.length < msnslp_header.total_size. The SLP message is incomplete, which allows the attacker to send a second packet with a non-zero offset. For the purposes of this example, assume msnslp_header.length = 5 and msnslp_header.total_size = 10. Send the second message with same session and message ids msnslp_header.session_id=SESSION_ID, msnslp_header.id=MESSAGE_ID. However, send more data in the payload than the header specifies. For the purposes of the example, let us say msnslp_header.length = 5 and msnslp_header.total_size = 10 again, but this time the SLP message body is longer than the header specifies and contains a 1KiB of malicious data Thus msn_message_get_bin_data will set len = 1024. Furthermore, let us assume the attacker chooses offset = -2048 == 0xfffffffffffff800. The check performed is then evaluated as this: if ((gsize)offset > ((long long)slpmsg->size - (gsize)len)) On a system where gsize is 32 bits, offset gets truncated to 32 bits and this evaluates to if((gsize)0xfffff800 > (long long)-1014). 0xfffff800 is then implicitly converted back to a positive 64-bit integer, because an unsigned 32-bit value fits within the range of a signed 64-bit value, and the check works because the unsigned offset correctly doesn't get sign-extended. However, on a system where gsize and long long is 64 bits, this evaluates to if((gsize)0xfffffffffffff800 > (long long)-1014), the full untruncated offset specified in the packet. In this case, we have a 64-bit unsigned vs 64-bit signed comparison that GCC doesn't produce a warning for. Regardless of whether the compiler treats the result as signed or unsigned, the check is bypassed. 0xfffffffffffff800 > 0xfffffffffffffc0a and -2048 > -1014 are both false. Thus the memcpy line executes, writing the malicious data to buffer - 2048, well outside the 10 byte buffer allocated. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
- Loading branch information