Skip to content

Exception function codes are constructed by adding +0x80, which may cause a wrap-around for illegal function codes. #845

@MrAlaskan

Description

@MrAlaskan

Versions

  • OS: Ubuntu 20.04

  • libmodbus: 3.1.12

libmodbus Specific

  • Server: Modbus TCP server (127.0.0.1:1503), receives request with modbus_receive() and replies by modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_ILLEGAL_FUNCTION).

  • Client: Modbus TCP client sends raw illegal function 0x83 via modbus_send_raw_request_tid.

Description

I was testing exception response construction for invalid function values in modbus_reply_exception.

Current implementation uses arithmetic addition:

  • sft.function = function + 0x80; (in src/modbus.c)
    Per the Modbus protocol, exception function codes are formed by setting the highest bit (bit 8) of the request to 1 (bitwise OR | 0x80). However, the code uses arithmetic addition (+ 0x80) at modbus.c. For request function 0x83, the computed value becomes 0x103 and is truncated to 0x03 in an 8-bit response byte.

This makes an exception response function code look like a normal function code (0x03), while the next byte is still exception code 0x01, causing protocol semantic confusion.

Code and Logs

/* Root cause snippet: src/modbus.c */
sft.slave = slave;
sft.function = function + 0x80;
sft.t_id = ctx->backend->get_response_tid(req);
rsp_length = ctx->backend->build_response_basis(&sft, rsp);

/* PoC server snippet */
modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_ILLEGAL_FUNCTION);

/* PoC client snippet */
uint8_t raw_req[2] = {1, 0x83};
modbus_send_raw_request_tid(ctx, raw_req, 2, 1);

$ ./server
Starting Modbus TCP server for exception function wrap-around PoC...
Client connection accepted from 127.0.0.1.
Waiting for an indication...
<00><01><00><00><00><02><01><83>
Received one request, sending exception with modbus_reply_exception.
[00][01][00][00][00][03][01][03][01]
Exception reply sent.

$ ./client
Connecting to 127.0.0.1:1503
[00][01][00][00][00][02][01][83]
Received 9 bytes.
Raw response: 00 01 00 00 00 03 01 03 01
Response function byte: 0x03
Response next byte: 0x01

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions