The ELF Virus Writing HOWTO: sparc-sunos5.7
Prev |  | Next

# 1. Variables & packages

| Once it hits the fan, the only rational choice is to sweep it up, package it, and sell it as fertilizer.
| anonymous

This document tries to cover multiple platforms through conditional compilation. There is a `configure.pl` that determines the host type and sets up a `config.sh` containing environment variable definitions. There also are equivalent `config.csh`, `config.h`, `config.mak`, `config.sed`, and `config.xml`. The `Makefile` then uses individual sub-directories for each platform. The name of these directories (and some other platform specific values) is retrieved through environment variables. The directory structure is not without meaning.

- `src/` is for source code, i.e. text files written and maintained by humans.

- `pre/sparc-sunos5.7/` is directory `src/` pre-processed with `config.sed`. In `pre/` all program names are absolute. Magic numbers and platform specific constants are verbatim.

- `tmp/sparc-sunos5.7/` is the only place to hold binaries, i.e. executables and `.o` files.

- `out/sparc-sunos5.7/` is for the output of executables, hex dumps, disassembly listings, text processing.

The files in `src/` are obfuscated with obscene amounts of variable references like `${TEVWH_ELF_BASE}` or even `${TEVWH_PATH_LS}`. I admit that using variables instead of plain program names makes shell scripts harder to read. But this is necessary to maintain a minimum level of reproducibility on SunOS. Anyway, directory `pre/` makes that `10000` and `/usr/xpg4/bin/ls`, so you will probably never encounter this syntax nightmare. An almost complete list of used variables is given below.

Table 1. Variables prefixed with `TEVWH_`

Variable name | Value on this platform | Variable name | Value on this platform
--- | --- | --- | ---
`ARCH` | `sparc` | `ASM_COMMENT` | `!`
`ASM_FLAVOR` | `` | `ASM_RETURN` | `\(restore\|unimp\)`
`ASM_STYLE` | `att` | `BYTE_ORDER` | `M`
`CFLAGS` | `-O1 -I out/sparc-sunos5.7 -D NDEBUG` | `ELF_ADDR_SIZE` | `32`
`ELF_ALIGN` | `0x10000` | `ELF_BASE` | `0x10000`
`ELF_EHDR` | `Elf32_Ehdr` | `ELF_MAGIC` | `0x10001`
`ELF_PHDR` | `Elf32_Phdr` | `ELF_SHDR` | `Elf32_Shdr`
`HOSTTYPE` | `SunOS/sparc` | `OS_CODE` | `sparc-sunos5.7`
`OS_NAME` | `SunOS 5.7` | `OS_PKG_SYS` | `SunOS`
`OS_VERSION` | `5.7` | `OUT` | `out/sparc-sunos5.7`
`OUT_XML` | `out/sparc-sunos5.7/xml` | `PAGESIZE` | `0x1000`
`PRE` | `pre/sparc-sunos5.7` | `PROC_EXE` | `/proc/self/object/a.out`
`TMP` | `tmp/sparc-sunos5.7` | `UNAME` | `SunOS`

Note that hexadecimal shell variables actually miss the leading `0x` to simplify calculations with `bc`. These values are also available to C code through corresponding `#define` statements after `#include <config.h>`. Values are not quoted, but hexadecimal values are correctly prefixed by `0x`.

Table 2. Variables prefixed with `TEVWH_PATH_`

