diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 00000000..945c9b46 --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 0d7ded57..0133250f 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -537,11 +538,20 @@ int32_t parse_fold_state(const char *str) { } int64_t parse_color(const char *hex_str) { char *endptr; - int64_t hex_num = strtol(hex_str, &endptr, 16); - if (*endptr != '\0') { + errno = 0; + uint64_t hex_num = strtoul(hex_str, &endptr, 16); + + // Check for conversion errors + if (*endptr != '\0' || errno == ERANGE) { return -1; } - return hex_num; + + // Validate range for color values (0x00000000 to 0xFFFFFFFF) + if (hex_num > 0xFFFFFFFF) { + return -1; + } + + return (int64_t)hex_num; } // 辅助函数:检查字符串是否以指定的前缀开头(忽略大小写) @@ -581,19 +591,32 @@ static char *combine_args_until_empty(char *values[], int count) { // plus the number of commas (first_empty-1 commas) total_len += (first_empty - 1); - // allocate memory and concatenate + // allocate memory and concatenate safely char *combined = malloc(total_len + 1); if (combined == NULL) { return strdup(""); } - combined[0] = '\0'; + char *ptr = combined; + size_t remaining = total_len + 1; // Include space for null terminator + for (int i = 0; i < first_empty; i++) { - if (i > 0) { - strcat(combined, ","); + if (i > 0 && remaining > 1) { + *ptr++ = ','; + remaining--; + } + if (remaining > 1) { + size_t val_len = strlen(values[i]); + // Always leave space for null terminator + size_t to_copy = (val_len < remaining - 1) ? val_len : remaining - 1; + if (to_copy > 0) { + memcpy(ptr, values[i], to_copy); + ptr += to_copy; + remaining -= to_copy; + } } - strcat(combined, values[i]); } + *ptr = '\0'; // Null terminate return combined; } @@ -626,8 +649,10 @@ uint32_t parse_mod(const char *mod_str) { if (strncmp(token, "code:", 5) == 0) { // 处理 code: 形式 char *endptr; + errno = 0; long keycode = strtol(token + 5, &endptr, 10); - if (endptr != token + 5 && (*endptr == '\0' || *endptr == ' ')) { + // Check for conversion errors: overflow or no conversion + if (endptr != token + 5 && (*endptr == '\0' || *endptr == ' ') && errno != ERANGE) { switch (keycode) { case 133: case 134: @@ -777,7 +802,16 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { // 处理 code: 前缀的情况 if (strncmp(key_str, "code:", 5) == 0) { char *endptr; + errno = 0; xkb_keycode_t keycode = (xkb_keycode_t)strtol(key_str + 5, &endptr, 10); + + // Validate conversion + if (errno == ERANGE || *endptr != '\0') { + kc.type = KEY_TYPE_SYM; + kc.keysym = XKB_KEY_NoSymbol; + return kc; + } + kc.type = KEY_TYPE_CODE; kc.keycode.keycode1 = keycode; // 只设置第一个 kc.keycode.keycode2 = 0; @@ -2284,7 +2318,8 @@ bool parse_option(Config *config, char *key, char *value) { trim_whitespace(arg_value4); trim_whitespace(arg_value5); - strcpy(binding->mode, config->keymode); + strncpy(binding->mode, config->keymode, sizeof(binding->mode) - 1); + binding->mode[sizeof(binding->mode) - 1] = '\0'; if (strcmp(binding->mode, "common") == 0) { binding->iscommonmode = true; binding->isdefaultmode = false; @@ -3479,7 +3514,8 @@ bool parse_config(void) { config.tag_rules = NULL; config.tag_rules_count = 0; config.cursor_theme = NULL; - strcpy(config.keymode, "default"); + strncpy(config.keymode, "default", sizeof(config.keymode) - 1); + config.keymode[sizeof(config.keymode) - 1] = '\0'; create_config_keymap(); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 0bfab158..c54f9a53 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -836,14 +836,24 @@ int32_t spawn(const Arg *arg) { // 2. 解析参数 char *argv[64]; + char *allocated_strings[64]; // Track strdup'd strings for cleanup int32_t argc = 0; + int32_t alloc_count = 0; + char *token = strtok((char *)arg->v, " "); while (token != NULL && argc < 63) { wordexp_t p; - if (wordexp(token, &p, 0) == 0) { - argv[argc++] = p.we_wordv[0]; + if (wordexp(token, &p, 0) == 0 && p.we_wordc > 0) { + // Duplicate the string since we'll free the wordexp result + argv[argc] = strdup(p.we_wordv[0]); + wordfree(&p); // Free immediately after copying + if (argv[argc] != NULL) { + allocated_strings[alloc_count++] = argv[argc]; + argc++; + } } else { - argv[argc++] = token; + argv[argc] = token; + argc++; } token = strtok(NULL, " "); } @@ -852,7 +862,12 @@ int32_t spawn(const Arg *arg) { // 3. 执行命令 execvp(argv[0], argv); - // 4. execvp 失败时:打印错误并直接退出(避免 coredump) + // 4. execvp 失败时:清理并退出 + // If execvp succeeds, this code never runs (process replaced) + // If it fails, clean up allocated strings before exiting + for (int32_t i = 0; i < alloc_count; i++) { + free(allocated_strings[i]); + } wlr_log(WLR_ERROR, "mango: execvp '%s' failed: %s\n", argv[0], strerror(errno)); _exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作 diff --git a/src/fetch/common.h b/src/fetch/common.h index 58e69dc1..b04f090d 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -26,6 +26,9 @@ int32_t isdescprocess(pid_t p, pid_t c) { return (int32_t)c; } +// Buffer size for layout abbreviations (must match kb_layout buffer in dwl-ipc.h) +#define LAYOUT_ABBR_SIZE 32 + void get_layout_abbr(char *abbr, const char *full_name) { // 清空输出缓冲区 abbr[0] = '\0'; @@ -33,7 +36,8 @@ void get_layout_abbr(char *abbr, const char *full_name) { // 1. 尝试在映射表中查找 for (int32_t i = 0; layout_mappings[i].full_name != NULL; i++) { if (strcmp(full_name, layout_mappings[i].full_name) == 0) { - strcpy(abbr, layout_mappings[i].abbr); + strncpy(abbr, layout_mappings[i].abbr, LAYOUT_ABBR_SIZE - 1); + abbr[LAYOUT_ABBR_SIZE - 1] = '\0'; return; } } @@ -73,7 +77,9 @@ void get_layout_abbr(char *abbr, const char *full_name) { abbr[2] = '\0'; } else { // 5. 最终回退:返回 "xx" - strcpy(abbr, "xx"); + abbr[0] = 'x'; + abbr[1] = 'x'; + abbr[2] = '\0'; } }