bhuvan-somisetty opened a new issue, #13952:
URL: https://github.com/apache/apisix/issues/13952

   ### Current Behavior
   
   The `mqtt-proxy` stream plugin can throw an unhandled Lua runtime error 
while parsing the CONNECT packet, instead of rejecting the connection with a 
503 like it does for every other malformed-packet case.
   
   The problem is in `decode_variable_byte_int()` in 
`apisix/stream/plugins/mqtt-proxy.lua`:
   
   ```lua
   local function decode_variable_byte_int(data, offset)
       local multiplier = 1
       local len = 0
       local pos
       for i = offset, offset + 3 do
           pos = i
           local byte = str_byte(data, i, i)
           len = len + bit.band(byte, 127) * multiplier
           multiplier = multiplier * 128
           if bit.band(byte, 128) == 0 then
               break
           end
       end
   
       return len, pos
   end
   ```
   
   It loops up to 4 bytes reading `str_byte(data, i, i)` but never checks that 
`i` is still inside `data`. This function is used to decode the MQTT v5 
"Properties Length" field (`parse_mqtt`, line 103), and unlike the client-ID 
length handling a few lines below it (which correctly checks `parsed_pos + 
client_id_len > #data` and bails out), there's no equivalent bounds check here.
   
   If the properties-length bytes have the continuation bit (0x80) set all the 
way to the end of the buffer that was peeked from the socket, `str_byte` 
returns nothing for the out-of-range index, so `byte` is `nil`, and 
`bit.band(nil, 127)` raises a runtime error. This happens inside the `preread` 
phase, so the connection doesn't get the plugin's normal `core.log.error(...); 
return 503` treatment - it just errors out.
   
   ### Expected Behavior
   
   A malformed/truncated MQTT v5 properties length should be handled the same 
way the rest of this parser handles malformed input - log an error and return 
503 - not raise an uncaught Lua error.
   
   ### Error Logs
   
   ```
   bad argument #1 to 'band' (number expected, got nil)
   ```
   (raised from `bit.band(byte, 127)` inside `decode_variable_byte_int`, 
`apisix/stream/plugins/mqtt-proxy.lua:62`)
   
   ### Steps to Reproduce
   
   1. Configure a stream route with the `mqtt-proxy` plugin (`protocol_name = 
"MQTT"`, `protocol_level = 5`) in front of any upstream.
   2. Open a raw TCP connection to the route and send this 14-byte MQTT v5 
CONNECT packet (hex):
   
   ```
   10 0c 00 04 4d 51 54 54 05 02 00 3c 80 80
   ```
   
   Breaking it down:
   - `10` - CONNECT packet type
   - `0c` - Remaining Length = 12
   - `00 04 4d 51 54 54` - protocol name length (4) + "MQTT"
   - `05` - protocol version 5 (MQTT v5, so the properties field gets parsed)
   - `02 00 3c` - connect flags + keepalive (skipped)
   - `80 80` - properties length field, both bytes have the continuation bit 
set, and the buffer ends right there
   
   3. `decode_variable_byte_int` walks past the end of the 14-byte buffer 
trying to read a third properties-length byte and errors instead of returning 
503.
   
   I checked the two mqtt-proxy test files (`t/stream-plugin/mqtt-proxy.t`, 
`t/stream-plugin/mqtt-proxy2.t`) and none of the existing cases cover a 
properties length whose continuation bytes run past the end of the peeked data, 
so this isn't caught by CI right now.
   
   ### Environment
   
   - APISIX version: master (current HEAD around 3.18)
   - Operating system: N/A (code-level issue, not environment specific)
   - OpenResty / Nginx version: N/A
   - etcd version, if relevant: N/A
   - APISIX Dashboard version, if relevant: N/A
   - Plugin runner version, for issues related to plugin runners: N/A
   - LuaRocks version, for installation issues: N/A
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to