Variable name | Value on this platform | Variable name | Value on this platform
--- | --- | --- | ---
`BC` | `/usr/bin/bc` | `CC` | `/usr/local/bin/gcc`
`CHMOD` | `/usr/bin/chmod` | `COL` | `/usr/bin/col`
`CSH` | `/usr/bin/csh` | `CUT` | `/usr/bin/cut`
`DD` | `/usr/bin/dd` | `DU` | `/usr/xpg4/bin/du`
`DUMP` | `/usr/ccs/bin/dump` | `ECHO` | `/usr/bin/echo`
`ELFDUMP` | `/usr/ccs/bin/elfdump` | `EXPAND` | `/usr/bin/expand`
`FILE` | `/usr/bin/file` | `FIND` | `/usr/bin/find`
`GDB` | `/usr/local/bin/gdb` | `GREP` | `/usr/xpg4/bin/grep`
`HEAD` | `/usr/bin/head` | `KILL` | `/usr/bin/kill`
`LD` | `/usr/local/bin/ld` | `LDD` | `/usr/bin/ldd`
`LS` | `/usr/xpg4/bin/ls` | `MAKE` | `/usr/xpg4/bin/make`
`MAN` | `/usr/bin/man` | `MT` | `/usr/bin/mt`
`NICE` | `/usr/xpg4/bin/nice` | `NM` | `/usr/xpg4/bin/nm`
`OBJDUMP` | `/usr/local/bin/objdump` | `OD` | `/usr/xpg4/bin/od`
`PERL` | `/usr/bin/perl` | `PKGCHK` | `/usr/sbin/pkgchk`
`PKGINFO` | `/usr/bin/pkginfo` | `READELF` | `/usr/local/bin/readelf`
`SED` | `/usr/xpg4/bin/sed` | `SH` | `/usr/xpg4/bin/sh`
`SORT` | `/usr/xpg4/bin/sort` | `STRACE` | `/usr/bin/strace`
`STRINGS` | `/usr/bin/strings` | `STRIP` | `/usr/local/bin/strip`
`TAIL` | `/usr/xpg4/bin/tail` | `TEE` | `/usr/bin/tee`
`TR` | `/usr/xpg4/bin/tr` | `TRUSS` | `/usr/bin/truss`
`UNIQ` | `/usr/bin/uniq` | `WHICH` | `/usr/bin/which`
`XARGS` | `/usr/bin/xargs` |  |

## 1.1. The owner of files

One of the lesser known features of package management is self-reflection. How do we determine the package owning a file if we have the canonical path name?

The package format used by SunOS 5.7 is called "pkg Datastream (SVR4)" by a recent file(1). Relevant information is stored as a set of text files in directory `/var/sadm`. For each installed package there is a sub directory in `/var/sadm/pkg` that includes a description.

