diff options
Diffstat (limited to 'docs/adding.tex')
-rw-r--r-- | docs/adding.tex | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/docs/adding.tex b/docs/adding.tex new file mode 100644 index 0000000..7b80c0d --- /dev/null +++ b/docs/adding.tex @@ -0,0 +1,590 @@ +Linux is now one of the most widespread operating system for embedded devices due +to its openess as well as the wide variety of platforms it can run on. Many +manufacturer actually use it in firmware you can find on many devices: DVB-T +decoders, routers, print servers, DVD players ... Most of the time the stock +firmware is not really open to the consumer, even if it uses open source software. + +You might be interested in running a Linux based firmware for your router for +various reasons: extending the use of a network protocol (such as IPv6), having +new features, new piece of software inside, or for security reasons. A fully +open-source firmware is de-facto needed for such applications, since you want to +be free to use this or that version of a particular reason, be able to correct a +particular bug. Few manufacturers do ship their routers with a Sample Development Kit, +that would allow you to create your own and custom firmware and most of the time, +when they do, you will most likely not be able to complete the firmware creation process. + +This is one of the reasons why OpenWrt and other firmware exists: providing a +version independent, and tools independent firmware, that can be run on various +platforms, known to be running Linux originally. + +\subsection{Which Operating System does this device run?} + +There is a lot of methods to ensure your device is running Linux. Some of them do +need your router to be unscrewed and open, some can be done by probing the device +using its external network interfaces. + +\subsubsection{Operating System fingerprinting and port scanning} + +A large bunch of tools over the Internet exists in order to let you do OS +fingerprinting, we will show here an example using \textbf{nmap}: + +\begin{Verbatim} +nmap -P0 -O <IP address> +Starting Nmap 4.20 ( http://insecure.org ) at 2007-01-08 11:05 CET +Interesting ports on 192.168.2.1: +Not shown: 1693 closed ports +PORT STATE SERVICE +22/tcp open ssh +23/tcp open telnet +53/tcp open domain +80/tcp open http +MAC Address: 00:13:xx:xx:xx:xx (Cisco-Linksys) +Device type: broadband router +Running: Linksys embedded +OS details: Linksys WRT54GS v4 running OpenWrt w/Linux kernel 2.4.30 +Network Distance: 1 hop +\end{Verbatim} + +nmap is able to report whether your device uses a Linux TCP/IP stack, and if so, +will show you which Linux kernel version is probably runs. This report is quite +reliable and it can make the distinction between BSD and Linux TCP/IP stacks and others. + +Using the same tool, you can also do port scanning and service version discovery. +For instance, the following command will report which IP-based services are running +on the device, and which version of the service is being used: + +\begin{verbatim} +nmap -P0 -sV <IP address> +Starting Nmap 4.20 ( http://insecure.org ) at 2007-01-08 11:06 CET +Interesting ports on 192.168.2.1: +Not shown: 1693 closed ports +PORT STATE SERVICE VERSION +22/tcp open ssh Dropbear sshd 0.48 (protocol 2.0) +23/tcp open telnet Busybox telnetd +53/tcp open domain ISC Bind dnsmasq-2.35 +80/tcp open http OpenWrt BusyBox httpd +MAC Address: 00:13:xx:xx:xx:xx (Cisco-Linksys) +Service Info: Device: WAP +\end{verbatim} + +The web server version, if identified, can be determining in knowing the Operating +System. For instance, the \textbf{BOA} web server is typical from devices running +an open-source Unix or Unix-like. + +\subsubsection{Wireless Communications Fingerprinting} + +Although this method is not really known and widespread, using a wireless scanner +to discover which OS your router or Access Point run can be used. We do not have +a clear example of how this could be achieved, but you will have to monitor raw +802.11 frames and compare them to a very similar device running a Linux based firmware. + +\subsubsection{Web server security exploits} + +The Linksys WRT54G was originally hacked by using a "ping bug" discovered in the +web interface. This tip has not been fixed for months by Linksys, allowing people +to enable the "boot\_wait" helper process via the web interface. Many web servers +used in firmwares are open source web server, thus allowing the code to be audited +to find an exploit. Once you know the web server version that runs on your device, +by using \textbf{nmap -sV} or so, you might be interested in using exploits to reach +shell access on your device. + +\subsubsection{Native Telnet/SSH access} + +Some firmwares might have restricted or unrestricted Telnet/SSH access, if so, +try to log in with the web interface login/password and see if you can type in +some commands. This is actually the case for some Broadcom BCM963xx based firmwares +such as the one in Neuf/Cegetel ISP routers, Club-Internet ISP CI-Box and many +others. Some commands, like \textbf{cat} might be left here and be used to +determine the Linux kernel version. + +\subsubsection{Analysing a binary firmware image} + +You are very likely to find a firmware binary image on the manufacturer website, +even if your device runs a proprietary operating system. If so, you can download +it and use an hexadecimal editor to find printable words such as \textbf{vmlinux}, +\textbf{linux}, \textbf{ramdisk}, \textbf{mtd} and others. + +Some Unix tools like \textbf{hexdump} or \textbf{strings} can be used to analyse +the firmware. Below there is an example with a binary firmware found other the Internet: + +\begin{verbatim} +hexdump -C <binary image.extension> | less (more) +00000000 46 49 52 45 32 2e 35 2e 30 00 00 00 00 00 00 00 |FIRE2.5.0.......| +00000010 00 00 00 00 31 2e 30 2e 30 00 00 00 00 00 00 00 |....1.0.0.......| +00000020 00 00 00 00 00 00 00 38 00 43 36 29 00 0a e6 dc |.......8.C6)..??| +00000030 54 49 44 45 92 89 54 66 1f 8b 08 08 f8 10 68 42 |TIDE..Tf....?.hB| +00000040 02 03 72 61 6d 64 69 73 6b 00 ec 7d 09 bc d5 d3 |..ramdisk.?}.???| +00000050 da ff f3 9b f7 39 7b ef 73 f6 19 3b 53 67 ea 44 |???.?9{?s?.;Sg?D| +\end{verbatim} + +Scroll over the firmware to find printable words that can be significant. + +\subsubsection{Amount of flash memory} + +Linux can hardly fit in a 2MB flash device, once you have opened the device and +located the flash chip, try to find its characteristics on the Internet. If +your flash chip is a 2MB or less device, your device is most likely to run a +proprietary OS such as WindRiver VxWorks, or a custom manufacturer OS like Zyxel ZynOS. + +OpenWrt does not currently run on devices which have 2MB or less of flash memory. +This limitation will probably not be worked around since those devices are most +of the time micro-routers, or Wireless Access Points, which are not the main +OpenWrt target. + +\subsubsection{Pluging a serial port} + +By using a serial port and a level shifter, you may reach the console that is being shown by the device +for debugging or flashing purposes. By analysing the output of this device, you can +easily notice if the device uses a Linux kernel or something different. + +\subsection{Finding and using the manufacturer SDK} + +Once you are sure your device run a Linux based firmware, you will be able to start +hacking on it. If the manufacturer respected the GPL, it will have released a Sample +Development Kit with the device. + +\subsubsection{GPL violations} + +Some manufacturers do release a Linux based binary firmware, with no sources at all. +The first step before doing anything is to read the license coming with your device, +then write them about this lack of Open Source code. If the manufacturer answers +you they do not have to release a SDK containing Open Source software, then we +recommend you get in touch with the gpl-violations.org community. + +You will find below a sample letter that can be sent to the manufacturer: + +\begin{verse} +Miss, Mister, + +I am using a <device name>, and I cannot find neither on your website nor on the +CD-ROM the open source software used to build or modify the firmware. + +In conformance to the GPL license, you have to release the following sources: + +\begin{itemize} +\item complete toolchain that made the kernel and applications be compiled (gcc, binutils, libc) +\item tools to build a custom firmware (mksquashfs, mkcramfs ...) +\item kernel sources with patches to make it run on this specific hardware, this does not include binary drivers +\end{itemize} + +Thank you very much in advance for your answer. + +Best regards, <your name> +\end{verse} + +\subsubsection{Using the SDK} + +Once the SDK is available, you are most likely not to be able to build a complete +or functional firmware using it, but parts of it, like only the kernel, or only +the root filesystem. Most manufacturers do not really care releasing a tool that +do work every time you uncompress and use it. + +You should anyway be able to use the following components: + +\begin{itemize} +\item kernel sources with more or less functional patches for your hardware +\item binary drivers linked or to be linked with the shipped kernel version +\item packages of the toolchain used to compile the whole firmware: gcc, binutils, libc or uClibc +\item binary tools to create a valid firmware image +\end{itemize} + +Your work can be divided into the following tasks: + +\begin{itemize} +\item create a clean patch of the hardware specific part of the linux kernel +\item spot potential kernel GPL violations especially on netfilter and USB stack stuff +\item make the binary drivers work, until there are open source drivers +\item use standard a GNU toolchain to make working executables +\item understand and write open source tools to generate a valid firmware image +\end{itemize} + +\subsubsection{Creating a hardware specific kernel patch} + +Most of the time, the kernel source that comes along with the SDK is not really +clean, and is not a standard Linux version, it also has architecture specific +fixes backported from the \textbf{CVS} or the \textbf{git} repository of the +kernel development trees. Anyway, some parts can be easily isolated and used as +a good start to make a vanilla kernel work your hardware. + +Some directories are very likely to have local modifications needed to make your +hardware be recognized and used under Linux. First of all, you need to find out +the linux kernel version that is used by your hardware, this can be found by +editing the \textbf{linux/Makefile} file. + +\begin{verbatim} +head -5 linux-2.x.x/Makefile +VERSION = 2 +PATCHLEVEL = x +SUBLEVEL = y +EXTRAVERSION = z +NAME=A fancy name +\end{verbatim} + +So now, you know that you have to download a standard kernel tarball at +\textbf{kernel.org} that matches the version being used by your hardware. + +Then you can create a \textbf{diff} file between the two trees, especially for the +following directories: + +\begin{verbatim} +diff -urN linux-2.x.x/arch/<sub architecture> linux-2.x.x-modified/arch/<sub architecture> > 01-architecture.patch +diff -urN linux-2.x.x/include/ linux-2.x.x-modified/include > 02-includes.patch +diff -urN linux-2.x.x/drivers/ linux-2.x.x-modified/drivers > 03-drivers.patch +\end{verbatim} + +This will constitute a basic set of three patches that are very likely to contain +any needed modifications that has been made to the stock Linux kernel to run on +your specific device. Of course, the content produced by the \textbf{diff -urN} +may not always be relevant, so that you have to clean up those patches to only +let the "must have" code into them. + +The first patch will contain all the code that is needed by the board to be +initialized at startup, as well as processor detection and other boot time +specific fixes. + +The second patch will contain all useful definitions for that board: addresses, +kernel granularity, redefinitions, processor family and features ... + +The third patch may contain drivers for: serial console, ethernet NIC, wireless +NIC, USB NIC ... Most of the time this patch contains nothing else than "glue" +code that has been added to make the binary driver work with the Linux kernel. +This code might not be useful if you plan on writing drivers from scratch for +this hardware. + +\subsubsection{Using the device bootloader} + +The bootloader is the first program that is started right after your device has +been powered on. This program, can be more or less sophisticated, some do let you +do network booting, USB mass storage booting ... The bootloader is device and +architecture specific, some bootloaders were designed to be universal such as +RedBoot or U-Boot so that you can meet those loaders on totally different +platforms and expect them to behave the same way. + +If your device runs a proprietary operating system, you are very likely to deal +with a proprietary boot loader as well. This may not always be a limitation, +some proprietary bootloaders can even have source code available (i.e : Broadcom CFE). + +According to the bootloader features, hacking on the device will be more or less +easier. It is very probable that the bootloader, even exotic and rare, has a +documentation somewhere over the Internet. In order to know what will be possible +with your bootloader and the way you are going to hack the device, look over the +following features : + +\begin{itemize} +\item does the bootloader allow net booting via bootp/DHCP/NFS or tftp +\item does the bootloader accept loading ELF binaries ? +\item does the bootloader have a kernel/firmware size limitation ? +\item does the bootloader expect a firmware format to be loaded with ? +\item are the loaded files executed from RAM or flash ? +\end{itemize} + +Net booting is something very convenient, because you will only have to set up network +booting servers on your development station, and keep the original firmware on the device +till you are sure you can replace it. This also prevents your device from being flashed, +and potentially bricked every time you want to test a modification on the kernel/filesystem. + +If your device needs to be flashed every time you load a firmware, the bootlader might +only accept a specific firmware format to be loaded, so that you will have to +understand the firmware format as well. + +\subsubsection{Making binary drivers work} + +As we have explained before, manufacturers do release binary drivers in their GPL +tarball. When those drivers are statically linked into the kernel, they become GPL +as well, fortunately or unfortunately, most of the drivers are not statically linked. +This anyway lets you a chance to dynamically link the driver with the current kernel +version, and try to make them work together. + +This is one of the most tricky and grey part of the fully open source projects. +Some drivers require few modifications to be working with your custom kernel, +because they worked with an earlier kernel, and few modifications have been made +to the kernel in-between those versions. This is for instance the case with the +binary driver of the Broadcom BCM43xx Wireless Chipsets, where only few differences +were made to the network interface structures. + +Some general principles can be applied no matter which kernel version is used in +order to make binary drivers work with your custom kernel: + +\begin{itemize} +\item turn on kernel debugging features such as: +\begin{itemize} +\item CONFIG\_DEBUG\_KERNEL +\item CONFIG\_DETECT\_SOFTLOCKUP +\item CONFIG\_DEBUG\_KOBJECT +\item CONFIG\_KALLSYMS +\item CONFIG\_KALLSYMS\_ALL +\end{itemize} +\item link binary drivers when possible to the current kernel version +\item try to load those binary drivers +\item catch the lockups and understand them +\end{itemize} + +Most of the time, loading binary drivers will fail, and generate a kernel oops. +You can know the last symbol the binary drivers attempted to use, and see in the +kernel headers file, if you do not have to move some structures field before or +after that symbol in order to keep compatibily with both the binary driver and +the stock kernel drivers. + +\subsubsection{Understanding the firmware format} + +You might want to understand the firmware format, even if you are not yet capable +of running a custom firmware on your device, because this is sometimes a blocking +part of the flashing process. + +A firmware format is most of the time composed of the following fields: + +\begin{itemize} +\item header, containing a firmware version and additional fields: Vendor, Hardware version ... +\item CRC32 checksum on either the whole file or just part of it +\item Binary and/or compressed kernel image +\item Binary and/or compressed root filesystem image +\item potential garbage +\end{itemize} + +Once you have figured out how the firmware format is partitioned, you will have +to write your own tool that produces valid firmware binaries. One thing to be very +careful here is the endianness of either the machine that produces the binary +firmware and the device that will be flashed using this binary firmware. + +\subsubsection{Writing a flash map driver} + +The flash map driver has an important role in making your custom firmware work +because it is responsible of mapping the correct flash regions and associated +rights to specific parts of the system such as: bootloader, kernel, user filesystem. + +Writing your own flash map driver is not really a hard task once you know how your +firmware image and flash is structured. You will find below a commented example +that covers the case of the device where the bootloader can pass to the kernel its partition plan. + +First of all, you need to make your flash map driver be visible in the kernel +configuration options, this can be done by editing the file \ +\textbf{linux/drivers/mtd/maps/Kconfig}: + +\begin{verbatim} +config MTD_DEVICE_FLASH + tristate "Device Flash device" + depends on ARCHITECTURE && DEVICE + help + Flash memory access on DEVICE boards. Currently only works with + Bootloader Foo and Bootloader Bar. +\end{verbatim} + +Then add your source file to the \textbf{linux/drivers/mtd/maps/Makefile}, so +that it will be compiled along with the kernel. + +\begin{verbatim} +obj-\$(CONFIG_MTD_DEVICE_FLASH) += device-flash.o +\end{verbatim} + +You can then write the kernel driver itself, by creating a +\textbf{linux/drivers/mtd/maps/device-flash.c} C source file. + +\begin{verbatim} +// Includes that are required for the flash map driver to know of the prototypes: +#include <asm/io.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/vmalloc.h> + +// Put some flash map definitions here: +#define WINDOW_ADDR 0x1FC00000 /* Real address of the flash */ +#define WINDOW_SIZE 0x400000 /* Size of flash */ +#define BUSWIDTH 2 /* Buswidth */ + +static void __exit device_mtd_cleanup(void); + +static struct mtd_info *device_mtd_info; + +static struct map_info devicd_map = { + .name = "device", + .size = WINDOW_SIZE, + .bankwidth = BUSWIDTH, + .phys = WINDOW_ADDR, +}; + +static int __init device_mtd_init(void) +{ + // Display that we found a flash map device + printk("device: 0x\%08x at 0x\%08x\n", WINDOW_SIZE, WINDOW_ADDR); + // Remap the device address to a kernel address + device_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); + + // If impossible to remap, exit with the EIO error + if (!device_map.virt) { + printk("device: Failed to ioremap\n"); + return -EIO; + } + + // Initialize the device map + simple_map_init(&device_map); + + /* MTD informations are closely linked to the flash map device + you might also use "jedec_probe" "amd_probe" or "intel_probe" */ + device_mtd_info = do_map_probe("cfi_probe", &device_map); + + if (device_mtd_info) { + device_mtd_info->owner = THIS_MODULE; + + int parsed_nr_parts = 0; + + // We try here to use the partition schema provided by the bootloader specific code + if (parsed_nr_parts == 0) { + int ret = parse_bootloader_partitions(device_mtd_info, &parsed_parts, 0); + if (ret > 0) { + part_type = "BootLoader"; + parsed_nr_parts = ret; + } + } + + add_mtd_partitions(devicd_mtd_info, parsed_parts, parsed_nr_parts); + + return 0; + } + iounmap(device_map.virt); + + return -ENXIO; +} + +// This function will make the driver clean up the MTD device mapping +static void __exit device_mtd_cleanup(void) +{ + // If we found a MTD device before + if (device_mtd_info) { + // Delete every partitions + del_mtd_partitions(device_mtd_info); + // Delete the associated map + map_destroy(device_mtd_info); + } + + // If the virtual address is already in use + if (device_map.virt) { + // Unmap the physical address to a kernel space address + iounmap(device_map.virt); + // Reset the structure field + device_map.virt = 0; + } +} + + +// Macros that indicate which function is called on loading/unloading the module +module_init(device_mtd_init); +module_exit(device_mtd_cleanup); + + +// Macros defining license and author, parameters can be defined here too. +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Me, myself and I <memyselfandi@domain.tld"); +\end{verbatim} + +\subsection{Adding your target in OpenWrt} + +Once you spotted the key changes that were made to the Linux kernel +to support your target, you will want to create a target in OpenWrt +for your hardware. This can be useful to benefit from the toolchain +that OpenWrt builds as well as the resulting user-space and kernel +configuration options. + +Provided that your target is already known to OpenWrt, it will be +as simple as creating a \texttt{target/linux/board} directory +where you will be creating the following directories and files. + +Here for example, is a \texttt{target/linux/board/Makefile}: + +\begin{Verbatim}[frame=single,numbers=left] +# +# Copyright (C) 2009 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +ARCH:=mips +BOARD:=board +BOARDNAME:=Eval board +FEATURES:=squashfs jffs2 pci usb + +LINUX_VERSION:=2.6.27.10 + +include $(INCLUDE_DIR)/target.mk + +DEFAULT_PACKAGES += hostapd-mini + +define Target/Description + Build firmware images for Evaluation board +endef + +$(eval $(call BuildTarget)) +\end{Verbatim} + +\begin{itemize} + \item \texttt{ARCH} \\ + The name of the architecture known by Linux and uClibc + \item \texttt{BOARD} \\ + The name of your board that will be used as a package and build directory identifier + \item \texttt{BOARDNAME} \\ + Expanded name that will appear in menuconfig + \item \texttt{FEATURES} \\ + Set of features to build filesystem images, USB, PCI, VIDEO kernel support + \item \texttt{LINUX\_VERSION} \\ + Linux kernel version to use for this target + \item \texttt{DEFAULT\_PACKAGES} \\ + Set of packages to be built by default +\end{itemize} + +A partial kernel configuration which is either named \texttt{config-default} or which matches the kernel version \texttt{config-2.6.x} should be present in \texttt{target/linux/board/}. +This kernel configuration will only contain the relevant symbols to support your target and can be changed using \texttt{make kernel\_menuconfig}. + +To patch the kernel sources with the patches required to support your hardware, you will have to drop them in \texttt{patches} or in \texttt{patches-2.6.x} if there are specific +changes between kernel versions. Additionnaly, if you want to avoid creating a patch that will create files, you can put those files into \texttt{files} or \texttt{files-2.6.x} +with the same directory structure that the kernel uses (e.g: drivers/mtd/maps, arch/mips ..). + +The build system will require you to create a \texttt{target/linux/board/image/Makefile}: + +\begin{Verbatim}[frame=single,numbers=left] +# +# Copyright (C) 2009 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +define Image/BuildKernel + cp $(KDIR)/vmlinux.elf $(BIN_DIR)/openwrt-$(BOARD)-vmlinux.elf + gzip -9n -c $(KDIR)/vmlinux > $(KDIR)/vmlinux.bin.gz + $(STAGING_DIR_HOST)/bin/lzma e $(KDIR)/vmlinux $(KDIR)/vmlinux.bin.l7 + dd if=$(KDIR)/vmlinux.bin.l7 of=$(BIN_DIR)/openwrt-$(BOARD)-vmlinux.lzma bs=65536 conv=sync + dd if=$(KDIR)/vmlinux.bin.gz of=$(BIN_DIR)/openwrt-$(BOARD)-vmlinux.gz bs=65536 conv=sync +endef + +define Image/Build/squashfs + $(call prepare_generic_squashfs,$(KDIR)/root.squashfs) +endef + +define Image/Build + $(call Image/Build/$(1)) + dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-root.$(1) bs=128k conv=sync + + -$(STAGING_DIR_HOST)/bin/mkfwimage \ + -B XS2 -v XS2.ar2316.OpenWrt \ + -k $(BIN_DIR)/openwrt-$(BOARD)-vmlinux.lzma \ + -r $(BIN_DIR)/openwrt-$(BOARD)-root.$(1) \ + -o $(BIN_DIR)/openwrt-$(BOARD)-ubnt2-$(1).bin +endef + +$(eval $(call BuildImage)) + +\end{Verbatim} + +\begin{itemize} + \item \texttt{Image/BuildKernel} \\ + This template defines changes to be made to the ELF kernel file + \item \texttt{Image/Build} \\ + This template defines the final changes to apply to the rootfs and kernel, either combined or separated + firmware creation tools can be called here as well. +\end{itemize} |