mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-11-12 09:24:24 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88d8c69ebd | ||
|
|
59d47e91d6 |
No files matched your search
@@ -635,13 +635,56 @@ function createSessionOpsApi(ctx) {
|
||||
_rc_cwd=$(readlink "/proc/$1/cwd" 2>/dev/null)
|
||||
if [ -n "$_rc_cwd" ]; then printf '%s\\n' "$_rc_cwd"; return 0; fi
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
# An unknown-type record can put a readlink error in its name field.
|
||||
# Only a confirmed directory name is usable as an upload destination.
|
||||
# lsof can label an unreadable root shell's cwd as a directory while
|
||||
# appending "(readlink: Permission denied)" to its name on AL2023
|
||||
# (#3493). Check annotation-shaped names before using them: real
|
||||
# directories can also end in text such as " (owner: alice)".
|
||||
_rc_cwd=$(LC_ALL=C lsof -a -p "$1" -d cwd -Fnt 2>/dev/null | awk '
|
||||
/^f/ { is_dir=0 }
|
||||
/^t/ { is_dir=($0 == "tDIR" || $0 == "tVDIR") }
|
||||
/^n/ && is_dir { print substr($0, 2); exit }
|
||||
/^n/ && is_dir {
|
||||
name=substr($0, 2)
|
||||
if (name ~ / \\([A-Za-z][A-Za-z0-9]*: .*\\)$/) print "?" name
|
||||
else print name
|
||||
exit
|
||||
}
|
||||
')
|
||||
case "$_rc_cwd" in
|
||||
\\?*)
|
||||
_rc_cwd=\${_rc_cwd#?}
|
||||
# lsof escapes non-ASCII bytes under LC_ALL=C. Decode only for
|
||||
# the existence check; keep the original for the client decoder.
|
||||
_rc_test_cwd=$(printf '%s' "$_rc_cwd" | LC_ALL=C awk '
|
||||
function hex(c) { return index("0123456789abcdef", tolower(c)) - 1 }
|
||||
{
|
||||
for (i=1; i<=length($0); i++) {
|
||||
c=substr($0,i,1)
|
||||
if (c!="\\\\") { printf "%s", c; continue }
|
||||
e=substr($0,++i,1)
|
||||
if (e=="x") {
|
||||
hi=hex(substr($0,++i,1)); lo=hex(substr($0,++i,1))
|
||||
if (hi<0 || lo<0) exit 1
|
||||
printf "%c", hi*16+lo
|
||||
} else if (e=="\\\\") printf "\\\\"
|
||||
else if (e=="n") printf "\\n"
|
||||
else if (e=="r") printf "\\r"
|
||||
else if (e=="t") printf "\\t"
|
||||
else if (e=="b") printf "%c", 8
|
||||
else if (e=="f") printf "%c", 12
|
||||
else if (e=="v") printf "%c", 11
|
||||
else if (e ~ /^[0-7]$/) {
|
||||
n=e+0
|
||||
for (j=0; j<2 && substr($0,i+1,1) ~ /^[0-7]$/; j++) {
|
||||
n=n*8+substr($0,++i,1)
|
||||
}
|
||||
printf "%c", n
|
||||
} else exit 1
|
||||
}
|
||||
}
|
||||
') || return 1
|
||||
[ -d "$_rc_test_cwd" ] || return 1
|
||||
;;
|
||||
esac
|
||||
if [ -n "$_rc_cwd" ]; then printf 'NETCATTY_LSOF_CWD=%s\\n' "$_rc_cwd"; return 0; fi
|
||||
fi
|
||||
return 1
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { EventEmitter } = require("node:events");
|
||||
const fs = require("node:fs");
|
||||
const os = require("node:os");
|
||||
const path = require("node:path");
|
||||
|
||||
const { createSessionOpsApi, decodeLsofFileName } = require("./sessionOps.cjs");
|
||||
|
||||
@@ -123,7 +126,7 @@ test("session cwd probe decodes the marked lsof pathname", async () => {
|
||||
assert.deepEqual(result, { success: true, cwd: "/srv/中文" });
|
||||
});
|
||||
|
||||
test("lsof cwd fallback accepts only directory records, not diagnostic names (#3237)", async () => {
|
||||
test("lsof cwd fallback accepts only directory records, not diagnostic names (#3237, #3493)", async (t) => {
|
||||
let script;
|
||||
const api = makeApi({
|
||||
shellPid: "4242",
|
||||
@@ -144,13 +147,35 @@ test("lsof cwd fallback accepts only directory records, not diagnostic names (#3
|
||||
const helper = script.match(/ read_shell_cwd\(\) \{[\s\S]*?\n \}/)?.[0];
|
||||
assert.ok(helper, "exercise the actual remote cwd helper");
|
||||
const { spawnSync } = require("node:child_process");
|
||||
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), "netcatty-lsof-cwd-"));
|
||||
t.after(() => fs.rmSync(fixtureRoot, { recursive: true, force: true }));
|
||||
const realParenthesizedPath = path.join(fixtureRoot, "release (owner: alice)");
|
||||
const realDiagnosticShapedPath = path.join(fixtureRoot, "job (stat: ready)");
|
||||
const realErrorShapedPath = path.join(fixtureRoot, "job (readlink: Permission denied)");
|
||||
const realUnicodePath = path.join(fixtureRoot, "中文 (owner: alice)");
|
||||
fs.mkdirSync(realParenthesizedPath);
|
||||
fs.mkdirSync(realDiagnosticShapedPath);
|
||||
fs.mkdirSync(realErrorShapedPath);
|
||||
fs.mkdirSync(realUnicodePath);
|
||||
for (const [output, expected] of [
|
||||
["p4242\nfcwd\ntunknown\nn/proc/4242/cwd (readlink: Permission denied)\n", null],
|
||||
["p4242\nfcwd\ntunknown\nn/proc/4242/cwd (readlink: No such file or directory)\n", null],
|
||||
// AL2023: lsof reports the VDIR type from the fd but annotates the name
|
||||
// when the login user cannot readlink a root-owned shell's cwd (#3493).
|
||||
["p683339\nfcwd\ntVDIR\nn/proc/683339/cwd (readlink: Permission denied)\n", null],
|
||||
["p4242\nfcwd\ntDIR\nn/proc/4242/cwd (readlink: Permission denied)\n", null],
|
||||
["p4242\nfcwd\ntDIR\nn/proc/4242/cwd (readlink: No such file or directory)\n", null],
|
||||
["p4242\nfcwd\ntDIR\nn/proc/4242/cwd (stat: Operation not permitted)\n", null],
|
||||
["p4242\nfcwd\ntDIR\nn/srv/app (stat: Operation not permitted)\n", null],
|
||||
["p4242\nfcwd\ntDIR\nn/srv/app (readlink: Permission denied)\n", null],
|
||||
["p4242\nfcwd\nn/proc/4242/cwd\n", null],
|
||||
["p4242\nfcwd\ntDIR\nn/srv/app\n", "/srv/app"],
|
||||
["p4242\nfcwd\ntVDIR\nn/usr/home/alice\n", "/usr/home/alice"],
|
||||
["p4242\nfcwd\ntDIR\nn/tmp/literal (readlink: Permission denied)\n", "/tmp/literal (readlink: Permission denied)"],
|
||||
["p4242\nfcwd\ntDIR\nn/srv/backup (old)\n", "/srv/backup (old)"],
|
||||
["p4242\nfcwd\ntDIR\nn" + realParenthesizedPath + "\n", realParenthesizedPath],
|
||||
["p4242\nfcwd\ntDIR\nn" + realDiagnosticShapedPath + "\n", realDiagnosticShapedPath],
|
||||
["p4242\nfcwd\ntDIR\nn" + realErrorShapedPath + "\n", realErrorShapedPath],
|
||||
["p4242\nfcwd\ntDIR\nn" + realUnicodePath.replace("中文", "\\xe4\\xb8\\xad\\xe6\\x96\\x87") + "\n", realUnicodePath.replace("中文", "\\xe4\\xb8\\xad\\xe6\\x96\\x87")],
|
||||
["p4242\nfcwd\ntDIR\nn/tmp/\\xe4\\xb8\\xad\\xe6\\x96\\x87\n", "/tmp/\\xe4\\xb8\\xad\\xe6\\x96\\x87"],
|
||||
]) {
|
||||
const result = spawnSync("sh", ["-c", `
|
||||
@@ -159,7 +184,7 @@ test("lsof cwd fallback accepts only directory records, not diagnostic names (#3
|
||||
${helper}
|
||||
read_shell_cwd 4242
|
||||
`], { encoding: "utf8", env: { ...process.env, LSOF_TEST_OUTPUT: output } });
|
||||
assert.equal(result.status, expected === null ? 1 : 0, output);
|
||||
assert.equal(result.status, expected === null ? 1 : 0, `${output}\n${result.stderr}`);
|
||||
assert.equal(result.stdout, expected === null ? "" : `NETCATTY_LSOF_CWD=${expected}\n`, output);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user