From: Petr Hodina <[email protected]> Extend cmdline_utils to support masking or replacing parameters in command line strings. This is useful for filtering sensitive data or modifying boot parameters.
Signed-off-by: Petr Hodina <[email protected]> --- include/cmdline_utils.h | 7 +++ lib/cmdline_utils.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/include/cmdline_utils.h b/include/cmdline_utils.h index cf127b64e55..fa6e20b2417 100644 --- a/include/cmdline_utils.h +++ b/include/cmdline_utils.h @@ -18,4 +18,11 @@ struct cmdline_param { int parse_cmdline_params(const char *cmdline, struct cmdline_param *params, int count); +struct cmdline_mask_param { + const char *key; + const char *new_value; +}; + +char *mask_cmdline_params(const char *cmdline, struct cmdline_mask_param *params, int count); + #endif /* _CMDLINE_UTILS_H_ */ diff --git a/lib/cmdline_utils.c b/lib/cmdline_utils.c index b4798c439b8..4355bdd45f4 100644 --- a/lib/cmdline_utils.c +++ b/lib/cmdline_utils.c @@ -94,3 +94,153 @@ cleanup_error: } return -ENOMEM; } + +static int ensure_capacity(char **result, int *result_len, char **dst_pos, int needed) +{ + int current_pos = *dst_pos - *result; + char *temp; + + if (current_pos + needed < *result_len) + return 0; + + while (current_pos + needed >= *result_len) + *result_len *= 2; + + temp = realloc(*result, *result_len + 1); + if (!temp) { + free(*result); + return -ENOMEM; + } + + *result = temp; + *dst_pos = *result + current_pos; + + return 0; +} + +static int write_replacement(char **result, int *result_len, char **dst_pos, + const char *key_with_equals, const char *new_value) +{ + int key_len = strlen(key_with_equals); + int new_value_len = strlen(new_value); + + if (ensure_capacity(result, result_len, dst_pos, key_len + new_value_len)) + return -ENOMEM; + + memcpy(*dst_pos, key_with_equals, key_len); + *dst_pos += key_len; + + strcpy(*dst_pos, new_value); + *dst_pos += new_value_len; + + return 0; +} + +enum match_result { + NO_MATCH, + MATCHED, + MATCH_ERROR, +}; + +static enum match_result apply_mask_param(const char *cmdline, const char *src_pos, + struct cmdline_mask_param *param, + char **result, int *result_len, char **dst_pos, + const char **next_src_pos) +{ + char *key_with_equals; + int key_len; + const char *value_start, *value_end, *param_end; + enum match_result ret; + + if (!param->key) + return NO_MATCH; + + key_len = strlen(param->key); + if (param->key[key_len - 1] == '=') { + key_with_equals = (char *)param->key; + } else { + key_with_equals = malloc(key_len + 2); + if (!key_with_equals) { + free(*result); + return MATCH_ERROR; + } + strcpy(key_with_equals, param->key); + strcat(key_with_equals, "="); + } + + if (strncmp(src_pos, key_with_equals, strlen(key_with_equals)) != 0 || + (src_pos != cmdline && *(src_pos - 1) != ' ')) { + ret = NO_MATCH; + goto out; + } + + value_start = src_pos + strlen(key_with_equals); + value_end = strstr(value_start, " "); + if (!value_end) + value_end = value_start + strlen(value_start); + param_end = value_end; + + if (!param->new_value) { + *next_src_pos = (*param_end == ' ') ? param_end + 1 : param_end; + } else if (write_replacement(result, result_len, dst_pos, + key_with_equals, param->new_value)) { + ret = MATCH_ERROR; + goto out; + } else { + *next_src_pos = param_end; + } + + ret = MATCHED; + +out: + if (key_with_equals != param->key) + free(key_with_equals); + return ret; +} + +char *mask_cmdline_params(const char *cmdline, struct cmdline_mask_param *params, int count) +{ + char *result; + const char *src_pos; + char *dst_pos; + int i, result_len, cmdline_len; + bool found_match; + + if (!cmdline || !params || count <= 0) + return NULL; + + cmdline_len = strlen(cmdline); + result_len = cmdline_len * 2; + result = malloc(result_len + 1); + if (!result) + return NULL; + + src_pos = cmdline; + dst_pos = result; + + while (*src_pos) { + found_match = false; + + for (i = 0; i < count; i++) { + enum match_result mr; + + mr = apply_mask_param(cmdline, src_pos, ¶ms[i], + &result, &result_len, &dst_pos, &src_pos); + if (mr == MATCH_ERROR) + return NULL; + if (mr == MATCHED) { + found_match = true; + break; + } + } + + if (!found_match) { + if (ensure_capacity(&result, &result_len, &dst_pos, 1)) + return NULL; + *dst_pos++ = *src_pos++; + } + } + + *dst_pos = '\0'; + return result; +} -- 2.55.0
