Skip to content

Commit 3946101

Browse files
amn-rtlhefloryd
authored andcommitted
Add a check of received RPC fragment size
The RPC specification says that there is a maximum size of a PDU that can be sent between client and server without further negotiation. This change adds a check of the size of a received PDU and a Reject response when the check fails.
1 parent 18db689 commit 3946101

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

src/device/pf_cmrpc.c

+59-2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@
6161
#error "PNET_MAX_SESSION_BUFFER_SIZE must be less than or equal to 65535"
6262
#endif
6363

64+
/* Unless negotiated between server and client, a CL-PDU (header (80 bytes) +
65+
* body) should not be larger than MustRecvFragSize (1464 bytes). This means
66+
* that a CL-PDU body should not be larger than 1384 bytes.
67+
* (See DCE 1.1: RPC, p. 578)
68+
*/
69+
#define PF_CMRPC_MUST_RECV_FRAG_SIZE (1464)
70+
#define PF_CMRPC_PDU_HEADER_SIZE (80)
71+
#define PF_CMRPC_MAX_PDU_BODY_SIZE \
72+
(PF_CMRPC_MUST_RECV_FRAG_SIZE - PF_CMRPC_PDU_HEADER_SIZE)
73+
6474
static const pf_uuid_t implicit_ar = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
6575

6676
static const pf_uuid_t uuid_epmap_interface = {
@@ -4326,7 +4336,16 @@ static int pf_cmrpc_dce_packet (
43264336
p_sess->get_info = get_info;
43274337
memset (&p_sess->rpc_result, 0, sizeof (p_sess->rpc_result));
43284338

4329-
if (rpc_req.flags.fragment == false)
4339+
if (rpc_req.length_of_body > PF_CMRPC_MAX_PDU_BODY_SIZE)
4340+
{
4341+
LOG_ERROR (
4342+
PF_RPC_LOG,
4343+
"CMRPC(%d): RPC fragment too large (%hu bytes)."
4344+
" Check the conformance of the controller (PLC).\n",
4345+
__LINE__,
4346+
rpc_req.length_of_body);
4347+
}
4348+
else if (rpc_req.flags.fragment == false)
43304349
{
43314350
/* Incoming message is a request or response contained entirely in one
43324351
* frame */
@@ -4438,7 +4457,45 @@ static int pf_cmrpc_dce_packet (
44384457
/* Decide what to do with incoming message */
44394458
/* Enter here _even_if_ an error is already detected because we may need
44404459
* to generate an error response. */
4441-
if (
4460+
if (rpc_req.length_of_body > PF_CMRPC_MAX_PDU_BODY_SIZE)
4461+
{
4462+
/* The specifications do not clearly state what the response should
4463+
* be in this case. The current best guess is to send a Reject PDU.
4464+
*/
4465+
4466+
/* Prepare the response */
4467+
rpc_res = rpc_req;
4468+
rpc_res.packet_type = PF_RPC_PT_REJECT;
4469+
rpc_res.flags.last_fragment = false;
4470+
rpc_res.flags.fragment = false;
4471+
rpc_res.flags.no_fack = true;
4472+
rpc_res.flags.maybe = false;
4473+
rpc_res.flags.idempotent = true;
4474+
rpc_res.flags.broadcast = false;
4475+
rpc_res.flags2.cancel_pending = false;
4476+
rpc_res.length_of_body = sizeof (uint32_t);
4477+
rpc_res.fragment_nmb = 0;
4478+
rpc_res.is_big_endian = p_sess->is_big_endian;
4479+
4480+
pf_put_dce_rpc_header (
4481+
&rpc_res,
4482+
*p_res_len,
4483+
p_res,
4484+
&res_pos,
4485+
&length_of_body_pos);
4486+
4487+
pf_put_uint32 (
4488+
rpc_res.is_big_endian,
4489+
PF_RPC_NCA_PROTO_ERROR,
4490+
*p_res_len,
4491+
p_res,
4492+
&res_pos);
4493+
4494+
pf_cmrpc_send_once_from_buffer (net, p_sess, p_res, res_pos, "REJECT");
4495+
4496+
p_sess->kill_session = is_new_session;
4497+
}
4498+
else if (
44424499
(rpc_req.flags.fragment == false) ||
44434500
(rpc_req.flags.last_fragment == true))
44444501
{

src/pf_types.h

+20
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,26 @@ typedef struct pf_rpc_lookup_req
468468
uint16_t udpPort;
469469
} pf_rpc_lookup_req_t;
470470

471+
typedef enum
472+
{
473+
PF_RPC_NCA_RPC_VERSION_MISMATCH = 0x1C000008,
474+
PF_RPC_NCA_UNSPEC_REJECT = 0x1C000009,
475+
PF_RPC_NCA_S_BAD_ACTID = 0x1C00000A,
476+
PF_RPC_NCA_WHO_ARE_YOU_FAILED = 0x1C00000B,
477+
PF_RPC_NCA_MANAGER_NOT_ENTERED = 0x1C00000C,
478+
PF_RPC_NCA_UNSUPPORTED_AUTHN_LEVEL = 0x1C00001D,
479+
PF_RPC_NCA_INVALID_CHECKSUM = 0x1C00001F,
480+
PF_RPC_NCA_INVALID_CRC = 0x1C000020,
481+
PF_RPC_NCA_OP_RNG_ERROR = 0x1C010002,
482+
PF_RPC_NCA_UNK_IF = 0x1C010003,
483+
PF_RPC_NCA_WRONG_BOOT_TIME = 0x1C010006,
484+
PF_RPC_NCA_S_YOU_CRASHED = 0x1C010009,
485+
PF_RPC_NCA_PROTO_ERROR = 0x1C01000B,
486+
PF_RPC_NCA_OUT_ARGS_TOO_BIG = 0x1C010013,
487+
PF_RPC_NCA_SERVER_TOO_BUSY = 0x1C010014,
488+
PF_RPC_NCA_UNSUPPORTED_TYPE = 0x1C010017
489+
} pf_rpc_nca_reject_status_t;
490+
471491
/************************** Block header *************************************/
472492

473493
typedef enum pf_block_type_values

0 commit comments

Comments
 (0)