Source: pre/sparc-sunos5.7/packages/SunOS/du.sh

    #!/usr/xpg4/bin/sh
    /usr/bin/file /var/sadm/* | /usr/bin/expand -t 32
    /usr/xpg4/bin/ls -l /var/sadm/install/contents
    /usr/xpg4/bin/du -s /var/sadm/pkg /var/sadm/install

Output: out/sparc-sunos5.7/packages/du

    /var/sadm/install:              directory
    /var/sadm/install_data:         directory
    /var/sadm/pkg:                  directory
    /var/sadm/README:               English text
    /var/sadm/softinfo:             directory
    /var/sadm/system:               directory
    -rw-r--r--   1 root     other    2841948 Sep  9 02:31 /var/sadm/install/contents
    3348 /var/sadm/pkg
    5578 /var/sadm/install

The first half of a query does a linear search trough text file `/var/sadm/install/contents`. The tricky part is to find the canonical name of a file. A lot of tools are provided in two different variations. The POSIX confirming ones are located in directory `/usr/xpg4/bin/`, as described by xpg4(5). The classic tools are installed in `/usr/bin`. But since `/bin` is a symbolic link to `/usr/bin`, a naive which(1) can give unexpected results.

Source: pre/sparc-sunos5.7/packages/SunOS/simple.sh

    #!/usr/xpg4/bin/sh
    query='/bin/sed /usr/bin/sed /usr/xpg4/bin/sed'
    /usr/xpg4/bin/ls -li ${query}
    /usr/sbin/pkgchk -l -p "${query}"

Output: out/sparc-sunos5.7/packages/simple

        279597 -r-xr-xr-x   1 bin      bin        27368 Oct  6  1998 /bin/sed
        279597 -r-xr-xr-x   1 bin      bin        27368 Oct  6  1998 /usr/bin/sed
        317464 -r-xr-xr-x   1 bin      bin        28068 Sep  1  1998 /usr/xpg4/bin/sed
    Pathname: /usr/bin/sed
    Type: regular file
    Expected mode: 0555
    Expected owner: bin
    Expected group: bin
    Expected file size (bytes): 27368
    Expected sum(1) of contents: 18227
    Expected last modification: Oct 06 09:45:42 AM 1998
    Referenced by the following packages:
    	SUNWcsu
    Current status: installed

    Pathname: /usr/xpg4/bin/sed
    Type: regular file
    Expected mode: 0555
    Expected owner: bin
    Expected group: bin
    Expected file size (bytes): 28068
    Expected sum(1) of contents: 40692
    Expected last modification: Sep 01 01:04:13 PM 1998
    Referenced by the following packages:
    	SUNWxcu4
    Current status: installed

The second part of the query works on a single file, `/var/sadm/pkg/*/pkginfo`:

Source: pre/sparc-sunos5.7/packages/SunOS/version.sh

    #!/usr/xpg4/bin/sh
    pkg=$( /usr/sbin/pkgchk -l -p /usr/xpg4/bin/sed \
    | /usr/xpg4/bin/grep -v '^[A-Z]' )
    /usr/bin/pkginfo -x ${pkg}

Output: out/sparc-sunos5.7/packages/SunOS/version

    SUNWxcu4        XCU4 Utilities
                    (sparc) 11.7.0,REV=1998.09.01.04.16

## 1.2. The source of man-pages

Option `-a` of `man` returns all matching entries, not just the lowest section. This behavior is identical between platforms.

Command: pre/sparc-sunos5.7/packages/man-all/SunOS.sh

    #!/usr/xpg4/bin/sh
    /usr/bin/man -a -d kill \
    | /usr/xpg4/bin/sed -ne 's/.*\<formatted = //p'

Output: out/sparc-sunos5.7/packages/man-all

    /usr/share/man/cat1/kill.1
    /usr/share/man/cat2/kill.2

Requesting a specific section requires option `-s `section`` on SunOS, while Linux prefers a plain ``section``.

Command: pre/sparc-sunos5.7/packages/man-section/SunOS.sh

    #!/usr/xpg4/bin/sh
    /usr/bin/man -d -s 2 kill \
    | /usr/xpg4/bin/sed -ne 's/.*\<formatted = //p'

Output: out/sparc-sunos5.7/packages/man-section

    /usr/share/man/cat2/kill.2

## 1.3. Verifying installed packages

This chapter is not about checking the integrity of package files. See Intrusion detection systems for a general introduction.

SunOS uses checksums based on sum(1). pkgchk(1) lets you verify everything, complete packages or a list of files specified with option `-i `listfile``. Diagnostics are written to stderr and no news is good news.

Command: pre/sparc-sunos5.7/packages/SunOS/verify.sh

    #!/usr/xpg4/bin/sh
    pkg=$( /usr/sbin/pkgchk -l -p /etc/profile \
    | /usr/xpg4/bin/grep -v '^[A-Z]' )
    /usr/bin/echo pkg=[${pkg}]
    /usr/sbin/pkgchk ${pkg} 2>&1 | /usr/bin/head
    /usr/bin/echo status=$?

Output: out/sparc-sunos5.7/packages/verify

    pkg=[ SUNWcsr ]
    ERROR: /etc/default/init
        file size <219> expected <605> actual
        file cksum <18231> expected <48341> actual
    ERROR: /etc/device.tab
        file size <1207> expected <1998> actual
        file cksum <37074> expected <37523> actual
    ERROR: /etc/devlink.tab
        group name <sys> expected <other> actual
        file size <4043> expected <4117> actual
        file cksum <28952> expected <35993> actual
    status=0

Option `-n` is advertised as "Do not check volatile or editable files". With option `-d `package_file`` you can verify against the checksums included in a package file, e.g. on the installation CD.

Prev | Home | Next
The ELF Virus Writing HOWTO |  | The magic of the Elf