Skip to content

fix: replace system() with fork+execl to prevent command injection (CWE-78) - #214

Open
fly602 wants to merge 1 commit into
masterfrom
agent/agent/6e487a86e304
Open

fly602 wants to merge 1 commit into
masterfrom
agent/agent/6e487a86e304

Conversation

@fly602

@fly602 fly602 commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

修复内容

CWE-78 OS命令注入

将 analyse.c 中 system() 调用替换为 fork()+execl(),避免通过 shell 执行拼接的命令字符串。

原代码

snprintf(command, command_len, "%s \"%s\" \"%s\" \"%s\"", config.script, devices.dev[i].device, devices.dev[i].ip, rcv_smac);
rv = system(command);

修复后

pid_t pid = fork();
if (pid == 0) {
    execl(config.script, config.script, devices.dev[i].device, devices.dev[i].ip, rcv_smac, (char *) NULL);
    _exit(127);
} else {
    waitpid(pid, &status, 0);
}

参数直接传递给 execl,不经过 shell 解释,消除命令注入风险。

Log: replace system() call with fork+execl in analyse.c ipwatchd
Influence: fix CWE-78 OS command injection vulnerability in conflict notification script execution

Summary by Sourcery

Harden user-defined script execution against command injection vulnerabilities.

Bug Fixes:

  • Prevent OS command injection when executing the user-defined conflict notification script by removing shell-based command execution.

Enhancements:

  • Pass script arguments directly and wait for the child process, with explicit handling for process creation and execution failures.

Log: replace system() call with fork+execl in analyse.c ipwatchd
Influence: fix CWE-78 OS command injection vulnerability in conflict notification script execution
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fly602

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Nov 2, 2026

Copy link
Copy Markdown

Reviewer's Guide

The conflict-notification script is now launched with fork()+execl() and its arguments passed directly, preventing shell metacharacters in device, IP, or MAC values from being interpreted as commands while preserving synchronous execution.

Sequence diagram for safe conflict-notification script execution

sequenceDiagram
    participant Analyse as ipwd_analyse
    participant Parent as Parent process
    participant Child as Child process
    participant Script as config.script

    Analyse->>Parent: fork()
    alt fork failed
        Parent->>Analyse: ipwd_message(... fork failed)
    else child process
        Parent->>Child: execl(config.script, device, ip, rcv_smac)
        Child->>Script: Execute directly without shell
        alt execl failed
            Child->>Child: _exit(127)
        end
    else parent process
        Parent->>Parent: waitpid(pid, &status, 0)
        alt waitpid failed
            Parent->>Analyse: ipwd_message(... config.script)
        end
    end
Loading

File-Level Changes

Change Details Files
Replaced shell-based script execution with direct process creation and execution to eliminate command injection through user-controlled arguments.
  • Removed command-string construction, allocation, and cleanup.
  • Forked a child process and passed script arguments directly via execl without shell interpretation.
  • Used _exit(127) when execution fails and waitpid in the parent to synchronously reap the child.
  • Added error reporting for fork and waitpid failures.
src/plugin-sdbus/plugin-ipwatchd/upstream/analyse.c

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/plugin-sdbus/plugin-ipwatchd/upstream/analyse.c" line_range="216" />
<code_context>
+			{
+				/* Parent process - wait for child */
+				int status;
+				rv = waitpid (pid, &status, 0);
+				if (rv == -1)
+				{
</code_context>
<issue_to_address>
**Scripts outlive daemon shutdown**

When a caught signal, especially SIGTERM, interrupts `waitpid` while a notification script runs, `waitpid` returns `-1` with `EINTR`, and the callback in `ipwd_analyse` returns without retrying or reaping the child. The daemon can exit while the script is still running, or leave an unreaped child that becomes a zombie.

Retry `waitpid` when it fails with `EINTR` until the child is reaped.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

{
/* Parent process - wait for child */
int status;
rv = waitpid (pid, &status, 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Scripts outlive daemon shutdown

When a caught signal, especially SIGTERM, interrupts waitpid while a notification script runs, waitpid returns -1 with EINTR, and the callback in ipwd_analyse returns without retrying or reaping the child. The daemon can exit while the script is still running, or leave an unreaped child that becomes a zombie.

Retry waitpid when it fails with EINTR until the child is reaped.

Prompt for AI agents
In `src/plugin-sdbus/plugin-ipwatchd/upstream/analyse.c` at line 216:

**Scripts outlive daemon shutdown**

When a caught signal, especially SIGTERM, interrupts `waitpid` while a notification script runs, `waitpid` returns `-1` with `EINTR`, and the callback in `ipwd_analyse` returns without retrying or reaping the child. The daemon can exit while the script is still running, or leave an unreaped child that becomes a zombie.

Retry `waitpid` when it fails with `EINTR` until the child is reaped.

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 97 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 本次提交将 system() 替换为 fork+execl+waitpid,正确修复了 CWE-78 命令注入漏洞,消除 shell 解释风险且参数以独立 argv 传递,安全性显著提升;四维度均通过,仅遗留两处因移除 malloc 路径而产生的未使用局部变量(command、command_len),建议清理。

🔍 详细分析

1. 语法逻辑 ✅

评价: 语法正确,逻辑清晰 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['删除第 43-44 行已无用的 command 与 command_len 声明,消除编译器警告', "可选:父进程 waitpid 成功后通过 WIFEXITED/WEXITSTATUS 检查子脚本退出码,以区分'脚本执行失败'与'fork/waitpid 失败',提升可诊断性(原 system() 同样未检查退出码,故非回归)"]


2. 代码质量 ✅

评价: 代码结构清晰,注释完整 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['fork 失败分支仅打印日志后继续循环(原 malloc 失败为 break),行为略有差异但可接受;如需保持一致可考虑 break']


3. 代码性能 ✅

评价: 性能良好,资源使用合理 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: []


4. 代码安全 🔒

评价: 存在0个安全漏洞 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: ['建议确认 ipwatchd.h 已包含 <unistd.h>、<sys/wait.h>、<sys/types.h> 以提供 fork/execl/waitpid/pid_t 声明(当前未见显式 include,依赖头文件传递)']


💡 改进建议代码示例

/* 清理无用声明后的推荐写法(仅展示关键片段) */
void ipwd_analyse(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
    int rv = 0;
    int i = 0;
    /* ... 删除 char *command 与 int command_len 声明 ... */

    if (config.script != NULL)
    {
        /* Run user-defined script: script "dev" "ip" "mac" */
        pid_t pid = fork();
        if (pid == -1)
        {
            ipwd_message(IPWD_MSG_TYPE_ERROR, "Unable to execute user-defined script - fork failed");
        }
        else if (pid == 0)
        {
            /* Child process */
            execl(config.script, config.script,
                  devices.dev[i].device, devices.dev[i].ip, rcv_smac,
                  (char *)NULL);
            _exit(127);  /* execl only returns on failure */
        }
        else
        {
            /* Parent process - wait for child */
            int status;
            rv = waitpid(pid, &status, 0);
            if (rv == -1)
            {
                ipwd_message(IPWD_MSG_TYPE_ERROR,
                             "Unable to execute user-defined script: %s", config.script);
            }
            else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
            {
                ipwd_message(IPWD_MSG_TYPE_ERROR,
                             "User-defined script exited with code %d", WEXITSTATUS(status));
            }
        }
    }
    /* ... */
}

本报告由 AI 代码审查工具自动生成

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants