Skip to content

Commit ce9bdd5

Browse files
committed
daemon: parse incrementally in dlt_daemon_control_set_trace_status_v2
Rewrite the handler to parse the GET request field-by-field instead of casting msg->databuffer directly to DltServiceSetLogLevelV2 *. The struct has char *apid / char *ctid pointer fields, so a direct cast filled them with attacker-controlled values from network input that were then dereferenced — and the old code also hit the same NULL-deref pattern as COVESA#863. Add bounds checks for the two attacker-controlled length fields so the variable-length reads stay within msg->databuffer. Copy the apid/ctid into local fixed-size buffers through the shared dlt_set_id_v2() helper and point apid/ctid at those buffers, keeping id initialisation inside the helper API rather than aliasing the receive buffer (consistent with COVESA#864/COVESA#868/COVESA#861). Related: COVESA#866. Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
1 parent fd1fbf8 commit ce9bdd5

1 file changed

Lines changed: 73 additions & 29 deletions

File tree

src/daemon/dlt_daemon_client.c

Lines changed: 73 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4027,84 +4027,128 @@ void dlt_daemon_control_set_trace_status_v2(int sock,
40274027

40284028
char *apid = NULL;
40294029
char *ctid = NULL;
4030-
DltServiceSetLogLevelV2 *req = NULL;
4030+
char apid_buf[DLT_V2_ID_SIZE] = {0};
4031+
char ctid_buf[DLT_V2_ID_SIZE] = {0};
40314032
DltDaemonContext *context = NULL;
4032-
int8_t apid_length = 0;
4033-
int8_t ctid_length = 0;
4033+
uint32_t service_id = 0;
4034+
uint8_t apidlen = 0;
4035+
uint8_t ctidlen = 0;
4036+
uint8_t log_level = 0;
4037+
int offset = 0;
40344038

40354039
if ((daemon == NULL) || (msg == NULL) || (msg->databuffer == NULL))
40364040
return;
40374041

4038-
//TBD: Review sizeof(DltServiceSetLogLevelV2)) or fixed size
4039-
if (dlt_check_rcv_data_size(msg->datasize, sizeof(DltServiceSetLogLevelV2)) < 0)
4042+
if (dlt_check_rcv_data_size(msg->datasize, DLT_SERVICE_SET_LOG_LEVEL_FIXED_SIZE_V2) < 0)
40404043
return;
40414044

4042-
req = (DltServiceSetLogLevelV2 *)(msg->databuffer);
4045+
/* Parse wire bytes incrementally instead of casting msg->databuffer to
4046+
* DltServiceSetLogLevelV2 *. The struct contains char *apid / char *ctid
4047+
* pointer fields. Under a direct cast those fields would have been
4048+
* filled with attacker-controlled pointer values from network input,
4049+
* then dereferenced by dlt_set_id_v2 — an arbitrary memory read. The
4050+
* previous code also fell into the same NULL-deref pattern as #863
4051+
* (apid / ctid NULL when used at apid[apid_length - 1] etc.).
4052+
* See #866 for the broader pattern. */
4053+
memcpy(&service_id, msg->databuffer + offset, sizeof(uint32_t));
4054+
offset = offset + (int)sizeof(uint32_t);
4055+
memcpy(&apidlen, msg->databuffer + offset, sizeof(uint8_t));
4056+
offset = offset + (int)sizeof(uint8_t);
40434057

4044-
if (daemon_local->flags.enforceContextLLAndTS)
4045-
req->log_level = (uint8_t) getStatus(req->log_level, daemon_local->flags.contextTraceStatus);
4058+
/* Bounds check for apid (apidlen bytes) + the upcoming ctidlen byte.
4059+
* The fixed-size precheck at the top only validates the empty case. */
4060+
if ((offset + (int)apidlen + (int)sizeof(uint8_t)) > msg->datasize)
4061+
return;
40464062

4047-
apid_length = (int8_t) req->apidlen;
4048-
dlt_set_id_v2(apid, req->apid, req->apidlen);
4049-
ctid_length = (int8_t) req->ctidlen;
4050-
dlt_set_id_v2(ctid, req->ctid, req->ctidlen);
4063+
/* Copy the variable-length apid into a local fixed-size buffer through the
4064+
* dlt_set_id_v2() helper rather than aliasing the receive buffer, keeping
4065+
* id initialisation inside the shared API. */
4066+
if (apidlen > 0) {
4067+
dlt_set_id_v2(apid_buf, (const char *)(msg->databuffer + offset), apidlen);
4068+
apid = apid_buf;
4069+
offset = offset + (int)apidlen;
4070+
}
4071+
memcpy(&ctidlen, msg->databuffer + offset, sizeof(uint8_t));
4072+
offset = offset + (int)sizeof(uint8_t);
40514073

4052-
//TBD: Review apid[apid_length - 1] == '*'
4053-
if ((apid_length != 0) && (apid[apid_length - 1] == '*') && (ctid == NULL)) { /*apid provided having '*' in it and ctid is null*/
4074+
/* Bounds check for ctid (ctidlen bytes) + log_level (1 byte) +
4075+
* the trailing com field (DLT_ID_SIZE bytes). */
4076+
if ((offset + (int)ctidlen + (int)sizeof(uint8_t) + DLT_ID_SIZE) > msg->datasize)
4077+
return;
4078+
4079+
if (ctidlen > 0) {
4080+
dlt_set_id_v2(ctid_buf, (const char *)(msg->databuffer + offset), ctidlen);
4081+
ctid = ctid_buf;
4082+
offset = offset + (int)ctidlen;
4083+
}
4084+
memcpy(&log_level, msg->databuffer + offset, sizeof(uint8_t));
4085+
4086+
if (daemon_local->flags.enforceContextLLAndTS)
4087+
log_level = (uint8_t) getStatus(log_level, daemon_local->flags.contextTraceStatus);
4088+
4089+
/* Use unsigned widths throughout. Casting uint8_t apidlen / ctidlen
4090+
* to int8_t (as the previous code did) would produce a negative value
4091+
* when the length exceeds 127, underflowing apid[apid_length - 1] etc.
4092+
* Note: downstream helpers below still take int8_t lengths; that
4093+
* narrowing remains a separate latent issue, out of scope here. */
4094+
if ((apidlen != 0) && (apid != NULL) && (apid[apidlen - 1] == '*') && (ctid == NULL)) {
4095+
/* apid provided having '*' in it and ctid is null */
40544096
dlt_daemon_find_multiple_context_and_send_trace_status_v2(sock,
40554097
daemon,
40564098
daemon_local,
40574099
1,
40584100
apid,
4059-
(int8_t) (apid_length - 1),
4060-
(int8_t) req->log_level,
4101+
(int8_t) (apidlen - 1),
4102+
(int8_t) log_level,
40614103
verbose);
40624104
}
4063-
else if ((ctid_length != 0) && (ctid[ctid_length - 1] == '*') && (apid == NULL)) /*ctid provided is having '*' in it and apid is null*/
4064-
4105+
else if ((ctidlen != 0) && (ctid != NULL) && (ctid[ctidlen - 1] == '*') && (apid == NULL))
40654106
{
4107+
/* ctid provided is having '*' in it and apid is null */
40664108
dlt_daemon_find_multiple_context_and_send_trace_status_v2(sock,
40674109
daemon,
40684110
daemon_local,
40694111
0,
40704112
ctid,
4071-
(int8_t) (ctid_length - 1),
4072-
(int8_t) req->log_level,
4113+
(int8_t) (ctidlen - 1),
4114+
(int8_t) log_level,
40734115
verbose);
40744116
}
4075-
else if ((apid_length != 0) && (apid[apid_length - 1] != '*') && (ctid == NULL)) /*only app id case*/
4117+
else if ((apidlen != 0) && (apid != NULL) && (apid[apidlen - 1] != '*') && (ctid == NULL))
40764118
{
4119+
/* only app id case */
40774120
dlt_daemon_find_multiple_context_and_send_trace_status_v2(sock,
40784121
daemon,
40794122
daemon_local,
40804123
1,
40814124
apid,
4082-
apid_length,
4083-
(int8_t) req->log_level,
4125+
(int8_t) apidlen,
4126+
(int8_t) log_level,
40844127
verbose);
40854128
}
4086-
else if ((ctid_length != 0) && (ctid[ctid_length - 1] != '*') && (apid == NULL)) /*only context id case*/
4129+
else if ((ctidlen != 0) && (ctid != NULL) && (ctid[ctidlen - 1] != '*') && (apid == NULL))
40874130
{
4131+
/* only context id case */
40884132
dlt_daemon_find_multiple_context_and_send_trace_status_v2(sock,
40894133
daemon,
40904134
daemon_local,
40914135
0,
40924136
ctid,
4093-
ctid_length,
4094-
(int8_t) req->log_level,
4137+
(int8_t) ctidlen,
4138+
(int8_t) log_level,
40954139
verbose);
40964140
}
40974141
else {
4098-
context = dlt_daemon_context_find_v2(daemon, (uint8_t)apid_length, apid, (uint8_t)ctid_length, ctid, daemon->ecuid2len, daemon->ecuid2, verbose);
4142+
context = dlt_daemon_context_find_v2(daemon, apidlen, apid, ctidlen, ctid, daemon->ecuid2len, daemon->ecuid2, verbose);
40994143

41004144
/* Set trace status */
41014145
if (context != 0) {
4102-
dlt_daemon_send_trace_status_v2(sock, daemon, daemon_local, context, (int8_t) req->log_level, verbose);
4146+
dlt_daemon_send_trace_status_v2(sock, daemon, daemon_local, context, (int8_t) log_level, verbose);
41034147
}
41044148
else {
41054149
dlt_vlog(LOG_ERR,
41064150
"Could not set trace status: %d. Context [%.4s:%.4s] not found:",
4107-
req->log_level,
4151+
log_level,
41084152
apid ? apid : "<NULL>",
41094153
ctid ? ctid : "<NULL>");
41104154
dlt_daemon_control_service_response_v2(sock,

0 commit comments

Comments
 (0)