Skip to content

Commit b359660

Browse files
shayshyiPaolo Abeni
authored andcommitted
net/mlx5: fw_tracer, Validate format string parameters
Add validation for format string parameters in the firmware tracer to prevent potential security vulnerabilities and crashes from malformed format strings received from firmware. The firmware tracer receives format strings from the device firmware and uses them to format trace messages. Without proper validation, bad firmware could provide format strings with invalid format specifiers (e.g., %s, %p, %n) that could lead to crashes, or other undefined behavior. Add mlx5_tracer_validate_params() to validate that all format specifiers in trace strings are limited to safe integer/hex formats (%x, %d, %i, %u, %llx, %lx, etc.). Reject strings containing other format types that could be used to access arbitrary memory or cause crashes. Invalid format strings are added to the trace output for visibility with "BAD_FORMAT: " prefix. Fixes: 70dd6fd ("net/mlx5: FW tracer, parse traces and kernel tracing support") Signed-off-by: Shay Drory <shayd@nvidia.com> Reviewed-by: Moshe Shemesh <moshe@nvidia.com> Reported-by: Breno Leitao <leitao@debian.org> Closes: https://lore.kernel.org/netdev/hanz6rzrb2bqbplryjrakvkbmv4y5jlmtthnvi3thg5slqvelp@t3s3erottr6s/ Signed-off-by: Tariq Toukan <tariqt@nvidia.com> Link: https://patch.msgid.link/1765284977-1363052-4-git-send-email-tariqt@nvidia.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 5846a36 commit b359660

File tree

2 files changed

+74
-10
lines changed

2 files changed

+74
-10
lines changed

drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "lib/eq.h"
3434
#include "fw_tracer.h"
3535
#include "fw_tracer_tracepoint.h"
36+
#include <linux/ctype.h>
3637

