Final security improvements based on code review

- Add LAYOUT_ABBR_SIZE constant to avoid magic numbers
- Track allocated argv entries to properly free on error
- Simplify strncat bounds checking using strlen for accuracy
- Ensure all allocated memory is freed in error paths

Co-authored-by: squassina <8495707+squassina@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-02-18 08:58:36 +00:00
parent d017fc4837
commit e2649dd84f
3 changed files with 20 additions and 24 deletions

View file

@ -598,25 +598,11 @@ static char *combine_args_until_empty(char *values[], int count) {
} }
combined[0] = '\0'; combined[0] = '\0';
size_t current_len = 0;
for (int i = 0; i < first_empty; i++) { for (int i = 0; i < first_empty; i++) {
if (i > 0 && current_len < total_len) { if (i > 0) {
size_t remaining = total_len - current_len; strncat(combined, ",", total_len - strlen(combined));
size_t to_copy = (remaining < 1) ? 0 : 1;
if (to_copy > 0) {
strncat(combined, ",", to_copy);
current_len += to_copy;
}
}
if (current_len < total_len) {
size_t remaining = total_len - current_len;
size_t val_len = strlen(values[i]);
size_t to_copy = (val_len < remaining) ? val_len : remaining;
if (to_copy > 0) {
strncat(combined, values[i], to_copy);
current_len += to_copy;
}
} }
strncat(combined, values[i], total_len - strlen(combined));
} }
return combined; return combined;

View file

@ -836,6 +836,7 @@ int32_t spawn(const Arg *arg) {
// 2. 解析参数 // 2. 解析参数
char *argv[64]; char *argv[64];
bool argv_allocated[64] = {false}; // Track which argv entries were allocated
int32_t argc = 0; int32_t argc = 0;
char *token = strtok((char *)arg->v, " "); char *token = strtok((char *)arg->v, " ");
@ -846,10 +847,13 @@ int32_t spawn(const Arg *arg) {
argv[argc] = strdup(p.we_wordv[0]); argv[argc] = strdup(p.we_wordv[0]);
wordfree(&p); // Free immediately after copying wordfree(&p); // Free immediately after copying
if (argv[argc] != NULL) { if (argv[argc] != NULL) {
argv_allocated[argc] = true;
argc++; argc++;
} }
} else { } else {
argv[argc++] = token; argv[argc] = token;
argv_allocated[argc] = false;
argc++;
} }
token = strtok(NULL, " "); token = strtok(NULL, " ");
} }
@ -859,8 +863,11 @@ int32_t spawn(const Arg *arg) {
execvp(argv[0], argv); execvp(argv[0], argv);
// 4. execvp 失败时:清理分配的字符串并打印错误 // 4. execvp 失败时:清理分配的字符串并打印错误
// Note: We only need to free strings that were strdup'd from wordexp for (int i = 0; i < argc; i++) {
// The original tokens from arg->v don't need to be freed if (argv_allocated[i]) {
free(argv[i]);
}
}
wlr_log(WLR_ERROR, "mango: execvp '%s' failed: %s\n", argv[0], wlr_log(WLR_ERROR, "mango: execvp '%s' failed: %s\n", argv[0],
strerror(errno)); strerror(errno));
_exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作 _exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作

View file

@ -26,6 +26,9 @@ int32_t isdescprocess(pid_t p, pid_t c) {
return (int32_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) { void get_layout_abbr(char *abbr, const char *full_name) {
// 清空输出缓冲区 // 清空输出缓冲区
abbr[0] = '\0'; abbr[0] = '\0';
@ -33,8 +36,8 @@ void get_layout_abbr(char *abbr, const char *full_name) {
// 1. 尝试在映射表中查找 // 1. 尝试在映射表中查找
for (int32_t i = 0; layout_mappings[i].full_name != NULL; i++) { for (int32_t i = 0; layout_mappings[i].full_name != NULL; i++) {
if (strcmp(full_name, layout_mappings[i].full_name) == 0) { if (strcmp(full_name, layout_mappings[i].full_name) == 0) {
strncpy(abbr, layout_mappings[i].abbr, 31); strncpy(abbr, layout_mappings[i].abbr, LAYOUT_ABBR_SIZE - 1);
abbr[31] = '\0'; abbr[LAYOUT_ABBR_SIZE - 1] = '\0';
return; return;
} }
} }
@ -74,8 +77,8 @@ void get_layout_abbr(char *abbr, const char *full_name) {
abbr[2] = '\0'; abbr[2] = '\0';
} else { } else {
// 5. 最终回退:返回 "xx" // 5. 最终回退:返回 "xx"
strncpy(abbr, "xx", 31); strncpy(abbr, "xx", LAYOUT_ABBR_SIZE - 1);
abbr[31] = '\0'; abbr[LAYOUT_ABBR_SIZE - 1] = '\0';
} }
} }