Home / Alt manpages / upx-ucl(1)

  • upx-ucl(1)
  • User command
  • linux

Compress a Linux executable safely with UPX

By the end, you will have inspected a Linux executable, compressed a disposable copy with UPX, checked that the packed file can be decompressed, and restored the original bytes. The installed manpage documents UPX 4.2.2, and the commands below target that behaviour.

Allow about 10 minutes for one file. You need the upx-ucl package, a trusted executable that you are allowed to modify, enough free storage for a temporary copy, and a shell account that can read and write the working directory. No root access is needed unless the file itself is protected; avoid changing permissions just to make this experiment work.

Checkpoint 1: confirm the tool and choose a copy

UPX handles executable files as input, and the default operation compresses them in place. Make a copy before running a command that changes bytes. Substitute a real path for PATH/TO/program; do not type the placeholder literally.

upx --version
cp --reflink=auto -- PATH/TO/program /tmp/program.upx-test
chmod --reference=PATH/TO/program /tmp/program.upx-test

On this installation, the manpage identifies the release as upx 4.2.2. The copy should exist with the source file's mode bits:

ls -l -- /tmp/program.upx-test
file -- /tmp/program.upx-test

UPX inherits the security context of every file it handles. Listing and testing are not a substitute for malware scanning, and compressing an untrusted executable can still expose you to its security context. Work on trusted files only.

Checkpoint 2: inspect before changing anything

Use -l to list the packed and unpacked sizes. This is read-only with respect to the executable, so it is a useful first check.

upx -l -- /tmp/program.upx-test

For an already packed file, the listing includes compressed and uncompressed sizes and a compression ratio. For a normal executable, the output tells you whether UPX recognises the format. Keep the output if you need to compare a later build.

Linux ELF executables normally use the specialised linux/elf386 format automatically. The manpage also describes linux/sh386 for recognised shell scripts and a generic linux/386 fallback. That distinction affects runtime resources: the ELF and shell formats decompress into memory, while the generic format needs temporary space in /tmp and support for /proc.

Checkpoint 3: compress the disposable copy

Compression changes the target file in place. Start with the default level rather than tuning a release build before you know whether the executable works when packed.

upx -- /tmp/program.upx-test

UPX uses level -8 by default for files smaller than 512 KiB and -7 otherwise. Levels -1 to -3 favour speed, -4 to -6 balance speed and ratio, and -7 to -9 favour a smaller result. --best can take a long time, so reserve it for a measured release workflow.

Check what happened and run the integrity test:

upx -l -- /tmp/program.upx-test
upx -t -- /tmp/program.upx-test

A successful test exits with status 0. It checks the compressed and uncompressed data that will be used during execution, not every byte of the file, so do not treat it as virus checking. The documented statuses are 0 for success, 1 for an error and 2 for a warning.

Runtime boundaries to check before deployment

Run the packed copy in a test environment using the same arguments and account that will use the released file. A compressed ELF program may need more RAM or swap because its pages are not shared in the same way as an ordinary file-backed executable. The generic Linux format also needs free /tmp space for the uncompressed program during execution. Programs launched many times in parallel, such as shells and build tools, are poor candidates for casual packing.

Do not pack set-user-ID, set-group-ID or sticky-bit programs: the manpage says UPX rejects these because of security implications. Do not assume that packing a script preserves portability; the Linux script format can lose the portability you had when the script was plain text. Self-reading programs can also fail because the file no longer has its original layout.

Overlays are extra data after an executable's logical end. UPX copies them by default, but an application may not access copied overlay data correctly. If the file must have no overlay, --overlay=skip refuses to compress one. Avoid --overlay=strip unless you have a tested recovery copy: stripping it can make the program unusable.

Checkpoint 4: restore or publish

The safest undo is to discard the disposable copy and start again from the untouched source:

rm -- /tmp/program.upx-test

If you intentionally need to unpack the copy, use -d. This is another state-changing operation, so test the result and compare it with a checksum captured before compression.

sha256sum -- PATH/TO/program > /tmp/program.sha256
upx -d -- /tmp/program.upx-test
upx -t -- /tmp/program.upx-test
sha256sum --check --status /tmp/program.sha256 --ignore-missing

For a release, make the checksum before packing and retain the original build artefact. UPX documents byte-identical decompression for the Linux formats, but --exact is still work in progress and is not supported for every format. The checksum comparison is the useful project-specific proof.

Defaults that can quietly change a run

The UPX environment variable supplies options before explicit command-line options. An old setting can therefore alter an apparently simple command. Inspect it before a reproducible build:

env | grep '^UPX=' || true
upx --no-env -t -- /tmp/program.upx-test

Use --no-env when you need the command line to ignore that variable. Explicit command-line options override environment defaults, but making the choice visible in a build script is easier to audit.

Done means

  • The tool reports the expected version and the input is trusted.
  • You inspected the file before changing it and worked on a copy.
  • upx -t returned status 0 after compression.
  • You checked RAM, swap, /tmp, /proc, overlays and self-reading behaviour for the target.
  • The original build artefact remains available, or a checksum proves the restored copy matches it.