3738
static int mlx5_query_mtrc_caps(struct mlx5_fw_tracer *tracer)
3839
{
@@ -358,6 +359,43 @@ static const char *VAL_PARM = "%llx";
358359
static const char *REPLACE_64_VAL_PARM = "%x%x";
359360
static const char *PARAM_CHAR = "%";
360361

362+
static bool mlx5_is_valid_spec(const char *str)
363+
{
364+
/* Parse format specifiers to find the actual type.
365+
* Structure: %[flags][width][.precision][length]type
366+
* Skip flags, width, precision & length.
367+
*/
368+
while (isdigit(*str) || *str == '#' || *str == '.' || *str == 'l')
369+
str++;
370+
371+
/* Check if it's a valid integer/hex specifier:
372+
* Valid formats: %x, %d, %i, %u, etc.
373+
*/
374+
if (*str != 'x' && *str != 'X' && *str != 'd' && *str != 'i' &&
375+
*str != 'u' && *str != 'c')
376+
return false;
377+
378+
return true;
379+
}
380+
381+
static bool mlx5_tracer_validate_params(const char *str)
382+
{
383+
const char *substr = str;
384+
385+
if (!str)
386+
return false;
387+
388+
substr = strstr(substr, PARAM_CHAR);
389+
while (substr) {
390+
if (!mlx5_is_valid_spec(substr + 1))
391+
return false;
392+
393+
substr = strstr(substr + 1, PARAM_CHAR);
394+
}
395+
396+
return true;
397+
}
398+
361399
static int mlx5_tracer_message_hash(u32 message_id)
362400
{
363401
return jhash_1word(message_id, 0) & (MESSAGE_HASH_SIZE - 1);
@@ -419,6 +457,10 @@ static int mlx5_tracer_get_num_of_params(char *str)
419457
char *substr, *pstr = str;
420458
int num_of_params = 0;
421459

460+
/* Validate that all parameters are valid before processing */
461+
if (!mlx5_tracer_validate_params(str))
462+
return -EINVAL;
463+
422464
/* replace %llx with %x%x */
423465
substr = strstr(pstr, VAL_PARM);
424466
while (substr) {
@@ -570,14 +612,17 @@ void mlx5_tracer_print_trace(struct tracer_string_format *str_frmt,
570612
{
571613
char tmp[512];
572614

573-
snprintf(tmp, sizeof(tmp), str_frmt->string,
574-
str_frmt->params[0],
575-
str_frmt->params[1],
576-
str_frmt->params[2],
577-
str_frmt->params[3],
578-
str_frmt->params[4],
579-
str_frmt->params[5],
580-
str_frmt->params[6]);
615+
if (str_frmt->invalid_string)
616+
snprintf(tmp, sizeof(tmp), "BAD_FORMAT: %s", str_frmt->string);
617+
else
618+
snprintf(tmp, sizeof(tmp), str_frmt->string,
619+
str_frmt->params[0],
620+
str_frmt->params[1],
621+
str_frmt->params[2],
622+
str_frmt->params[3],
623+
str_frmt->params[4],
624+
str_frmt->params[5],
625+
str_frmt->params[6]);
581626

582627
trace_mlx5_fw(dev->tracer, trace_timestamp, str_frmt->lost,
583628
str_frmt->event_id, tmp);
@@ -609,6 +654,13 @@ static int mlx5_tracer_handle_raw_string(struct mlx5_fw_tracer *tracer,
609654
return 0;
610655
}
611656

657+
static void mlx5_tracer_handle_bad_format_string(struct mlx5_fw_tracer *tracer,
658+
struct tracer_string_format *cur_string)
659+
{
660+
cur_string->invalid_string = true;
661+
list_add_tail(&cur_string->list, &tracer->ready_strings_list);
662+
}
663+
612664
static int mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer *tracer,
613665
struct tracer_event *tracer_event)
614666
{
@@ -619,12 +671,18 @@ static int mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer *tracer,
619671
if (!cur_string)
620672
return mlx5_tracer_handle_raw_string(tracer, tracer_event);
621673

622-
cur_string->num_of_params = mlx5_tracer_get_num_of_params(cur_string->string);
623-
cur_string->last_param_num = 0;
624674
cur_string->event_id = tracer_event->event_id;
625675
cur_string->tmsn = tracer_event->string_event.tmsn;
626676
cur_string->timestamp = tracer_event->string_event.timestamp;
627677
cur_string->lost = tracer_event->lost_event;
678+
cur_string->last_param_num = 0;
679+
cur_string->num_of_params = mlx5_tracer_get_num_of_params(cur_string->string);
680+
if (cur_string->num_of_params < 0) {
681+
pr_debug("%s Invalid format string parameters\n",
682+
__func__);
683+
mlx5_tracer_handle_bad_format_string(tracer, cur_string);
684+
return 0;
685+
}
628686
if (cur_string->num_of_params == 0) /* trace with no params */
629687
list_add_tail(&cur_string->list, &tracer->ready_strings_list);
630688
} else {
@@ -634,6 +692,11 @@ static int mlx5_tracer_handle_string_trace(struct mlx5_fw_tracer *tracer,
634692
__func__, tracer_event->string_event.tmsn);
635693
return mlx5_tracer_handle_raw_string(tracer, tracer_event);
636694
}
695+
if (cur_string->num_of_params < 0) {
696+
pr_debug("%s string parameter of invalid string, dumping\n",
697+
__func__);
698+
return 0;
699+
}
637700
cur_string->last_param_num += 1;
638701
if (cur_string->last_param_num > TRACER_MAX_PARAMS) {
639702
pr_debug("%s Number of params exceeds the max (%d)\n",

drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ struct tracer_string_format {
125125
struct list_head list;
126126
u32 timestamp;
127127
bool lost;
128+
bool invalid_string;
128129
};
129130

130131
enum mlx5_fw_tracer_ownership_state {

0 commit comments

Comments
 (0)