|
61 | 61 | #error "PNET_MAX_SESSION_BUFFER_SIZE must be less than or equal to 65535"
|
62 | 62 | #endif
|
63 | 63 |
|
| 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 | + |
64 | 74 | static const pf_uuid_t implicit_ar = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
|
65 | 75 |
|
66 | 76 | static const pf_uuid_t uuid_epmap_interface = {
|
@@ -4326,7 +4336,16 @@ static int pf_cmrpc_dce_packet (
|
4326 | 4336 | p_sess->get_info = get_info;
|
4327 | 4337 | memset (&p_sess->rpc_result, 0, sizeof (p_sess->rpc_result));
|
4328 | 4338 |
|
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) |
4330 | 4349 | {
|
4331 | 4350 | /* Incoming message is a request or response contained entirely in one
|
4332 | 4351 | * frame */
|
@@ -4438,7 +4457,45 @@ static int pf_cmrpc_dce_packet (
|
4438 | 4457 | /* Decide what to do with incoming message */
|
4439 | 4458 | /* Enter here _even_if_ an error is already detected because we may need
|
4440 | 4459 | * 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 ( |
4442 | 4499 | (rpc_req.flags.fragment == false) ||
|
4443 | 4500 | (rpc_req.flags.last_fragment == true))
|
4444 | 4501 | {
|
|
0 commit comments