tech stuff

Main - Archive - About - Feed

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/