Commit 48faffc1 authored by Robert Schmidt's avatar Robert Schmidt

dump_mac_stats(): avoid overflow

The call to snprintf() as was used is wrong: we use the return value to
advance output, but the man page says

> The functions snprintf() and vsnprintf() do not write more than size
> bytes (including the terminating null byte ('\0')).  If the output was
> truncated due  to this  limit,  then  the return value is the number of
> characters (excluding the terminating null byte) which would have been
> written to  the  final  string  if enough  space  had  been available.
> Thus, a return value of size or more means that the output was
> truncated.

Thus, output could go beyond end, and we get a stack overflow. Instead,
encapsulate the call to snprintf() checking this condition, and only
advancing output as intended, limiting to 0 if we are at the end of the
buffer.  This avoids this error:

    ==964825==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7be799f51988 at pc 0x7fe7d66b0d39 bp 0x7be79b825ef0 sp 0x7be79b8256c0
    WRITE of size 3 at 0x7be799f51988 thread T24
        #0 0x7fe7d66b0d38 in vsnprintf (/lib64/libasan.so.8+0xb0d38) (BuildId: 10b8ccd49f75c21babf1d7abe51bb63589d8471f)
        #1 0x7fe7d66b2d44 in snprintf (/lib64/libasan.so.8+0xb2d44) (BuildId: 10b8ccd49f75c21babf1d7abe51bb63589d8471f)
        #2 0x0000008fe7c6 in dump_mac_stats /home/richie/w/refactor-dlsch/openair2/LAYER2/NR_MAC_gNB/main.c:183
        #3 0x00000092071a in gNB_dlsch_ulsch_scheduler /home/richie/w/refactor-dlsch/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c:200
        #4 0x0000008f8f78 in run_scheduler_monolithic /home/richie/w/refactor-dlsch/openair2/NR_PHY_INTERFACE/NR_IF_Module.c:399
