FreeWRT Configuration Filesystem
Goal
Minor security or bugfix updates should be possible without any kind of interaction and without any configuration lost. We will provide a separate flash partition for /etc called "fwcf".
Below follows a detailed specification, designed and written by Thorsten Glaser. Comments are welcome.
The latest version can be found here: http://cvs.mirbsd.de/contrib/hosted/fwcf/fwcf.txt
FreeWRT Configuration Filesystem
================================
Specification Document
Version 0.91 - 16 September 2006
Copyright (c) 2006
Thorsten Glaser <tg@mirbsd.de>
This specification is subject to change. Users are advised to wait for the release of the specification version 1.0 released together with the first version of the configfs tool.
Licensee is hereby permitted to deal in this work without restriction, including unlimited rights to use, publicly perform, modify, merge, distribute, sell, give away or sublicence, provided all copyright notices above, these terms and the disclaimer are retained in all redistributions or reproduced in accompanying documentation or other materials provided with binary redistributions.
Advertising materials mentioning features or use of this work must display the following acknowledgement:
This product includes material provided by Thorsten Glaser for the FreeWRT Project.
Licensor offers the work "AS IS" and WITHOUT WARRANTY of any kind, express, or implied, to the maximum extent permitted by applicable law, without malicious intent or gross negligence; in no event may licensor, an author or contributor be held liable for any indirect or other damage, or direct damage except proven a consequence of a direct error of said person and intended use of this work, loss or other issues arising in any way out of its use, even if advised of the possibility of such damage or existence of a defect.
Abstract
FreeWRT is an operating system for embedded devices. At the moment, it provides a uClibc/GNU/Linux-based operating environment for mips- based hardware routers, e.g. from Linksys or Asus.
FreeWRT operates on flash memory and as such is under constraints to reduce the amount of write operations to the root filesystem, because flash memory has limited lifetime. Changing the file-based configuration in /etc, however, often requires a fair amount of write operations; furthermore, usual reconfiguration operations change more than only one file, possibly erasing and re-writing the same flash memory block several times. In addition, in between these changes, the system is in an inconsistent state. A reboot before the changes get saved can render the system unusable. A simple reboot could break it. A full reflash and reconfiguration can be required to get the system back to work again.
My proposed implementation will present /etc as a memory filesystem, loaded at boot with the content of the underlying /etc from the default root filesystem (usually on squashfs or jffs2). Then it gets populated with additional files read from a custom flash partition in the below documented format. Changes to /etc will never be reflected in the underlying root filesystem, and the fwcf partition is only updated by a userland programme to be run manually.
Implementation details
The size of the flash partition has been set by the FreeWRT project to 128 KiB (usually two flash blocks). A custom flash map driver is going to be added to the FreeWRT kernel before the import of fwcf.
The command-line utility will support three operations:
* fwcf setup to be run by the rc bootup script early * fwcf commit similar to Cisco 'write' * fwcf erase similar to Cisco 'erase startup-config'
Operation of 'fwcf setup'
This command first remaps the existing /etc (via mount --bind) to /var/fwcf/root. Then, it creates a memory filesystem (tmpfs) at /var/fwcf/tmp and populates it with all files from /var/fwcf/root. Now, the fwcf flash partition gets read, the format and checksum verified and the data extracted to /var/fwcf/tmp, possibly overwriting pre-existing files. The /var/fwcf/tmp filesystem will be re- bound to /etc and the mountpoint at /var/fwcf/tmp unloaded if possible
The data from the end of the fwcf data in the flash partition to the end of the 64 KiB block of data gets written to /dev/urandom.
Operation of 'fwcf commit'
A new memory filesystem (tmpfs) gets created at /var/fwcf/tmp and filled with the data currently in /etc. Then, all files with exactly the same content in /var/fwcf/root get removed from /var/fwcf/tmp. Any remaining files get packed into the fwcf format documented below and written to the flash partition, which is padded into a multiple of 64 KiB with data read from /dev/urandom.
Operation of 'fwcf erase'
In theory, just writing a NULL byte to the beginning of the flash partition would suffice. However, this requires an mtd erase and flash operation of one entire flash block (usually 64 KiB), so an empty fwcf filesystem padded with random data to the next 64 KiB get written instead, for the added benefit of improving the quality of the kernel PRNG even over total reconfigurations.
Structure of the fwcf data
All data is written in little-endian format.
The fwcf data begins at offset 0 in the flash partition, with the magic bytes "FWCF" (0x46435746).
The next doubleword (four bytes) is the "outer length" of the fwcf data, including the header (containing the magic bytes and the length information itself) and the trailer (checksum), but not the padding; the length takes up the lower 24 bits of this doubleword. The upper 8 bits are the (major) version of the specification adhered to, i.e. 0x00 for this document. This information shall be true for all versions of this specification in order to enable the fwcf commandline utility to perform as follows: it is not required to process any non- native versions of fwcf data, but even if reading a different version, the random data used for the padding should be written to /dev/urandom.
The following information is depending on the version of the specification.
The next doubleword (starting at offset 8) is the "inner length" of the compressed fwcf data (lower 24 bit), ordered with the identification number of the compression algorithm used (upper 8 bit). Note this effectively limits the uncompressed and the compressed size of an fwcf filesystem to 224 bytes = 16 MiB. Since the filesystem is designed for /etc, this limitation is not expected to be troublesome. Ending with the zero-padding of the compressed data.
Compression algorithm allocation
An implementation is only required to be able to use exactly one of the compression algorithms defined below, but it is not required to implement a specific algorithm. Conversion might be achieved by un- and repacking the data, or using an fwcf implementation with multiple algorithms. Every implementation, however, is required to offer at least one of the non-private algorithms below.
This draft of the specification offers two compression algorithms:
0x00 = plain uncompressed data 0x01 = zlib deflate compression
Algorithm codes from 0xC0 to 0xFF are available for private use.
Structure of the fwcf filesystem
The compressed/inner data consists of a byte stream without padding. After this, at offset 12, the compressed data starts. It is padded to the next 4-byte boundary with zeroes.
The next doubleword is the ADLER-32 checksum (as defined by libz) of all previous data, starting from the magic bytes at offset 0, applied in the following format:
entry ::= file-entry | NULL-byte file-entry ::= pathname NULL-byte attributes NULL-byte data attributes ::= attribute ( attribute )*
The pathname is a POSIX pathname, i.e. it can contain any character except NULL. Directories are separated with '/' and automatically created by the extraction tool if required. If the first octet of the pathname is a NULL byte (i.e. it is of zero length), the end of the filesystem has been reached. Any data read afterwards MUST be discarded for security reasons.
Attributes consist of a one-byte identifier, which is usually a letter, and a zero-to-multiple-bytes payload. If the identifier is a letter, its lowercase. Uppercase letters denote the same attribute with a different payload length.
The raw file data is not padded or aligned; its length is an at- tribute. Alternate streams / forks are not supported.
Currently defined attributes
0x01 this file is a block special device (*1)
no payload
0x02 this file is a character special device (*1)
no payload
0x03 this file is a symbolic link (*2)
no payload
0x04 this file is a hard link to another file (*4)
no payload
0x05 this file is a directory (*4)
no payload
0x10 modification time of the entry
optional
payload length: 32 bit
g/G group of the file (numeric GID)
optional
payload length: lowercase = 8 bit, uppercase = 32 bit
i/I "inode" of the file (*4)
required if this file is a hard link source or target
optional (ignored) otherwise
payload length: lowercase = 8 bit, uppercase = 16 bit
m/M mode_t / permissions of the file (*3)
optional
payload length: lowercase = 16 bit, uppercase = 32 bit
o/O owner of the file (numeric UID)
optional
payload length: lowercase = 8 bit, uppercase = 32 bit
s/S size of the file
for files and symbolic links: mandatory
for directories, device nodes and hard links: forbidden
payload length: lowercase = 8 bit, uppercase = 24 bit
*1) These identifiers are reserved in this specification; however,
implementations are not required to support them at this time. Device nodes in /etc do not make sense. (Neither do e.g. FIFOs or sockets.)
*2) The name of the target is the data, thus, size is required. *3) Defaults to 0 if not used (for security reasons), so labelling
it as "optional" is probably a farce ;)
*4) Implementing hard links and directories is, of course, optional
for the writer.
Miscellaneous
The initial idea for a "configuration filesystem" based upon the Linux FUSE kernel module has been communicated to me by Waldemar Brodkorb, FreeWRT Project Founder. After a discussion with him, I decided on the archive/userland tool layout outlined in sections 1 and 2 above.
Development of FWCF is hosted in the CVS repository of the MirOS project. Anonymous read-only CVS access is available at the root ":ext:anoncvs@anoncvs.mirbsd.org:/cvs" using password "anoncvs", SSH on port 22; module "fwcf". CVSweb is also available, e.g. at http://cvs.mirbsd.de/contrib/hosted/fwcf/ or its mirrors.
FWCF will be released under the same licence terms as the specification, but without the advertising clause. The author however would really appreciate users to credit his name and that of the FreeWRT Project in derived works and/or links to the CVS reposi- tory of the original source.


