Skip to content

fix(RDKB-65467): handle ECHILD in exec_shell_cmd to suppress false DHCPv6 error log#129

Open
aadhithan01 wants to merge 9 commits into
developfrom
fix/RDKB-65467
Open

fix(RDKB-65467): handle ECHILD in exec_shell_cmd to suppress false DHCPv6 error log#129
aadhithan01 wants to merge 9 commits into
developfrom
fix/RDKB-65467

Conversation

@aadhithan01

@aadhithan01 aadhithan01 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Problem

On XB8/XB9/XB10 bootup, the following false error is logged even though IPv6 address configuration succeeds:

[mod=DHCPMGR, lvl=ERROR] exec_shell_cmd: 65 system() failed to run shell
[mod=DHCPMGR, lvl=ERROR] configureNetworkInterface 397: Failed to configure IPv6 address on interface erouter0

Root Cause

A race condition between system() and sigchld_handler():

  1. system() forks a child (/bin/sh -c "ip -6 addr replace ...")
  2. Child runs ip -6 addr replace successfully and exits(0)
  3. Kernel sends SIGCHLD
  4. sigchld_handler() fires, calls waitpid(-1, WNOHANG) — reaps any child including the shell child
  5. system()'s own waitpid(child_pid) gets errno=ECHILD — child already gone
  6. system() returns -1 → falsely logged as ERROR

The IPv6 address is actually configured on erouter0. This is a pure logging false positive.

Fix

In exec_shell_cmd(), check errno == ECHILD before treating system() returning -1 as a failure:

  • ECHILD: log WARNING and return 0 (success). sigchld_handler's processKilled() only acts on registered DHCP client pids — the transient /bin/sh child is never registered, so it is a no-op. This is safe.
  • Other errno: log ERROR with errno + strerror() + command string and return -1.

Additional improvements:

  • Change exec_shell_cmd parameter to const char *
  • Add #include <errno.h> and #include <string.h>
  • Capture errno into saved_errno immediately after system() to avoid argument evaluation order issues

Why This Is Safe

sigchld_handler()processKilled(pid) only acts on pids registered as DHCP client processes. The transient shell spawned by system() is never registered → processKilled() is a no-op for it. DHCP client crash selfheal notifications are unaffected.

Test Procedure

  1. Boot XB8/XB9/XB10 device
  2. Confirm false ERROR log is gone from DHCPMGR logs on bootup
  3. Confirm DHCPv6 address is correctly assigned on erouter0
  4. Verify DHCP client selfheal still triggers correctly when DHCPv4/v6 client crashes

References

  • RDKB-65467

…ror log

system() returns -1 with errno=ECHILD when sigchld_handler reaps the
child process before system()'s own waitpid() can collect it. This is
a race condition where the command (e.g. 'ip -6 addr replace') runs
successfully but the error path is triggered incorrectly.

Root cause: sigchld_handler uses waitpid(-1, WNOHANG) which reaps ANY
child, including the transient /bin/sh spawned by system(). When that
happens, system() finds ECHILD and returns -1, causing a false ERROR
log in configureNetworkInterface().

Fix: Check errno == ECHILD before treating system() return -1 as a
failure. ECHILD here means the child already ran and was reaped - not
that it failed to run. Log a WARNING instead and return success.

The sigchld_handler / processKilled() flow is unaffected since the
transient shell child pid is never registered as a DHCP client pid.
@aadhithan01
aadhithan01 requested a review from a team as a code owner July 8, 2026 10:03
Copilot AI review requested due to automatic review settings July 8, 2026 10:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates DHCPMGR’s IPv6 lease handler to suppress a known false-negative error path where system() can return -1 with errno=ECHILD due to a SIGCHLD handler reaping the /bin/sh child before system() collects it, preventing misleading “Failed to configure IPv6 address” logs during boot.

Changes:

  • Treat system() returning -1 with errno==ECHILD as a non-fatal condition in exec_shell_cmd().
  • Add a warning log for the ECHILD case and return success to avoid propagating a false failure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
- Add missing #include <errno.h> for errno and ECHILD usage
- Reword log message to clarify exit status is unavailable (not
  confirmed success) and include the command string for easier
  debugging
Copilot AI review requested due to automatic review settings July 8, 2026 10:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
- Change exec_shell_cmd parameter to const char * for const-correctness
  (function never modifies the command string)
