Nuff Security

Nuff Security

Nuff Security

  1. General nuff security
  2. Safe, verified memory management
  3. Optimise For Security
  4. Cryptographic Random Numbers
  5. Verification of Packets
  6. Determinism

General nuff security

The biggest source of security problems in software comes from misunderstood and/or poorly designed programming abstractions (take strcpy(3)). The better our abstractions can be - the more tailored to our exact needs they are - the more secure our software gets. Lisp is the right technology for making those abstractions.

To get the best possible use out of nuff it is necessary to run it with root privileges. As with any piece of software - especially when attached to a potentially malicious internet - you should be concerned about this.

Many pieces of security software perform complex sequences of tasks requiring root privileges. In particular, a lot can be gained by using so called "raw sockets" which allow a program to parse and craft network packets in ways the operating system didn't intend. While this is very powerful and is used to great effect in tools like nmap and hping, the root privileges that raw sockets require can turn any small programming flaw into a serious system-wide security problem. Consider the recent traceroute remote vulnerability or the myriad of remotley exploitable flaws in ethereal.

Even programs that run without root privileges can be exploited in dangerous ways if the program wasn't designed with security in mind. Since one of nuff's goals is to provide a safe, reliable interface for experimenting with network protocols, nuff takes a pro-active approach to security. This document describes some of nuff's security features and the considerations we've given security.

Safe, verified memory management

Since nuff is a scheme system, we have a solid, well designed run-time type checking system. Barring any bugs in our scheme system, this provides a large amount of protection for a nuff script writer. Some of the safety checks that scheme employs are:

Optimise For Security

Nuff tries to adhere to the principle of least privilege in all its scripts. Since all nuff scripts are lists of scheme s-expressions, it is easy to write code to parse and process them. When the nuff compiler does this it takes a very strict approach to privileges. In general, unless the compiler detects an obvious need for some capability it doesn't grant the program permission to use that capability.

Some examples are:

Cryptographic Random Numbers

In network protocols there is a frequent need for random numbers. Generating session IDs, sequence numbers, and source ports are some typical examples.

The importance and ubiquity of random numbers in network protocols makes them attractive targets for attacks. If an attacker is able to predict the "random numbers" used by an application he or she can often perform all sorts of mischief.

Nuff tries to prevent this by using strong cryptography. Instead of implementing this ourselves, we decided to use libdnet's random number interface. libdnet provides a reliable, well tested interface to the operating system's cryptographic randomness pool and strong PRNG which nuff uses for all random values.

Verification of Packets

Nuff makes it easy to perform rudimentary verification on packets at all stages. In fact, when you use the parsepaq macro this is the default behaviour. The code that parsepaq generates will unravel the packet layer by layer running it through our verification closures. The verification closures are just closures around the expressions provided in the layer-specs and generally verify a minimum length of a packet and/or a protocol number in the parent layer.

Although parsepaq usually doesn't guarantee that a field in a packet will have a sensical value, it will always guarantee there is a value and the packet is properly structured.

Furthermore, due to the nature of shared strings, even parts of the packet being parsed will be inaccessible to different parts of the macro expansion. In other words, if you use parsepaq to extract a layer out a packet and pass that layer to a function outside your lexical scope, even though that layer shares memory with the original packet, the function will not be able to access the parent layers. See the note on shared strings in "nuff doc language" for more details.


Since nuff implements a co-operative multi-tasking environment, it is able to make more guarantees about run-time behaviour when it comes to multiple tasks accessing the same data structures concurrently.

The first thing of note is that there is little need for "locks" or other synchronisation primitives in nuff. Any operation that doesn't require I/O will never be pre-empted so there is no need for any sort of locking mechanism. As a running continuation, we can always be sure that all other continuations are blocked awaiting I/O. Even if data arrives for them, or their send operation completes while we are running, nuff will not schedule them to run until we block on I/O ourselves. Operations that do require I/O should generally be done concurrently.

Correct concurrent programming is difficult in all languages.

Whether it is simply the nature of the problem or if we just haven't yet invented decent enough abstractions remains to be seen. Correct concurrent nuff programming is also difficult, but we offer a rich set of flexible primitives that, in our opinion, make concurrent I/O based programming more tolerable. We are still experimenting with the programming interfaces used for concurrency and we have high hopes that, thanks to the beautiful and extensible nature of lisp, we will eventually reach a stable API optimised for both power and safety.

On a semi-related topic, a future nuff research project will involve continuation-based non-determinism as a convenient Domain Specific Language for creating so-called "protocol fuzzers". These are programs that try brute force attempts of a protocol against a daemon or network stack in order to discover odd behaviours and security weaknesses. See Graham's "On Lisp" for information on non-determinism and the back-tracking search it uses.

All material is © Doug Hoyte and/or HCSW Labs unless otherwise noted or implied.