Modifying a Linksys EFG120 firmware
The EFG120 is a so called Network Area Storage (short NAS). It is very
similiar to the famous NSLU2 but has (an) internal harddisk(s).
Like the NSLU2 the EFG120 runs an embedded Linux and thus could easily be used
for additional purposes.
The problem is the folowing: The system saves only those configuration files onto the harddisk which can be altered by the intened configuration interface (e.g. the Webinterface). If another file is altered by using a telnet session or tweaking the shares to access the config files, the altered file won't be written to the disk, causing the device to revert to old state.
The goal of this page is to describe the process we have developed to overcome this problem.
Keep in mind that this is no beginner's guide. To do this modifications
yourself, you are required to know how to use a Unix/Linux system, compile
programs from source and you need to be familiar with the basic system tools (dd, mount, cp, gcc, ...). Note that if something goes wrong, you
will be responsible for your mistakes and even ours, if we got something
By the way, we suggest to use a real Unix/Linux system to do the modifications of the firmware itself (which are done on a PC and not on the EFG120 itself) or at least a Cygwin environment, to keep all newlines in the config files Unix compliant.
THERE IS NO WARRANTY FOR ALL CONTENTS ON THIS WEBSITE INCLUDING ALL FILES AND LINKS, DOWNLOADABLE OR NOT. IT'S CONTENTS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE CONTENT OF THE WEBSITE IS WITH YOU. SHOULD THE WEBSITE OR ANY CONTENTS OR FILES PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
You have been warned.
#!/bin/sh echo "telnet stream tcp nowait root /usr/sbin/telnetd" >> /etc/inetd.conf killall inetd /usr/sbin/inetd &
The EFG120 runs entirely from RAM including the filesystem. On bootup it loads the filesystem contents from the flash memory. The are two different approaches:
# dd if=/dev/mtdblock3 of=/harddisk/somepath/somedir/somefile.img bs=1The dd command aborted with an I/O Error but a ls -l told us that the filesize was 14155776 bytes (= 0xD80000 in hex) so we had good chances that the I/O error was only due to reaching the end of the device.
As mentioned above, the splitnslu utility is only good for splitting the whole firmware image. We had to make our own utilities to accomplish the task of extracting only the data of the ramdisk block. We wrote ripdata.c which can split the ramdisk image and assembledata.c for combining the parts to a new image. By using some parts of the splitnslu it didn't take long to write the new tools. Our tools don't have any parameters and work on fixed file names. This could be changed, but I think it's not really necessary. You can compile them by running:
# gcc -o ripdata ripdata.c # gcc -o assembledata assembledata.cripdata requires the mtdblock file which we obtained in "Step 2" to be named input.raw the filenames of the two utilities are hardcoded in source so be sure to get the names right. Rename the output file which was generated by dd to input.raw. Then run:
# ./ripdata(Assuming that the two tools are placed in the current working directory.) After (hopefully successfully) running the utility you have two additional files which are called output.gz and trailer.bin. output.gz is the extracted compressed ramdisk image. That's the file we are going to work on. trailer.bin is the Sercomm flash trailer which the utility saved into that file, because the trailer is needed by assembledata later to build a new valid flash image. You should not change anything in this file.
Well. This is a step we did, because we didn't know whether we could write the
image back and whether it would be successful and if the EFG120 would still
boot. At first we checked if our two tools worked correctly. We splitted the
flash image with ripdata as described above and used
assembledata to combine the unchanged ramdisk image and the trailer
into a new flash image. Afterwards we ran cmp to verify that the
newly created flash image and the original one were the same. They were,
so our tools seemed to work.
The next step was trying to write the image into the EFG120 flash. We decided to try it first with the original, unchanged flash image. Thus in a telnet session to the EFG120 we did.
# dd if=original_flash_img of=/dev/mtdblock3 bs=1024We chose a blocksize of 1k, because at this point we knew that the size of the flashblock image was divideable by 1024. After pressing enter it took about 3 nerve straining minutes until the process had competed. A reboot showed that the device was still fully functional.
We used gunzip to decompress the file output.gz and creates
the file output. gunzip completed without errors, and that's
how it should be. If you get errors from gunzip, something went wrong in the
preceding steps and you have a corrupted output.gz.
The ramdisk filesystem of the EFG120 is an ext2 filesystem and we could loopback mount it. (You could even do a bare losetup before and fsck the ramdisk image to make double-sure everything is right and the image is not corrupted. We did that.) We mounted it:
# mount -t ext2 output any_mount_point -o loopAnd Tadaa! We could cd into any_mount_point and see the root filesystem of the EFG120.
if [ -f /harddisk/hd~2/scripts/custominit.sh ]; then /bin/sh /harddisk/hd~2/scripts/custominit.sh > /harddisk/hd~2/scripts/logfile.txt fi(The scripts subdirectoy was created by us.) which caused the EFG120 to have a look at the harddisk and if a script file was present, it executed it. The output is redirected into a file which might be useful for debugging purposes.
Having modified the firmware, we unmounted the EFG120 filesystem:
# umount any_mount_pointassembledata requires as input files newdisk.gz and trailer.bin.
# mv output newdisk # gzip -9 newdiskThe first command renamed the changed ramdisk image and the second compressed the image and gave us the desired newdisk.gz. The next substep is to run assembledata
# ./assembledataThe newly created flash image is called newimg.raw which is the file we have written back into the EFG120's flashblock. The newimg.raw should be exactly as big as the original flash image. If not, something went wrong.
We copied the newimg.raw file onto the EFG120's harddisk and telneted into the device. The last thing to do was to write the modified flashblock image back into mtdblock3:
# dd if=newimg.raw of=/dev/mtdblock3 bs=1024This took about three to five minutes or so, I don't remember exactly. Anyways, it feels like an eternity. After the command had completed, we rebooted the device and -- TADA!! -- the EFG120 executed our custom script from the harddisk. Now we could make all custom changes permanent.
This activity is left over to the motivated reader. We put the same lines into it as we added to the /etc/rc.d/rc.reboot file mentioned in "Step 1", to make the telnet access permanent:
#!/bin/sh echo "telnet stream tcp nowait root /usr/sbin/telnetd" >> /etc/inetd.conf killall inetd /usr/sbin/inetd &Of course, you can add whatever you want.