From bf614354cc0d3434ed721621a41dff5f1b8a4dcb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 28 Apr 2026 12:34:57 +0200 Subject: [PATCH] security: fix integer overflow in pw-cli param info allocation Memory Safety: High Three places in pw-cli allocated param info arrays using malloc(n_params * sizeof(struct spa_param_info)) where n_params comes from remote protocol data. The multiplication can overflow, causing a small buffer to be allocated while n_params remains large. Later code iterating over n_params entries would read past the allocated buffer. Fixed by using calloc(n_params, sizeof(...)) which internally checks for multiplication overflow and returns NULL on failure. Also added NULL checks and proper fallback when allocation fails. Co-Authored-By: Claude Opus 4.6 --- src/tools/pw-cli.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/tools/pw-cli.c b/src/tools/pw-cli.c index b731e0acb..a5723fce7 100644 --- a/src/tools/pw-cli.c +++ b/src/tools/pw-cli.c @@ -1140,11 +1140,15 @@ static void session_event_info(void *data, if (info != NULL) { info->id = update->id; if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) { - info->n_params = update->n_params; free(info->params); - info->params = malloc(info->n_params * sizeof(struct spa_param_info)); - memcpy(info->params, update->params, - info->n_params * sizeof(struct spa_param_info)); + info->params = calloc(update->n_params, sizeof(struct spa_param_info)); + if (update->n_params > 0 && info->params == NULL) { + info->n_params = 0; + } else { + info->n_params = update->n_params; + memcpy(info->params, update->params, + info->n_params * sizeof(struct spa_param_info)); + } } if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) { pw_properties_free ((struct pw_properties *)info->props); @@ -1196,11 +1200,15 @@ static void endpoint_event_info(void *data, if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_SESSION) info->session_id = update->session_id; if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PARAMS) { - info->n_params = update->n_params; free(info->params); - info->params = malloc(info->n_params * sizeof(struct spa_param_info)); - memcpy(info->params, update->params, - info->n_params * sizeof(struct spa_param_info)); + info->params = calloc(update->n_params, sizeof(struct spa_param_info)); + if (update->n_params > 0 && info->params == NULL) { + info->n_params = 0; + } else { + info->n_params = update->n_params; + memcpy(info->params, update->params, + info->n_params * sizeof(struct spa_param_info)); + } } if (update->change_mask & PW_ENDPOINT_CHANGE_MASK_PROPS) { pw_properties_free ((struct pw_properties *)info->props); @@ -1245,11 +1253,15 @@ static void endpoint_stream_event_info(void *data, info->name = update->name ? strdup(update->name) : NULL; if (update->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PARAMS) { - info->n_params = update->n_params; free(info->params); - info->params = malloc(info->n_params * sizeof(struct spa_param_info)); - memcpy(info->params, update->params, - info->n_params * sizeof(struct spa_param_info)); + info->params = calloc(update->n_params, sizeof(struct spa_param_info)); + if (update->n_params > 0 && info->params == NULL) { + info->n_params = 0; + } else { + info->n_params = update->n_params; + memcpy(info->params, update->params, + info->n_params * sizeof(struct spa_param_info)); + } } if (update->change_mask & PW_ENDPOINT_STREAM_CHANGE_MASK_PROPS) { pw_properties_free ((struct pw_properties *)info->props);