{"record":{"id":"6507c828f8e9b94e","repo":"shadowsocks/shadowsocks-rust","slug":"username","errorCode":null,"errorMessage":"username","messagePattern":"username","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/sys.rs","lineNumber":92,"sourceCode":"        }\n    }\n}\n\n/// setuid(), setgid() for a specific user or uid\n#[cfg(unix)]\npub fn run_as_user(uname: &str) -> std::io::Result<()> {\n    use log::error;\n    use std::{\n        ffi::{CStr, CString},\n        io::{Error, ErrorKind},\n    };\n\n    unsafe {\n        let pwd = match uname.parse::<libc::uid_t>() {\n            Ok(uid) => {\n                let mut pwd = libc::getpwuid(uid);\n                if pwd.is_null() {\n                    let uname = CString::new(uname).expect(\"username\");\n                    pwd = libc::getpwnam(uname.as_ptr())\n                }\n                pwd\n            }\n            Err(..) => {\n                let uname = CString::new(uname).expect(\"username\");\n                libc::getpwnam(uname.as_ptr())\n            }\n        };\n\n        if pwd.is_null() {\n            return Err(Error::new(ErrorKind::InvalidInput, format!(\"user {} not found\", uname)));\n        }\n\n        let pwd = &*pwd;\n\n        // setgid first, because we may not allowed to do it anymore after setuid\n        if libc::setgid(pwd.pw_gid as libc::gid_t) != 0 {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/src/sys.rs#L74-L110","documentation":"This panic comes from `.expect(\"username\")` on `CString::new(uname)` in `run_as_user` (src/sys.rs:92). `CString::new` fails only when the username string contains an interior NUL byte (`\\0`), which cannot be represented in a C string for `libc::getpwnam`. The panic occurs while looking up the user's passwd entry after parsing the `--user` value as a UID succeeded but `getpwuid` returned null.","triggerScenarios":"Calling `run_as_user` with a username containing an embedded NUL byte — realistically only via a CLI argument or config value built from binary data, an over-long truncated buffer, or programmatic callers passing a String with `\\0` inside.","commonSituations":"Rare: a `--user` argument sourced from corrupted input, environment substitution gone wrong, or a wrapper script inserting null bytes; also hit when a numeric-looking user string parsed as a UID but no matching passwd entry exists, sending execution into this fallback path.","solutions":["Pass a normal NUL-free username to --user, e.g. `--user nobody`.","If the user was given as a numeric UID, ensure a passwd entry exists or pass the username instead so getpwnam is used directly.","Sanitize the user string in the invoking script (strip control characters) before launching.","Patch the code to propagate `CString::new(...)` errors as `Error::new(ErrorKind::InvalidInput, ...)` instead of `.expect`."],"exampleFix":"// before\nlet uname = CString::new(uname).expect(\"username\");\n// after\nlet uname = CString::new(uname).map_err(|e| {\n    Error::new(ErrorKind::InvalidInput, format!(\"invalid user name: {e}\"))\n})?;","handlingStrategy":"validation","validationCode":"fn is_safe_username(u: &str) -> bool {\n    !u.is_empty() && !u.contains('\\0') && u.bytes().all(|b| b.is_ascii_graphic() || b == b'_')\n}\nassert!(is_safe_username(&user_arg), \"--user contains invalid characters\");","typeGuard":"fn nul_free(s: &str) -> Option<&str> {\n    if s.contains('\\0') { None } else { Some(s) }\n}","tryCatchPattern":"// If patching run_as_user\nlet uname = CString::new(uname).map_err(|e| {\n    Error::new(ErrorKind::InvalidInput, format!(\"user name contains NUL byte: {e}\"))\n})?;","preventionTips":["Validate the --user value (alphanumeric/underscore only) in launcher scripts.","Never build the user argument from binary or untrusted substituted input.","Prefer passing a real username over a numeric UID when switching privileges."],"tags":["unix","libc","panic","string-encoding"],"backgroundTag":"invalid-argument-value","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}