B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections. Squash of 94 local commits onto remote master.
193 lines
10 KiB
Bash
193 lines
10 KiB
Bash
#!/usr/bin/env bash
|
|
# CWE-407 scanner for unsandbox — runs INSIDE each language sandbox.
|
|
# Finds compiler/stdlib source and checks for O(n) membership in graph traversal.
|
|
# Usage: submit this as bash to each unsandbox language container.
|
|
set -euo pipefail
|
|
|
|
LANG="${1:-unknown}"
|
|
|
|
# ── Find source roots ─────────────────────────────────────────────────────────
|
|
find_source_roots() {
|
|
local roots=""
|
|
# Python
|
|
for d in /usr/lib/python* /usr/local/lib/python*; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Ruby stdlib + pre-cached gems (.rb source)
|
|
for d in /usr/lib/ruby /usr/local/lib/ruby; do [ -d "$d" ] && roots="$roots $d"; done
|
|
for d in /var/lib/gems /usr/lib/ruby/gems /usr/local/lib/ruby/gems; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Perl
|
|
for d in /usr/lib/perl5 /usr/share/perl5 /usr/local/lib/perl5; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Haskell/GHC
|
|
for d in /usr/lib/ghc* /usr/local/lib/ghc* /opt/ghc*; do [ -d "$d" ] && roots="$roots $d"; done
|
|
for d in /root/.cabal/packages /root/.cabal/store; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# OCaml
|
|
for d in /usr/lib/ocaml /usr/local/lib/ocaml; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Erlang (erlang-src puts .erl files under /usr/lib/erlang/lib/*/src/)
|
|
for d in /usr/lib/erlang /usr/local/lib/erlang; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Elixir stdlib + pre-cached hex deps (.ex source)
|
|
for d in /usr/lib/elixir /usr/local/lib/elixir /opt/elixir*; do [ -d "$d" ] && roots="$roots $d"; done
|
|
for d in /root/.mix/deps /usr/share/elixir-deps; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Node/npm
|
|
for d in /usr/lib/node_modules /usr/local/lib/node_modules ~/.nvm/versions/node/*/lib/node_modules; do
|
|
[ -d "$d" ] && roots="$roots $d"
|
|
done
|
|
# Rust std (rust-src component) + pre-cached crate registry (.rs source for all crates)
|
|
for d in /usr/lib/rust* /root/.rustup/toolchains/*/lib/rustlib/src; do [ -d "$d" ] && roots="$roots $d"; done
|
|
for d in /root/.cargo/registry/src; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Go stdlib + pre-cached module source
|
|
for d in /usr/local/go/src /usr/lib/go/src; do [ -d "$d" ] && roots="$roots $d"; done
|
|
for d in /root/go/pkg/mod /root/.cache/go/pkg/mod; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Lua
|
|
for d in /usr/share/lua* /usr/lib/lua*; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# PHP
|
|
for d in /usr/share/php* /usr/lib/php*; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# R
|
|
for d in /usr/lib/R /usr/local/lib/R; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Julia (binary tarball stdlib + pre-cached packages at ~/.julia/packages/)
|
|
for d in /opt/julia-*/share/julia /usr/share/julia /usr/local/share/julia; do [ -d "$d" ] && roots="$roots $d"; done
|
|
for d in /root/.julia/packages; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Kotlin (SDKMAN + extracted stdlib sources)
|
|
for d in /usr/share/kotlin /root/.sdkman/candidates/kotlin/current /opt/kotlin*; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Scala
|
|
for d in /usr/share/scala /opt/scala*; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Groovy (apt + extracted sources JAR)
|
|
for d in /usr/share/groovy /usr/share/groovy/src /opt/groovy*; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Clojure (linux-install + extracted sources JAR)
|
|
for d in /usr/share/clojure /usr/share/clojure/src /usr/lib/clojure /usr/local/lib/clojure; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Common Lisp (SBCL + Quicklisp packages)
|
|
for d in /usr/lib/sbcl /root/quicklisp/dists; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Nim stdlib + nimble packages (.nim source)
|
|
for d in /opt/Nim/lib /usr/lib/nim; do [ -d "$d" ] && roots="$roots $d"; done
|
|
for d in /root/.nimble/pkgs /root/.nimble/pkgs2; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Crystal (install script puts stdlib at /usr/share/crystal/src/ or /usr/lib/crystal/)
|
|
for d in /usr/share/crystal /usr/lib/crystal; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# D (LDC Phobos stdlib at /usr/include/dlang/)
|
|
for d in /usr/include/dlang /usr/share/dmd; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Zig (binary tarball stdlib at /opt/zig-linux-x86_64-VERSION/lib/)
|
|
for d in /opt/zig-linux-x86_64-*/lib /usr/lib/zig; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Dart (SDK stdlib at /usr/lib/dart/lib/)
|
|
for d in /usr/lib/dart/lib /usr/lib/dart; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# V (git clone + vlib)
|
|
for d in /opt/vlang/vlib; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Raku
|
|
for d in /usr/share/perl6 /usr/lib/raku /root/.raku; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Tcl
|
|
for d in /usr/lib/tcl8.6 /usr/share/tcltk /usr/lib/tcltk; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Prolog
|
|
for d in /usr/lib/swi-prolog/library /usr/share/swi-prolog; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Forth
|
|
for d in /usr/share/gforth; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# PowerShell
|
|
for d in /opt/microsoft/powershell; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# F# extracted sources
|
|
for d in /usr/share/fsharp/src; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# C# extracted NuGet sources
|
|
for d in /usr/share/dotnet-src; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# Deno std cache
|
|
for d in /root/.deno/deps; do [ -d "$d" ] && roots="$roots $d"; done
|
|
# C/C++ headers
|
|
for d in /usr/include; do [ -d "$d" ] && roots="$roots $d"; done
|
|
echo $roots
|
|
}
|
|
|
|
# ── Graph traversal keywords ───────────────────────────────────────────────────
|
|
GRAPH_KW="tarjan|scc|strongly.connected|dfs|topolog|topo.sort|cycle|closure|reachab|postorder|dominator|liveness|digraph"
|
|
|
|
# ── Membership patterns by extension ──────────────────────────────────────────
|
|
check_file() {
|
|
local f="$1"
|
|
local ext="${f##*.}"
|
|
local mem=""
|
|
case "$ext" in
|
|
py) mem='[^a-z]in (stack|path|visited|seen|queue|nodes|list)\b|\.append\b.*in path' ;;
|
|
rb) mem='\.include\?|\.member\?|Array.*include' ;;
|
|
pm|pl) mem='grep\s*{.*eq\b|List::Util.*first|foreach.*eq\b|member\([A-Z]' ;;
|
|
hs) mem='`elem`|\belem\b' ;;
|
|
ml|mli) mem='List\.mem\b|List\.exists\b' ;;
|
|
erl) mem='lists:member\b|lists:any\b' ;;
|
|
ex|exs) mem='Enum\.member\?|List\.member\?|[^a-z]in\s+(stack|path|list|visited)' ;;
|
|
java) mem='\.contains\(|ArrayList.*contains|List.*contains|Deque.*contains' ;;
|
|
kt|kts) mem='\.contains\(|[^a-z]in\s+(stack|path|list|visited)' ;;
|
|
scala) mem='\.contains\(|List.*contains|Seq.*contains|ArrayBuffer.*contains' ;;
|
|
cpp|cc|cxx|c|h|hpp) mem='std::find[(]|[.]count[(]|find.*begin.*end|linear_search' ;;
|
|
rs) mem='\.contains\(&|iter\(\)\.any\(|iter\(\)\.position\(' ;;
|
|
go) mem='slices\.Contains|for.*range.*==\s*\w' ;;
|
|
js|ts|mjs) mem='\.includes\(|\.indexOf\(|\.find\(' ;;
|
|
lua) mem='table\.search\|linear.*find' ;;
|
|
php) mem='in_array\(|array_search\(' ;;
|
|
r|R) mem='%in%.*c(' ;;
|
|
# ── Work Item 2: extended language patterns ───────────────────────────────
|
|
jl) mem='[^a-z]in\(|findfirst\b|indexin\b|\.in\b' ;;
|
|
nim) mem='[^a-z]in\s+\w|\.contains\b|\.find\b' ;;
|
|
cr) mem='\.includes\?\b|\.index\b|Array.*includes\?' ;;
|
|
d) mem='canFind\b|std\.algorithm\.find\b|\.canFind\b' ;;
|
|
zig) mem='for\s*\([^)]+\)\s*\|[^|]+\|[^{]*==\s*\w' ;;
|
|
dart) mem='\.contains\(|\.indexOf\(' ;;
|
|
fs) mem='List\.contains\b|List\.exists\b|Seq\.contains\b|SEARCH\b' ;;
|
|
cs) mem='\.Contains\(|IEnumerable.*Contains|List<.*>.*Contains' ;;
|
|
groovy) mem='\.contains\(|\.indexOf\(' ;;
|
|
clj) mem='(some\s+#{|member\b|\(\.contains\b' ;;
|
|
lisp) mem='(member\s|(find\s|(position\s' ;;
|
|
scm) mem='(member\s|(memq\s|(memv\s' ;;
|
|
raku|pm6) mem='\(elem\)\b|@.*\.first\b|\$.*~~\s*@' ;;
|
|
tcl) mem='lsearch\s|-exact\b' ;;
|
|
ps1) mem='-contains\b|\.IndexOf\(' ;;
|
|
v) mem='\.contains\(|\.index\(' ;;
|
|
cob) mem='SEARCH\s|PERFORM\s.*VARYING\b' ;;
|
|
f90|f|for) mem='ANY\s*\(|COUNT\s*\(|FINDLOC\s*(' ;;
|
|
*) return ;;
|
|
esac
|
|
|
|
# Check if file has graph traversal context
|
|
local graph_lines
|
|
graph_lines=$(grep -inE "$GRAPH_KW" "$f" 2>/dev/null | cut -d: -f1 | head -5 || true)
|
|
[ -z "$graph_lines" ] && return
|
|
|
|
while IFS= read -r lineno; do
|
|
local s=$(( lineno > 20 ? lineno - 20 : 1 ))
|
|
local e=$(( lineno + 20 ))
|
|
local hit
|
|
hit=$(sed -n "${s},${e}p" "$f" 2>/dev/null | grep -iE "$mem" 2>/dev/null | head -1 | sed 's/^\s*//' || true)
|
|
if [ -n "$hit" ]; then
|
|
echo "CANDIDATE ${f}:${lineno} ${hit}"
|
|
fi
|
|
done <<< "$graph_lines"
|
|
}
|
|
export -f check_file
|
|
export GRAPH_KW
|
|
|
|
# ── Main scan ─────────────────────────────────────────────────────────────────
|
|
echo "# CWE-407 scan — lang=${LANG} host=$(hostname) date=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
echo "#"
|
|
|
|
ROOTS=$(find_source_roots)
|
|
if [ -z "$ROOTS" ]; then
|
|
echo "# no source roots found"
|
|
exit 0
|
|
fi
|
|
|
|
echo "# roots: $ROOTS"
|
|
echo "#"
|
|
|
|
find $ROOTS -type f \( \
|
|
-name "*.py" -o -name "*.rb" -o -name "*.pm" -o -name "*.pl" \
|
|
-o -name "*.hs" -o -name "*.ml" -o -name "*.mli" \
|
|
-o -name "*.erl" -o -name "*.ex" -o -name "*.exs" \
|
|
-o -name "*.java" -o -name "*.kt" -o -name "*.kts" -o -name "*.scala" \
|
|
-o -name "*.cpp" -o -name "*.cc" -o -name "*.c" -o -name "*.h" -o -name "*.hpp" \
|
|
-o -name "*.rs" -o -name "*.go" -o -name "*.js" -o -name "*.ts" -o -name "*.mjs" \
|
|
-o -name "*.lua" -o -name "*.php" -o -name "*.r" -o -name "*.R" \
|
|
-o -name "*.jl" -o -name "*.nim" -o -name "*.cr" \
|
|
-o -name "*.d" -o -name "*.zig" -o -name "*.dart" \
|
|
-o -name "*.fs" -o -name "*.cs" -o -name "*.groovy" \
|
|
-o -name "*.clj" -o -name "*.lisp" -o -name "*.scm" \
|
|
-o -name "*.raku" -o -name "*.pm6" -o -name "*.tcl" \
|
|
-o -name "*.ps1" -o -name "*.v" -o -name "*.cob" \
|
|
-o -name "*.f90" -o -name "*.f" -o -name "*.for" \
|
|
\) -not -path "*/.git/*" -not -path "*/test*" -not -path "*/doc*" \
|
|
-not -path "*/bench*" -not -path "*/example*" 2>/dev/null \
|
|
| sort | while IFS= read -r f; do
|
|
check_file "$f"
|
|
done
|
|
|
|
echo "#"
|
|
echo "# scan complete"
|