java-topology/defects/yabause-0001/test/YabauseNetlinkCredentialLogTest.java
russell@unturf.com 2f0da6752a zesarux: 1 CWE-312 defect, MOAD 0001/0002/0003/0005 CLEAN
yabause: 1 CWE-312 defect, MOAD 0001/0002/0003/0005 CLEAN
vita3k-0001: unit test added for pre-existing CWE-407 patch
2026-03-31 19:29:16 -04:00

217 lines
7.8 KiB
Java

import java.util.*;
/**
* Unit test for yabause CWE-312 defect yabause-0001.
*
* yabause-0001: In yabause/src/netlink.c, NetlinkWriteByte() handles the
* Saturn NetLink modem dial-up login sequence. When NETLINK_DEBUG is
* compiled in, two NETLINK_LOG calls write the Saturn internet credentials
* verbatim into the debug log:
*
* Line 582: NETLINK_LOG("login response: %s", inbuffer+inbufferstart)
* Line 592: NETLINK_LOG("password response: %s", inbuffer+inbufferstart)
*
* This test models the C logging logic and verifies the redaction fix.
*/
public class YabauseNetlinkCredentialLogTest {
/** Connection state machine, mirroring NL_CONNECTSTATUS_* enum. */
enum ConnectStatus {
IDLE, LOGIN1, LOGIN2, LOGIN3, CONNECTED
}
/** Simulates the NETLINK_LOG debug output sink. */
static class NetlinkLog {
private final List<String> entries = new ArrayList<>();
void log(String msg) {
entries.add(msg);
}
boolean anyEntryContains(String substring) {
for (String e : entries) {
if (e.contains(substring)) return true;
}
return false;
}
List<String> getEntries() {
return Collections.unmodifiableList(entries);
}
}
// ---------------------------------------------------------------
// DEFECTIVE: logs login name and password verbatim
// ---------------------------------------------------------------
static ConnectStatus defectiveHandleCarriageReturn(
NetlinkLog log, ConnectStatus status, String inbuffer) {
if (status == ConnectStatus.LOGIN1) {
// Line 582 — logs login name verbatim
log.log(String.format("login response: %s", inbuffer));
return ConnectStatus.LOGIN2;
}
if (status == ConnectStatus.LOGIN2) {
// Line 592 — logs password verbatim
log.log(String.format("password response: %s", inbuffer));
return ConnectStatus.LOGIN3;
}
if (status == ConnectStatus.LOGIN3) {
log.log(String.format("shell response: %s", inbuffer));
return ConnectStatus.CONNECTED;
}
return status;
}
// ---------------------------------------------------------------
// FIXED: redacts credentials, logs byte count only
// ---------------------------------------------------------------
static ConnectStatus fixedHandleCarriageReturn(
NetlinkLog log, ConnectStatus status, String inbuffer) {
if (status == ConnectStatus.LOGIN1) {
// Patched line 582: redacted
log.log(String.format("login response: [REDACTED %d bytes]",
inbuffer.length()));
return ConnectStatus.LOGIN2;
}
if (status == ConnectStatus.LOGIN2) {
// Patched line 592: redacted
log.log(String.format("password response: [REDACTED %d bytes]",
inbuffer.length()));
return ConnectStatus.LOGIN3;
}
if (status == ConnectStatus.LOGIN3) {
log.log(String.format("shell response: %s", inbuffer));
return ConnectStatus.CONNECTED;
}
return status;
}
// ---------------------------------------------------------------
// Test cases
// ---------------------------------------------------------------
static class TestCase {
final String loginName;
final String password;
TestCase(String loginName, String password) {
this.loginName = loginName;
this.password = password;
}
}
static final TestCase[] CASES = {
new TestCase("saturn_user", "hunter2"),
new TestCase("netlink_player", "S3cr3tP@ss"),
new TestCase("segaNet001", "CorrectHorseBattery"),
};
public static void main(String[] args) {
int pass = 0;
int fail = 0;
for (TestCase tc : CASES) {
// --- DEFECTIVE path ---
NetlinkLog defLog = new NetlinkLog();
ConnectStatus s = ConnectStatus.LOGIN1;
s = defectiveHandleCarriageReturn(defLog, s, tc.loginName);
s = defectiveHandleCarriageReturn(defLog, s, tc.password);
defectiveHandleCarriageReturn(defLog, s, "$ ");
boolean defExpLogin = defLog.anyEntryContains(tc.loginName);
boolean defExpPass = defLog.anyEntryContains(tc.password);
if (defExpLogin) {
System.out.println("PASS (defect confirmed): login name '"
+ tc.loginName + "' appears in defective log");
pass++;
} else {
System.out.println("FAIL (defect NOT confirmed): login name '"
+ tc.loginName + "' missing from defective log");
fail++;
}
if (defExpPass) {
System.out.println("PASS (defect confirmed): password '"
+ tc.password + "' appears in defective log");
pass++;
} else {
System.out.println("FAIL (defect NOT confirmed): password '"
+ tc.password + "' missing from defective log");
fail++;
}
// --- FIXED path ---
NetlinkLog fixLog = new NetlinkLog();
s = ConnectStatus.LOGIN1;
s = fixedHandleCarriageReturn(fixLog, s, tc.loginName);
s = fixedHandleCarriageReturn(fixLog, s, tc.password);
fixedHandleCarriageReturn(fixLog, s, "$ ");
boolean fixExpLogin = fixLog.anyEntryContains(tc.loginName);
boolean fixExpPass = fixLog.anyEntryContains(tc.password);
if (!fixExpLogin) {
System.out.println("PASS (fix confirmed): login name '"
+ tc.loginName + "' NOT in fixed log");
pass++;
} else {
System.out.println("FAIL (fix broken): login name '"
+ tc.loginName + "' still appears in fixed log");
fail++;
}
if (!fixExpPass) {
System.out.println("PASS (fix confirmed): password '"
+ tc.password + "' NOT in fixed log");
pass++;
} else {
System.out.println("FAIL (fix broken): password '"
+ tc.password + "' still appears in fixed log");
fail++;
}
// Redaction markers must be present
boolean hasLoginRedact = fixLog.anyEntryContains("login response: [REDACTED");
boolean hasPassRedact = fixLog.anyEntryContains("password response: [REDACTED");
if (hasLoginRedact) {
System.out.println("PASS (login redaction marker present)");
pass++;
} else {
System.out.println("FAIL (login redaction marker missing)");
fail++;
}
if (hasPassRedact) {
System.out.println("PASS (password redaction marker present)");
pass++;
} else {
System.out.println("FAIL (password redaction marker missing)");
fail++;
}
// Shell response (non-credential) must still log verbatim
boolean shellVisible = fixLog.anyEntryContains("shell response: $ ");
if (shellVisible) {
System.out.println("PASS (non-credential shell response visible)");
pass++;
} else {
System.out.println("FAIL (non-credential shell response missing)");
fail++;
}
}
System.out.println();
System.out.println("Results: " + pass + " passed, " + fail + " failed");
if (fail > 0) {
System.exit(1);
}
}
}