Cisco IOU on n900
Cisco IOU has been floating around for quite some time. Out of the boredom, and for fun having Cisco switching lab in my pocket, I've managed to make it running on my Nokia N900.
Prerequisites: Debian chroot on N900 Maemo - all actions on N900 are assumed within Debian chroot.
Obtain IOU image (insert default joke of you being Cisco employee or having a valid license here) :
N900-deb:~# mkdir -p /data/cisco
N900-deb:~# mv /tmp/a.bin /data/cisco/i86bi-linux-l2-upk9-15.0b.bin
N900-deb:~# file /data/cisco/i86bi-linux-l2-upk9-15.0b.bin
/data/cisco/i86bi-linux-l2-upk9-15.0b.bin: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.2.5, stripped
N900-deb:~# uname -m
armv7l
Install qemu-user:
N900-deb:~# apt-get install qemu-user
N900-deb:~# qemu-i386 -version
qemu-i386 version 2.1.2 (Debian 1:2.1+dfsg-12+deb8u5a~bpo70+1), Copyright (c) 2003-2008 Fabrice Bellard
IOU binaries for linux are dynamically linked ELF 32-bit LSB executables for Intel 80386. If we try to simply execute it via qemu-i386, we'll get an error for missing dynamic linker/loader (see "interpreter" part in 'file' output above):
N900-deb:~# qemu-i386 /data/cisco/i86bi-linux-l2-upk9-15.0b.bin
/lib/ld-linux.so.2: No such file or directory
You can locate the debian package, containing ld-linux.so.2 by searching on packages.debian.org,
for a i386 architecture, (i'm going to use use wheezy packages, because it's the distro my debian chroot is based on). In this case
it's libc6
- download it, and extract to a local directory, then copy ld-linux.so.2
to /lib
, where IOU image expects it:
N900-deb:~# wget http://security.debian.org/debian-security/pool/updates/main/e/eglibc/libc6_2.13-38+deb7u10_i386.deb
N900-deb:~# dpkg -x libc6_2.13-38+deb7u10_i386.deb /data/cisco/extract
N900-deb:~# find /data/cisco/extract/ -name ld-linux.so.2
/data/cisco/extract/lib/ld-linux.so.2
/data/cisco/extract/lib/i386-linux-gnu/ld-linux.so.2
N900-deb:~# file /data/cisco/extract/lib/ld-linux.so.2
/data/cisco/extract/lib/ld-linux.so.2: symbolic link to i386-linux-gnu/ld-2.13.so
N900-deb:~# cp /data/cisco/extract/lib/ld-linux.so.2 /lib/
N900-deb:~# file /lib/ld-linux.so.2
/lib/ld-linux.so.2: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=50ea7a832566b8e48b2824267f8f92decdf1c2db, stripped
If you try running IOU image via qemu now, you'll get an error for missing shared library file :
N900-deb:~# qemu-i386 /data/cisco/i86bi-linux-l2-upk9-15.0b.bin
/data/cisco/i86bi-linux-l2-upk9-15.0b.bin: error while loading shared libraries: libcrypto.so.4: cannot open shared object file: No such file or directory
We can use objdump
or readelf
to find out the needed shared libraries from the foreign architecture binary (ldd
won't work here):
N900-deb:~# objdump -x /data/cisco/i86bi-linux-l2-upk9-15.0b.bin | grep NEEDED
NEEDED libcrypto.so.4
NEEDED libm.so.6
NEEDED libgcc_s.so.1
NEEDED libc.so.6
NEEDED libdl.so.2
N900-deb:~# readelf -d /data/cisco/i86bi-linux-l2-upk9-15.0b.bin | grep NEEDED
0x00000001 (NEEDED) Shared library: [libcrypto.so.4]
0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x00000001 (NEEDED) Shared library: [libdl.so.2]
We can even use readelf
to generate full dependence list, containing all needed files, to automate
package search later:
N900-deb:~# readelf -a /data/cisco/i86bi-linux-l2-upk9-15.0b.bin | egrep "interpreter|NEEDED" | awk '{print $3,$4,$5}' | sed -e 's/\[//' -e 's/\]//'
interpreter: /lib/ld-linux.so.2
Shared library: libcrypto.so.4
Shared library: libm.so.6
Shared library: libgcc_s.so.1
Shared library: libc.so.6
Shared library: libdl.so.2
Use debian package search as per above, to find out and download packages containing needed files, extract packages locally, find, and
copy needed files to some location. Please note that libcrypto.so.4
in a list is going to be copied from libcrypto.so.1.0.0
from libssl
,
and it itself contains additional libz
dependency. Final needed package list:
And files within:
Missing | Package | File in a package |
---|---|---|
interpreter: /lib/ld-linux.so.2 | libc6 | /lib/ld-linux.so.2 |
Shared library: libcrypto.so.4 | libssl1.0.0 | /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0 |
Shared library: libz.so.1 | zlib1g | /lib/i386-linux-gnu/libz.so.1 |
Shared library: libm.so.6 | libc6 | /lib/i386-linux-gnu/libm.so.6 |
Shared library: libgcc_s.so.1 | libgcc1 | /lib/i386-linux-gnu/libgcc_s.so.1 |
Shared library: libc.so.6 | libc6 | /lib/i386-linux-gnu/libc.so.6 |
Shared library: libdl.so.2 | libc6 | /lib/i386-linux-gnu/libdl.so.2 |
Log:
N900-deb:~# ls -1 /data/cisco/pkg/
libc6_2.13-38+deb7u10_i386.deb
libgcc1_4.7.2-5_i386.deb
libssl1.0.0_1.0.1e-2+deb7u20_i386.deb
zlib1g_1.2.7.dfsg-13_i386.deb
N900-deb:~# find /data/cisco/pkg/ -name '*.deb' | while read line; do dpkg -x $line /data/cisco/extract/; done
N900-deb:~# mkdir -p /data/cisco/lib
N900-deb:~# cp /data/cisco/extract/usr/lib/i386-linux-gnu/libcrypto.so.1.0.0 /data/cisco/lib/libcrypto.so.4
N900-deb:~# for i in /data/cisco/extract/lib/i386-linux-gnu/{libz.so.1,libm.so.6,libgcc_s.so.1,libc.so.6,libdl.so.2}; do cp $i /data/cisco/lib/; done
N900-deb:~# ls -1 /data/cisco/lib/
libcrypto.so.4
libc.so.6
libdl.so.2
libgcc_s.so.1
libm.so.6
libz.so.1
Now we can try pointing LD_LIBRARY_PATH environment variable to our library directory, and run IOU image via qemu again:
N900-deb:~# cd /data/cisco
N900-deb:/data/cisco# LD_LIBRARY_PATH=/data/cisco/lib qemu-i386 ./i86bi-linux-l2-upk9-15.0b.bin
IOS On Unix - Cisco Systems confidential, internal use only
<...>
It works:
Last touch: we have all foreign architecture shared library files isolated in a separate directory, but full path to the "ld-linux.so.2" is hardcoded into the IOU binary, and this file polutes our chroot distro. The solution could be modifying IOU binary and changing path to the "interpreter" to someting else, or shrinking it so, it is relative, and then placing dynamic linker/loader to the directory we are running IOU binary from:
There are several standard tools for manipulating ELF headers, like elfedit
or objcopy
from binutils
, or we can simpy
use any HEX editor for that, but for a job,
the most convenient tool I found was patchelf:
N900-deb:~# readelf -a /data/cisco/i86bi-linux-l2-upk9-15.0b.bin | grep interpreter
[Requesting program interpreter: /lib/ld-linux.so.2]
N900-deb:~# patchelf --set-interpreter 'ld-linux.so.2' /data/cisco/i86bi-linux-l2-upk9-15.0b.bin
N900-deb:~# readelf -a /data/cisco/i86bi-linux-l2-upk9-15.0b.bin | grep interpreter
[Requesting program interpreter: ld-linux.so.2]
N900-deb:~# mv /lib/ld-linux.so.2 /data/cisco/