From 9243a6e36964ba7443f62be05abd19303109e95d Mon Sep 17 00:00:00 2001 From: Yves Rutschle Date: Sun, 8 Sep 2024 23:11:50 +0200 Subject: [PATCH] check asprintf return value (fix #471) --- echosrv-conf.c | 69 +++++++++++++++++++++++++++++++++----------------- echosrv-conf.h | 4 +-- sslh-conf.c | 69 +++++++++++++++++++++++++++++++++----------------- sslh-conf.h | 4 +-- version.h | 2 +- 5 files changed, 97 insertions(+), 51 deletions(-) diff --git a/echosrv-conf.c b/echosrv-conf.c index b1db542..1f3a1b2 100644 --- a/echosrv-conf.c +++ b/echosrv-conf.c @@ -1,8 +1,8 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Wed Jul 10 15:35:54 2024. + * on Sun Sep 8 23:10:29 2024. # conf2struct: generate libconf parsers that read to structs -# Copyright (C) 2018-2021 Yves Rutschle +# Copyright (C) 2018-2024 Yves Rutschle # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include "echosrv-conf.h" #include "argtable3.h" #ifdef LIBPCRE @@ -216,6 +218,19 @@ char* config_error_text(config_t* c) { } #endif +static jmp_buf c2s_asprintf_fail; + +static int c2s_asprintf(char **restrict strp, const char *restrict fmt, ...) +{ + va_list ap; + + va_start(ap,fmt); + int res = vasprintf(strp, fmt, ap); + va_end(ap); + if (res == -1) longjmp(c2s_asprintf_fail, res); + return res; +} + /* This is the same as config_setting_lookup_string() except it allocates a new string which belongs to the caller */ static int myconfig_setting_lookup_stringcpy( @@ -226,7 +241,7 @@ static int myconfig_setting_lookup_stringcpy( const char* str; *value = NULL; if (config_setting_lookup_string(setting, name, &str) == CONFIG_TRUE) { - asprintf(value, "%s", str); + c2s_asprintf(value, "%s", str); return CONFIG_TRUE; } else { return CONFIG_FALSE; @@ -310,7 +325,7 @@ static int settingcpy(config_type type, void* target, const config_setting_t* se break; case CFG_STRING: - asprintf(&str, "%s", config_setting_get_string(setting)); + c2s_asprintf(&str, "%s", config_setting_get_string(setting)); val.def_string = str; *(char**)target = val.def_string; break; @@ -353,7 +368,7 @@ static int clcpy(config_type type, void* target, const void* cl_arg) break; case CFG_STRING: - asprintf(&str, "%s", (*(struct arg_str**)cl_arg)->sval[0]); + c2s_asprintf(&str, "%s", (*(struct arg_str**)cl_arg)->sval[0]); val.def_string = str; *(char**)target = val.def_string; break; @@ -765,7 +780,7 @@ static int read_block_setval(void* target, /* setting is present in cfg, look it up */ if (lookup_typed_ud(cfg, target, desc) != CONFIG_TRUE) { TRACE_READ((" but wrong type (expected %s) ", type2str[desc->type])); - asprintf(errmsg, "Option \"%s\" wrong type, expected %s\n", + c2s_asprintf(errmsg, "Option \"%s\" wrong type, expected %s\n", desc->name, type2str[desc->type]); return 0; } @@ -822,7 +837,7 @@ static int read_block(config_setting_t* cfg, void* target, struct config_desc* d set = read_block_setval(target, cfg, desc, errmsg); if (!set && desc->mandatory) { - asprintf(errmsg, "Mandatory option \"%s\" not found", desc->name); + c2s_asprintf(errmsg, "Mandatory option \"%s\" not found", desc->name); return 0; } @@ -980,13 +995,13 @@ static int regcompmatch_posix( regmatch_t* pmatch, int errlen = regerror(res, &preg, NULL, 0); regerr = malloc(errlen); regerror(res, &preg, regerr, errlen); - asprintf(errmsg, "compiling pattern /%s/:%s", arg->regex, regerr); + c2s_asprintf(errmsg, "compiling pattern /%s/:%s", arg->regex, regerr); free(regerr); return 0; } res = regexec(&preg, arg_cl->sval[arg_index], MAX_MATCH, &pmatch[0], 0); if (res) { - asprintf(errmsg, "--%s %s: Illegal argument", + c2s_asprintf(errmsg, "--%s %s: Illegal argument", arg_cl->hdr.longopts, arg->regex); return 0; @@ -1012,7 +1027,7 @@ static int regcompmatch_pcre2( regmatch_t* pmatch, pcre = pcre2_compile((PCRE2_SPTR8)arg->regex, PCRE2_ZERO_TERMINATED, 0, &error, &error_offset, NULL); if (!pcre) { pcre2_get_error_message(error, err_str, sizeof(err_str)); - asprintf(errmsg, "compiling pattern /%s/:%d: %s at offset %ld\n", + c2s_asprintf(errmsg, "compiling pattern /%s/:%d: %s at offset %ld\n", arg->regex, error, err_str, error_offset); return 0; } @@ -1022,7 +1037,7 @@ static int regcompmatch_pcre2( regmatch_t* pmatch, 0, 0, matches, NULL); if (res < 0) { pcre2_get_error_message(res, err_str, sizeof(err_str)); - asprintf(errmsg, "matching %s =~ /%s/:%d: %s\n", + c2s_asprintf(errmsg, "matching %s =~ /%s/:%d: %s\n", arg_cl->sval[arg_index], arg->regex, res, err_str); return 0; } @@ -1111,13 +1126,13 @@ static int c2s_parse_file(const char* filename, config_t* c, char**errmsg) /* Read config file */ if (config_read_file(c, filename) == CONFIG_FALSE) { if (config_error_line(c) != 0) { - asprintf(errmsg, "%s:%d:%s", + c2s_asprintf(errmsg, "%s:%d:%s", filename, config_error_line(c), config_error_text(c)); return 0; } - asprintf(errmsg, "%s:%s", filename, config_error_text(c)); + c2s_asprintf(errmsg, "%s:%s", filename, config_error_text(c)); return 0; } return 1; @@ -1128,23 +1143,23 @@ static void scalar_to_string(char** strp, config_setting_t* s) { switch(config_setting_type(s)) { case CONFIG_TYPE_INT: - asprintf(strp, "%d\n", config_setting_get_int(s)); + c2s_asprintf(strp, "%d\n", config_setting_get_int(s)); break; case CONFIG_TYPE_BOOL: - asprintf(strp, "%s\n", config_setting_get_bool(s) ? "[true]" : "[false]" ); + c2s_asprintf(strp, "%s\n", config_setting_get_bool(s) ? "[true]" : "[false]" ); break; case CONFIG_TYPE_INT64: - asprintf(strp, "%lld\n", config_setting_get_int64(s)); + c2s_asprintf(strp, "%lld\n", config_setting_get_int64(s)); break; case CONFIG_TYPE_FLOAT: - asprintf(strp, "%lf\n", config_setting_get_float(s)); + c2s_asprintf(strp, "%lf\n", config_setting_get_float(s)); break; case CONFIG_TYPE_STRING: - asprintf(strp, "%s\n", config_setting_get_string(s)); + c2s_asprintf(strp, "%s\n", config_setting_get_string(s)); break; default: /* This means a bug */ @@ -1172,9 +1187,9 @@ static int cfg_as_string(config_setting_t* parent, const char* path, char** strp if(config_setting_is_list(parent) || config_setting_is_array(parent)) { - asprintf(&subpath, "%s[%d]%s", path, config_setting_index(child), name); + c2s_asprintf(&subpath, "%s[%d]%s", path, config_setting_index(child), name); } else { - asprintf(&subpath, "%s/%s", path, name); + c2s_asprintf(&subpath, "%s/%s", path, name); } if (config_setting_is_scalar(child)) { @@ -1182,12 +1197,12 @@ static int cfg_as_string(config_setting_t* parent, const char* path, char** strp /* Add value to the output string */ if (*strp) { - asprintf(&old, "%s", *strp); + c2s_asprintf(&old, "%s", *strp); free(*strp); } else { - asprintf(&old, "%s", ""); + c2s_asprintf(&old, "%s", ""); } - asprintf(strp, "%s%s:%s", old, subpath, value); + c2s_asprintf(strp, "%s%s:%s", old, subpath, value); free(value); free(old); @@ -1224,6 +1239,14 @@ int echocfg_cl_parse(int argc, char* argv[], struct echocfg_item* cfg) }; + /* Set up failure handler in case asprintf() runs out of + * memory */ + ; + if (setjmp(c2s_asprintf_fail)) { + fprintf(stderr, "asprintf: probably out of memory\n"); + return -1; + } + /* Parse command line */ nerrors = arg_parse(argc, argv, argtable); if (nerrors) { diff --git a/echosrv-conf.h b/echosrv-conf.h index 976e8e8..4cec9a5 100644 --- a/echosrv-conf.h +++ b/echosrv-conf.h @@ -1,8 +1,8 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Wed Jul 10 15:35:54 2024. + * on Sun Sep 8 23:10:29 2024. # conf2struct: generate libconf parsers that read to structs -# Copyright (C) 2018-2021 Yves Rutschle +# Copyright (C) 2018-2024 Yves Rutschle # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/sslh-conf.c b/sslh-conf.c index 331147f..70274a0 100644 --- a/sslh-conf.c +++ b/sslh-conf.c @@ -1,8 +1,8 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Wed Jul 10 15:35:54 2024. + * on Sun Sep 8 23:10:29 2024. # conf2struct: generate libconf parsers that read to structs -# Copyright (C) 2018-2021 Yves Rutschle +# Copyright (C) 2018-2024 Yves Rutschle # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include "sslh-conf.h" #include "argtable3.h" #ifdef LIBPCRE @@ -216,6 +218,19 @@ char* config_error_text(config_t* c) { } #endif +static jmp_buf c2s_asprintf_fail; + +static int c2s_asprintf(char **restrict strp, const char *restrict fmt, ...) +{ + va_list ap; + + va_start(ap,fmt); + int res = vasprintf(strp, fmt, ap); + va_end(ap); + if (res == -1) longjmp(c2s_asprintf_fail, res); + return res; +} + /* This is the same as config_setting_lookup_string() except it allocates a new string which belongs to the caller */ static int myconfig_setting_lookup_stringcpy( @@ -226,7 +241,7 @@ static int myconfig_setting_lookup_stringcpy( const char* str; *value = NULL; if (config_setting_lookup_string(setting, name, &str) == CONFIG_TRUE) { - asprintf(value, "%s", str); + c2s_asprintf(value, "%s", str); return CONFIG_TRUE; } else { return CONFIG_FALSE; @@ -310,7 +325,7 @@ static int settingcpy(config_type type, void* target, const config_setting_t* se break; case CFG_STRING: - asprintf(&str, "%s", config_setting_get_string(setting)); + c2s_asprintf(&str, "%s", config_setting_get_string(setting)); val.def_string = str; *(char**)target = val.def_string; break; @@ -353,7 +368,7 @@ static int clcpy(config_type type, void* target, const void* cl_arg) break; case CFG_STRING: - asprintf(&str, "%s", (*(struct arg_str**)cl_arg)->sval[0]); + c2s_asprintf(&str, "%s", (*(struct arg_str**)cl_arg)->sval[0]); val.def_string = str; *(char**)target = val.def_string; break; @@ -1760,7 +1775,7 @@ static int read_block_setval(void* target, /* setting is present in cfg, look it up */ if (lookup_typed_ud(cfg, target, desc) != CONFIG_TRUE) { TRACE_READ((" but wrong type (expected %s) ", type2str[desc->type])); - asprintf(errmsg, "Option \"%s\" wrong type, expected %s\n", + c2s_asprintf(errmsg, "Option \"%s\" wrong type, expected %s\n", desc->name, type2str[desc->type]); return 0; } @@ -1817,7 +1832,7 @@ static int read_block(config_setting_t* cfg, void* target, struct config_desc* d set = read_block_setval(target, cfg, desc, errmsg); if (!set && desc->mandatory) { - asprintf(errmsg, "Mandatory option \"%s\" not found", desc->name); + c2s_asprintf(errmsg, "Mandatory option \"%s\" not found", desc->name); return 0; } @@ -1975,13 +1990,13 @@ static int regcompmatch_posix( regmatch_t* pmatch, int errlen = regerror(res, &preg, NULL, 0); regerr = malloc(errlen); regerror(res, &preg, regerr, errlen); - asprintf(errmsg, "compiling pattern /%s/:%s", arg->regex, regerr); + c2s_asprintf(errmsg, "compiling pattern /%s/:%s", arg->regex, regerr); free(regerr); return 0; } res = regexec(&preg, arg_cl->sval[arg_index], MAX_MATCH, &pmatch[0], 0); if (res) { - asprintf(errmsg, "--%s %s: Illegal argument", + c2s_asprintf(errmsg, "--%s %s: Illegal argument", arg_cl->hdr.longopts, arg->regex); return 0; @@ -2007,7 +2022,7 @@ static int regcompmatch_pcre2( regmatch_t* pmatch, pcre = pcre2_compile((PCRE2_SPTR8)arg->regex, PCRE2_ZERO_TERMINATED, 0, &error, &error_offset, NULL); if (!pcre) { pcre2_get_error_message(error, err_str, sizeof(err_str)); - asprintf(errmsg, "compiling pattern /%s/:%d: %s at offset %ld\n", + c2s_asprintf(errmsg, "compiling pattern /%s/:%d: %s at offset %ld\n", arg->regex, error, err_str, error_offset); return 0; } @@ -2017,7 +2032,7 @@ static int regcompmatch_pcre2( regmatch_t* pmatch, 0, 0, matches, NULL); if (res < 0) { pcre2_get_error_message(res, err_str, sizeof(err_str)); - asprintf(errmsg, "matching %s =~ /%s/:%d: %s\n", + c2s_asprintf(errmsg, "matching %s =~ /%s/:%d: %s\n", arg_cl->sval[arg_index], arg->regex, res, err_str); return 0; } @@ -2106,13 +2121,13 @@ static int c2s_parse_file(const char* filename, config_t* c, char**errmsg) /* Read config file */ if (config_read_file(c, filename) == CONFIG_FALSE) { if (config_error_line(c) != 0) { - asprintf(errmsg, "%s:%d:%s", + c2s_asprintf(errmsg, "%s:%d:%s", filename, config_error_line(c), config_error_text(c)); return 0; } - asprintf(errmsg, "%s:%s", filename, config_error_text(c)); + c2s_asprintf(errmsg, "%s:%s", filename, config_error_text(c)); return 0; } return 1; @@ -2123,23 +2138,23 @@ static void scalar_to_string(char** strp, config_setting_t* s) { switch(config_setting_type(s)) { case CONFIG_TYPE_INT: - asprintf(strp, "%d\n", config_setting_get_int(s)); + c2s_asprintf(strp, "%d\n", config_setting_get_int(s)); break; case CONFIG_TYPE_BOOL: - asprintf(strp, "%s\n", config_setting_get_bool(s) ? "[true]" : "[false]" ); + c2s_asprintf(strp, "%s\n", config_setting_get_bool(s) ? "[true]" : "[false]" ); break; case CONFIG_TYPE_INT64: - asprintf(strp, "%lld\n", config_setting_get_int64(s)); + c2s_asprintf(strp, "%lld\n", config_setting_get_int64(s)); break; case CONFIG_TYPE_FLOAT: - asprintf(strp, "%lf\n", config_setting_get_float(s)); + c2s_asprintf(strp, "%lf\n", config_setting_get_float(s)); break; case CONFIG_TYPE_STRING: - asprintf(strp, "%s\n", config_setting_get_string(s)); + c2s_asprintf(strp, "%s\n", config_setting_get_string(s)); break; default: /* This means a bug */ @@ -2167,9 +2182,9 @@ static int cfg_as_string(config_setting_t* parent, const char* path, char** strp if(config_setting_is_list(parent) || config_setting_is_array(parent)) { - asprintf(&subpath, "%s[%d]%s", path, config_setting_index(child), name); + c2s_asprintf(&subpath, "%s[%d]%s", path, config_setting_index(child), name); } else { - asprintf(&subpath, "%s/%s", path, name); + c2s_asprintf(&subpath, "%s/%s", path, name); } if (config_setting_is_scalar(child)) { @@ -2177,12 +2192,12 @@ static int cfg_as_string(config_setting_t* parent, const char* path, char** strp /* Add value to the output string */ if (*strp) { - asprintf(&old, "%s", *strp); + c2s_asprintf(&old, "%s", *strp); free(*strp); } else { - asprintf(&old, "%s", ""); + c2s_asprintf(&old, "%s", ""); } - asprintf(strp, "%s%s:%s", old, subpath, value); + c2s_asprintf(strp, "%s%s:%s", old, subpath, value); free(value); free(old); @@ -2254,6 +2269,14 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg) }; + /* Set up failure handler in case asprintf() runs out of + * memory */ + ; + if (setjmp(c2s_asprintf_fail)) { + fprintf(stderr, "asprintf: probably out of memory\n"); + return -1; + } + /* Parse command line */ nerrors = arg_parse(argc, argv, argtable); if (nerrors) { diff --git a/sslh-conf.h b/sslh-conf.h index f5b9005..62c1e84 100644 --- a/sslh-conf.h +++ b/sslh-conf.h @@ -1,8 +1,8 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Wed Jul 10 15:35:54 2024. + * on Sun Sep 8 23:10:29 2024. # conf2struct: generate libconf parsers that read to structs -# Copyright (C) 2018-2021 Yves Rutschle +# Copyright (C) 2018-2024 Yves Rutschle # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/version.h b/version.h index 8a032ec..46523c6 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #ifndef VERSION_H #define VERSION_H -#define VERSION "v2.1.1-49-ge7a9a37-dirty" +#define VERSION "v2.1.1-50-g686d1f7-dirty" #endif