- Add #include <string.h> for strerror()
- Improve real failure error log to include command, errno value and
  strerror description for easier field diagnosis
Copilot AI review requested due to automatic review settings July 8, 2026 11:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
…issue

Capture errno in saved_errno right after system() returns -1, before
any other function call (including strerror()) can modify it. In C,
argument evaluation order is unspecified and strerror() may alter errno,
causing the numeric value and message to become inconsistent.
Copilot AI review requested due to automatic review settings July 8, 2026 11:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
… SIGCHLD race

system() is vulnerable to a race where sigchld_handler() (using
waitpid(-1)) reaps the child before system()'s own waitpid() can
collect it, causing system() to return -1/ECHILD even when the command
succeeded. Silently treating ECHILD as success is incorrect because the
exit status is genuinely unknown.

Replace system() with an explicit fork/exec/waitpid pattern:
- fork() a child and exec /bin/sh -c <command>
- Parent uses waitpid(specific_pid) with EINTR retry loop
- ECHILD case is now treated as a genuine error (exit status unknown)
  rather than silently swallowed
- Add #include <signal.h> and <unistd.h> for signal/fork/execl/_exit

This eliminates the false error log while correctly handling all
failure modes without masking real command failures.
Copilot AI review requested due to automatic review settings July 8, 2026 11:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
…rding

- On ECHILD from waitpid(), return 0 with WARNING instead of ERROR+failure.
  The shell child is never a registered DHCP client pid so processKilled()
  is a no-op — this is safe and suppresses the false error log (core intent).
- Restore non-ECHILD error path with errno+strerror for real failures.
- Reword parent comment: says 'significantly reduces' not 'avoids' the
  race since ECHILD is still possible (just less likely with waitpid(pid)).
Copilot AI review requested due to automatic review settings July 8, 2026 11:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
…status capture

The definitive fix: mirror the sigprocmask pattern already used in
start_exe2() in the same codebase.

Block SIGCHLD before fork() and restore after waitpid() completes:
- sigchld_handler cannot reap our child during the critical window
- waitpid(pid) reliably captures the exit status — ECHILD is impossible
- On unmask, any deferred SIGCHLD for other children fires normally so
  DHCP client selfheal notifications are not delayed or lost
- Remove signal(SIGCHLD, SIG_DFL) in child: execl() resets signal
  dispositions automatically and signal() is not async-signal-safe
  between fork() and exec() in a multi-threaded process

This eliminates the false error log without masking any real failures.
Copilot AI review requested due to automatic review settings July 8, 2026 12:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
…ror log

Revert to system()-based approach with explicit ECHILD handling.
The fork/exec/waitpid+sigprocmask approach was overly complex:
sigprocmask only blocks signals in the calling thread so ECHILD was
still possible in a multithreaded process, requiring ECHILD handling
regardless.

The minimal correct fix:
- Keep system() as the execution mechanism
- Capture errno immediately after system() returns -1
- On ECHILD: log WARNING and return 0 (success)
  sigchld_handler's processKilled() is a no-op for transient shell
  children (never registered as DHCP client pids) so this is safe
- On other errors: log ERROR with errno + strerror + command string
- Change parameter to const char * (no mutation)
- Add #include <errno.h> and <string.h>
Copilot AI review requested due to automatic review settings July 8, 2026 12:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c
Comment thread source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c Outdated
- ECHILD comment: clarify exit status is unknown (not that command ran
  successfully), add 'exit status unavailable' to the warning log
- Non-ECHILD error: change 'failed to fork shell' to 'fork/wait failed'
  since system() returns -1 for both fork and waitpid failures
Copilot AI review requested due to automatic review settings July 8, 2026 12:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

source/DHCPMgrUtils/dhcpmgr_v6_lease_handler.c:59

  • The Doxygen block immediately above exec_shell_cmd documents processv6LesSysevents (brief/params/return) rather than exec_shell_cmd, which makes the API documentation misleading now that exec_shell_cmd is being updated. Please update this block to describe exec_shell_cmd (or move it to the correct function).
/**
 * @brief processv6LesSysevents This function will set the sysevent values for IA_PD and IA_NA
 *
 * @param IPv6Events , size_t ,  const char*
 *

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