Binary Won't Execute¶
A program exists on disk but does not start. Interviewers use this scenario because several unrelated causes (permissions, mount options, architecture, interpreter, libraries, glibc version) produce similar one-line errors, and the fix depends on reading which one appeared.
Symptom¶
"We copied a set of tools to a new server. None of them run, and the errors all look like 'not found' or 'permission denied'. What do you check?"
Clarifying Questions¶
- What is the exact message and exit status?
126means found but not executable;127means something was not found, often not the file itself. - Where did the files come from? A different distribution, architecture or a Windows editor each points to a different cause.
- Scripts or compiled binaries? Scripts depend on their interpreter line; binaries on their loader and libraries.
- Where do they live?
/tmp, removable media and container volumes are often mountednoexec.
Diagnostic Path¶
Six tools in /opt/tools and one on a tmpfs mount, each started from a script:
for f in ./report-gen ./metrics-agent ./backup-cli ./deploy.sh ./musl-tool ./cleanup.sh /mnt/scratch/health-check; do $f >/dev/null; echo "rc=$?"; done
Output:
./report-gen: error while loading shared libraries: libgreet.so.1: cannot open shared object file: No such file or directory
rc=127
./metrics-agent: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.42' not found (required by ./metrics-agent)
rc=1
/tmp/scen.sh: line 14: ./backup-cli: cannot execute binary file: Exec format error
rc=126
/tmp/scen.sh: line 14: ./deploy.sh: cannot execute: required file not found
rc=127
/tmp/scen.sh: line 14: ./musl-tool: cannot execute: required file not found
rc=127
/tmp/scen.sh: line 14: ./cleanup.sh: Permission denied
rc=126
/tmp/scen.sh: line 14: /mnt/scratch/health-check: Permission denied
rc=126
1. Check the Execute Bit and the Mount¶
ls -l cleanup.sh /mnt/scratch/health-check
findmnt -no OPTIONS -T /mnt/scratch/health-check
Output:
-rwxr-xr-x 1 root root 26936 Sep 16 18:45 /mnt/scratch/health-check
-rw-r--r-- 1 laborant laborant 25 Sep 16 18:45 cleanup.sh
rw,noexec,relatime
cleanup.sh has no x bit. health-check has one, but its filesystem is mounted noexec, which gives the same Permission denied.
2. Check the File Type and Architecture¶
file backup-cli deploy.sh musl-tool | cut -c1-90
uname -m
Output:
backup-cli: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically link
deploy.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
musl-tool: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, i
x86_64
backup-cli is built for ARM, which explains Exec format error. deploy.sh has Windows line endings.
3. Check the Interpreter¶
"required file not found" means the kernel could not find the program named in the shebang or the ELF interpreter field.
head -1 deploy.sh | cat -A
readelf -l musl-tool | grep interpreter
ls -l /lib/ld-musl-x86_64.so.1
strace -f -e trace=execve ./deploy.sh 2>&1 | tail -2
Output:
#!/bin/bash^M$
[Requesting program interpreter: /lib/ld-musl-x86_64.so.1]
ls: cannot access '/lib/ld-musl-x86_64.so.1': No such file or directory
strace: exec: No such file or directory
+++ exited with 1 +++
deploy.sh asks for /bin/bash\r, which does not exist; musl-tool requests the musl loader, as any binary built on Alpine does, and this server has only glibc.
4. Check Shared Libraries¶
ldd ./report-gen | grep 'not found'
Output:
libgreet.so.1 => not found
5. Check the glibc Version¶
objdump -T metrics-agent | grep -o 'GLIBC_[0-9.]*' | sort -uV | tail -1
ldd --version | head -1
Output:
GLIBC_2.42
ldd (Ubuntu GLIBC 2.39-0ubuntu8.9) 2.39
The binary was built on a distribution with glibc 2.42 or newer (Fedora 44 here); the server has 2.39.
Root Causes¶
| Branch | Evidence | Fix |
|---|---|---|
| No execute bit | ls -l shows no x; exit 126 | chmod +x, or run through the interpreter |
noexec mount | findmnt shows noexec; exit 126 | Move the file, or remount without noexec if policy allows |
| Wrong architecture | file names another CPU; Exec format error | Download the build for uname -m |
| Windows line endings | cat -A shows ^M; required file not found | sed -i 's/\r$//' or dos2unix |
| Missing ELF interpreter | readelf -l names a loader that does not exist | Build for glibc, or install the musl runtime |
| Missing library | ldd shows not found; exit 127 | Install the package or register the directory with ldconfig |
| glibc too old | version GLIBC_x not found | Build on the oldest target, link statically, or use a container |
Fix¶
sed -i 's/\r$//' deploy.sh && ./deploy.sh
chmod +x cleanup.sh && ./cleanup.sh
sudo cp -a ~/libdemo/libgreet.so* /usr/local/lib/ && sudo ldconfig && ./report-gen
bash /mnt/scratch/health-check
Output:
deploy
cleanup
hello, world
/mnt/scratch/health-check: /mnt/scratch/health-check: cannot execute binary file
Passing a file to bash works only for scripts, even on a noexec mount; bash cannot run an ELF binary, so health-check has to move to an executable filesystem.
Prevention¶
- Publish builds per architecture and name them with
uname -mvalues; checkfilein the deployment pipeline. - Build release binaries on the oldest supported distribution, or statically, and record the minimum glibc.
- Enforce LF line endings with
.gitattributes(*.sh text eol=lf) and a pre-commit check. - Install tools with
install -m 0755into/usr/local/binor/opt, never onnoexecmounts. - Ship libraries with the application (
$ORIGINrunpath) or as packages that runldconfig.
Related¶
- Command Resolution: 126, 127 and
required file not found - Shared Libraries: loader search and glibc versions
- File Types:
fileandExec format error - Basic Permissions: the execute bit
Captured on Rocky Linux 10.2, Fedora 44 (where noted) and Ubuntu 24.04.4 LTS (iximiuz Labs microVMs, kernel 6.1.167), 2026-09.