Skip to content

Static analysis fixes#883

Open
ejohnstown wants to merge 6 commits intowolfSSL:masterfrom
ejohnstown:static-fixes
Open

Static analysis fixes#883
ejohnstown wants to merge 6 commits intowolfSSL:masterfrom
ejohnstown:static-fixes

Conversation

@ejohnstown
Copy link
Contributor

Fix some bugs found by the wolfSSL static analyzer:

  • Uninitialized mode Variable in FatFS ff_open
  • Operator Precedence Bug
  • Missing wc_ecc_init() Before ECC Key Import
  • Unchecked wc_InitRsaKey Return Value
  • Missing break between switch cases
  • Missing ForceZero on plaintext password copy

Copilot AI review requested due to automatic review settings March 3, 2026 19:37
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Addresses several findings from the wolfSSL static analyzer across terminal handling, SFTP/FatFS file open logic, agent signing key setup, and SSHD authentication cleanup to improve correctness and safety.

Changes:

  • Fixes a missing break in control-sequence handling to prevent unintended switch fallthrough.
  • Updates SFTP/FatFS open-mode handling and corrects an operator-precedence issue in Win32 authentication.
  • Adds missing crypto initialization/checks (ECC init before import, check wc_InitRsaKey() return) and securely zeroes plaintext password buffers before free.

Reviewed changes

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

File Description
src/wolfterm.c Adds missing break to stop unintended fallthrough in CSI J handling.
src/wolfsftp.c Initializes mode and adjusts flag tests for FatFS open-mode selection.
src/agent.c Adds unused-parameter suppression in stubs; adds RSA init return check and ECC init before key import.
apps/wolfsshd/auth.c Zeroes plaintext password copy before freeing; fixes precedence in LsaLookupAuthenticationPackage result check.

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

1. Initialized mode variable to `FA_OPEN_EXISTING`, which is zero.
2. Changed the comparisons for the read/write flags to mask the read and
   write flags, then compare against the specific read or write flag.
   Setting the mode to RDWR would get handled only as read only.

Affected function: ff_open.
Added parens around an assignment to a variable before it is compared to
an expected value.

Affected function: SetupUserTokenWin.
1. Call `wc_ecc_init()` on an ECC key before importing it.
2. Incidental: `PostLock()` and `PostUnlock()` needed their agent pointers
   tagged as unused.

Affected functions: SignHashEcc. PostLock and PostUnlock.
Check the return value of `wc_InitRsaKey()`. It will initialize the
structure provided the pointer is non-null. Since the key is on the
stack, the later call to `wc_FreeRsaKey()` will succeed as well.

Affected function: SignHashRsa.
Addded a break to the 'J' case of a switch statement that handles
terminal display clearing for Windows. It was flowing into case 'K'
without an explicit fallthrough tag.

Affected function: wolfSSH_DoControlSeq.
When a copy of the user's password is freed, it wasn't getting force
zeroed. It might still exist in the heap after getting freed.  Added
a call to `ForceZero()`.

Affected function: CheckPasswordUnix.
Copy link

Copilot AI left a comment

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 4 out of 4 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/agent.c:702

  • If wc_InitRsaKey() fails (i.e., ret != 0), the code still falls through to the encSigSz <= 0 check (since encSigSz remains 0) and overwrites ret with WS_CRYPTO_FAILED. This loses the original failure code and can misreport the root cause. Suggestion: handle the wc_InitRsaKey() error via an early return (or preserve ret and skip the encode/signature error mapping when init fails), so init failures aren’t masked as “Bad Encode Sig.”
    int encSigSz = 0;
    int ret = 0;

    ret = wc_InitRsaKey(&key, heap);
    if (ret == 0) {
        mp_read_unsigned_bin(&key.n, rawKey->n, rawKey->nSz);
        mp_read_unsigned_bin(&key.e, rawKey->e, rawKey->eSz);
        mp_read_unsigned_bin(&key.d, rawKey->d, rawKey->dSz);
        mp_read_unsigned_bin(&key.p, rawKey->p, rawKey->pSz);
        mp_read_unsigned_bin(&key.q, rawKey->q, rawKey->qSz);
        mp_read_unsigned_bin(&key.u, rawKey->iqmp, rawKey->iqmpSz);

        encSigSz = wc_EncodeSignature(encSig, digest, digestSz,
                wc_HashGetOID(hashType));
    }
    if (encSigSz <= 0) {
        WLOG(WS_LOG_DEBUG, "Bad Encode Sig");
        ret = WS_CRYPTO_FAILED;
    }

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

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +1950 to 1971
if ((flag & WOLFSSH_O_RDWR) == WOLFSSH_O_RDONLY) {
mode = FA_READ;
}
else if ((flag & WOLFSSH_O_RDWR) == WOLFSSH_O_RDWR) {
mode = FA_READ | FA_WRITE;
}
else if ((flag & WOLFSSH_O_RDWR) == WOLFSSH_O_WRONLY) {
mode = FA_WRITE;
}
else {
return -1;
}

} else if (flag & WOLFSSH_O_RDWR) {
if ((flag & WOLFSSH_O_CREAT) &&
(flag & WOLFSSH_O_TRUNC)) {
mode = FA_READ | FA_WRITE | FA_CREATE_ALWAYS;

} else if ((flag & WOLFSSH_O_CREAT) &&
(flag & WOLFSSH_O_APPEND)) {
mode = FA_READ | FA_WRITE | FA_CREATE_NEW | FA_OPEN_APPEND;

} else {
mode = AM_ARC;
if ((flag & (WOLFSSH_O_WRONLY | WOLFSSH_O_CREAT))
== (WOLFSSH_O_WRONLY | WOLFSSH_O_CREAT)) {
if (flag & WOLFSSH_O_TRUNC) {
mode |= FA_CREATE_ALWAYS;
}
} else if (flag & WOLFSSH_O_WRONLY) {
if ((flag & WOLFSSH_O_CREAT) &&
(flag & WOLFSSH_O_TRUNC)) {
mode = FA_READ | FA_CREATE_ALWAYS | FA_WRITE;
} else if ((flag & WOLFSSH_O_CREAT) &&
(flag & WOLFSSH_O_APPEND)) {
mode = FA_READ | FA_WRITE | FA_CREATE_NEW | FA_OPEN_APPEND;
else if (flag & WOLFSSH_O_APPEND) {
mode |= FA_CREATE_NEW | FA_OPEN_APPEND;
}
} else {
return -1;
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The access-mode decoding is inconsistent with the prior bit-test logic and can produce incorrect behavior. Masking with WOLFSSH_O_RDWR and then comparing to WOLFSSH_O_RDONLY / WOLFSSH_O_WRONLY is only correct if WOLFSSH_O_RDWR is an “access-mode mask” (like POSIX O_ACCMODE); if WOLFSSH_O_RDONLY/_WRONLY/_RDWR are independent bits (as implied by the previous flag & WOLFSSH_O_* checks), the WRONLY/RDONLY branches may never match and the function can incorrectly return -1. Also, create/trunc/append handling now only applies to (WRONLY|CREAT) and no longer applies to RDWR|CREAT paths that previously set create flags. Suggestion: derive an access-mode value using a dedicated mask (e.g., WOLFSSH_O_ACCMODE or an explicit (WOLFSSH_O_RDONLY|WOLFSSH_O_WRONLY|WOLFSSH_O_RDWR) mask) and apply the create/trunc/append logic for both WRONLY and RDWR where appropriate (matching the previous behavior).

Copilot uses AI. Check for mistakes.
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