parent 7df8243a
...@@ -118,6 +118,19 @@ void clear_mac_stats(gNB_MAC_INST *gNB) { ...@@ -118,6 +118,19 @@ void clear_mac_stats(gNB_MAC_INST *gNB) {
} }
} }
static char *st_append(char *start, const char *end, const char *format, ...)
{
size_t space = end - start;
va_list args;
va_start(args, format);
size_t written = vsnprintf(start, space, format, args);
va_end(args);
if (written <= space)
return start + written;
else
return (char *)end;
}
size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp) size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp)
{ {
const char *begin = output; const char *begin = output;
...@@ -133,39 +146,39 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset ...@@ -133,39 +146,39 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0;
const int avg_sinrx10 = stats->num_sinr_meas > 0 ? stats->cumul_sinrx10 / stats->num_sinr_meas : 0; const int avg_sinrx10 = stats->num_sinr_meas > 0 ? stats->cumul_sinrx10 / stats->num_sinr_meas : 0;
output += snprintf(output, end - output, "UE RNTI %04x CU-UE-ID ", UE->rnti); output = st_append(output, end, "UE RNTI %04x CU-UE-ID ", UE->rnti);
if (du_exists_f1_ue_data(UE->rnti)) { if (du_exists_f1_ue_data(UE->rnti)) {
f1_ue_data_t ued = du_get_f1_ue_data(UE->rnti); f1_ue_data_t ued = du_get_f1_ue_data(UE->rnti);
output += snprintf(output, end - output, "%d", ued.secondary_ue); output = st_append(output, end, "%d", ued.secondary_ue);
} else { } else {
output += snprintf(output, end - output, "(none)"); output = st_append(output, end, "(none)");
} }
bool in_sync = !sched_ctrl->ul_failure; bool in_sync = !sched_ctrl->ul_failure;
output += snprintf(output, output = st_append(output,
end - output, end,
" %s PH %d dB PCMAX %d dBm", " %s PH %d dB PCMAX %d dBm",
in_sync ? "in-sync" : "out-of-sync", in_sync ? "in-sync" : "out-of-sync",
sched_ctrl->ph, sched_ctrl->ph,
sched_ctrl->pcmax); sched_ctrl->pcmax);
if (stats->num_rsrp_meas) if (stats->num_rsrp_meas)
output += snprintf(output, end - output, ", average RSRP %d (%d meas)", avg_rsrp, stats->num_rsrp_meas); output = st_append(output, end, ", average RSRP %d (%d meas)", avg_rsrp, stats->num_rsrp_meas);
if (stats->num_sinr_meas) { if (stats->num_sinr_meas) {
output += snprintf(output, output = st_append(output,
end - output, end,
", average SINR %d.%d (%d meas)", ", average SINR %d.%d (%d meas)",
avg_sinrx10 / 10, avg_sinrx10 / 10,
avg_sinrx10 % 10, avg_sinrx10 % 10,
stats->num_sinr_meas); stats->num_sinr_meas);
} }
output += snprintf(output, end - output, "\n"); output = st_append(output, end, "\n");
if(sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report) if(sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report)
output += snprintf(output, output = st_append(output,
end - output, end,
"UE %04x: CQI %d, RI %d, PMI (%d,%d)\n", "UE %04x: CQI %d, RI %d, PMI (%d,%d)\n",
UE->rnti, UE->rnti,
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb, sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb,
...@@ -174,18 +187,18 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset ...@@ -174,18 +187,18 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2); sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2);
if (stats->srs_stats[0] != '\0') { if (stats->srs_stats[0] != '\0') {
output += snprintf(output, end - output, "UE %04x: %s\n", UE->rnti, stats->srs_stats); output = st_append(output, end, "UE %04x: %s\n", UE->rnti, stats->srs_stats);
} }
output += snprintf(output, output = st_append(output,
end - output, end,
"UE %04x: dlsch_rounds ", UE->rnti); "UE %04x: dlsch_rounds ", UE->rnti);
output += snprintf(output, end - output, "%"PRIu64, stats->dl.rounds[0]); output = st_append(output, end, "%"PRIu64, stats->dl.rounds[0]);
for (int i = 1; i < gNB->dl_bler.harq_round_max; i++) for (int i = 1; i < gNB->dl_bler.harq_round_max; i++)
output += snprintf(output, end - output, "/%"PRIu64, stats->dl.rounds[i]); output = st_append(output, end, "/%"PRIu64, stats->dl.rounds[i]);
output += snprintf(output, output = st_append(output,
end - output, end,
", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS (%d) %d CCE fail %d\n", ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS (%d) %d CCE fail %d\n",
stats->dl.errors, stats->dl.errors,
stats->pucch0_DTX, stats->pucch0_DTX,
...@@ -199,15 +212,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset ...@@ -199,15 +212,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
stats->num_sinr_meas = 0; stats->num_sinr_meas = 0;
stats->cumul_sinrx10 = 0; stats->cumul_sinrx10 = 0;
} }
output += snprintf(output, output = st_append(output,
end - output, end,
"UE %04x: ulsch_rounds ", UE->rnti); "UE %04x: ulsch_rounds ", UE->rnti);
output += snprintf(output, end - output, "%"PRIu64, stats->ul.rounds[0]); output = st_append(output, end, "%"PRIu64, stats->ul.rounds[0]);
for (int i = 1; i < gNB->ul_bler.harq_round_max; i++) for (int i = 1; i < gNB->ul_bler.harq_round_max; i++)
output += snprintf(output, end - output, "/%"PRIu64, stats->ul.rounds[i]); output = st_append(output, end, "/%"PRIu64, stats->ul.rounds[i]);
output += snprintf(output, output = st_append(output,
end - output, end,
", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d (Qm %d deltaMCS %d dB) NPRB %d SNR %d.%d dB CCE fail %d\n", ", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d (Qm %d deltaMCS %d dB) NPRB %d SNR %d.%d dB CCE fail %d\n",
stats->ul.errors, stats->ul.errors,
stats->ulsch_DTX, stats->ulsch_DTX,
...@@ -220,15 +233,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset ...@@ -220,15 +233,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
sched_ctrl->pusch_snrx10 / 10, sched_ctrl->pusch_snrx10 / 10,
sched_ctrl->pusch_snrx10 % 10, sched_ctrl->pusch_snrx10 % 10,
sched_ctrl->ul_cce_fail); sched_ctrl->ul_cce_fail);
output += snprintf(output, output = st_append(output,
end - output, end,
"UE %04x: MAC: TX %14"PRIu64" RX %14"PRIu64" bytes\n", "UE %04x: MAC: TX %14"PRIu64" RX %14"PRIu64" bytes\n",
UE->rnti, stats->dl.total_bytes, stats->ul.total_bytes); UE->rnti, stats->dl.total_bytes, stats->ul.total_bytes);
for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); i++) { for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); i++) {
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i); const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i);
output += snprintf(output, output = st_append(output,
end - output, end,
"UE %04x: LCID %d: TX %14"PRIu64" RX %14"PRIu64" bytes\n", "UE %04x: LCID %d: TX %14"PRIu64" RX %14"PRIu64" bytes\n",
UE->rnti, UE->rnti,
c->lcid, c->lcid,
...@@ -236,6 +249,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset ...@@ -236,6 +249,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
stats->ul.lc_bytes[c->lcid]); stats->ul.lc_bytes[c->lcid]);
} }
} }
DevAssert(output <= end);
return output - begin; return output - begin;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment