Securing Your System
|This version of this document is no longer maintained. For the latest documentation, see http://www.qnx.com/developers/docs.|
This chapter includes:
Now that more and more computers and other devices are hooked up to insecure networks, security has become a very important issue. The word security can have many meanings, but in a computer context, it generally means preventing unauthorized people from making your computer do things that you don't want it to do.
There are vast tracts of security information in books and on the Internet. This chapter provides a very brief introduction to the subject of security, points you toward outside information and resources, and discusses security issues that are unique to Neutrino.
It should be fairly obvious that security is important; you don't want someone to take control of a device and disrupt its normal functioning — imagine the havoc if someone could stop air traffic control systems or hospital equipment from functioning properly.
The importance of security to an individual machine depends on the context:
- A machine behind a strong firewall is less vulnerable than one connected to a public network.
- One that doesn't even have a network connection is in even less danger.
Part of securing a machine is identifying the level of risk. By classifying threats into categories, we can break down the issues and see which ones we need to concern ourselves with.
We can break the broad division of security threats, also known as exploits, into categories:
- Remote exploit
- The attacker connects to the machine via the network and takes advantage of bugs or weaknesses in the system.
- Local attack
- The attacker has an account on the system in question and can use that account to attempt unauthorized tasks.
Remote exploits are generally much more serious than local ones, but fortunately, remote exploits are much easier to prevent and are generally less common.
For example, suppose you're running bind (a DNS resolver) on port 53 of a publicly connected computer, and the particular version has a vulnerability whereby an attacker can send a badly formed query that causes bind to open up a shell that runs as root on a different port of the machine. An attacker can use this weakness to connect to and effectively “own” the computer.
This type of exploit is often called a buffer overrun or stack-smashing attack and is described in the article, Smashing the Stack for Fun and Profit by Aleph One (see http://www.insecure.org/stf/smashstack.txt). The simple solution to these problems is to make sure that you know which servers are listening on which ports, and that you're running the latest versions of the software. If a machine is publicly connected, don't run any more services than necessary on it.
Local exploits are much more common and difficult to prevent. Having a local account implies a certain amount of trust and it isn't always easy to imagine just how that trust could be violated. Most local exploits involve some sort of elevation of privilege, such as turning a normal user into the superuser, root.
Many local attacks take advantage of a misconfigured system (e.g. file permissions that are set incorrectly) or a buffer overrun on a binary that's set to run as root (known as a setuid binary). In the embedded world — where Neutrino is typically used — local users aren't as much of an issue and, in fact, many systems don't even have a shell shipped with them.
Another way of classifying exploits is by their effect:
- Takeover attacks
- These let the user take the machine over, or at least cause it to do something unpredictable to the owner but predictable to the attacker.
- Denial Of Service (DOS) attacks
- These are just disruptions. An example of this is flood-pinging a
machine to slow down its networking to the point that it's unusable.
DOS attacks are notoriously difficult to deal with, and often must be
handled in a reactive rather than proactive fashion.
As an example, there are very few systems that can't be brought to their knees by a malicious local user although, with such tools as the ksh's ulimit builtin command, you can often minimize these attacks.
Using these divisions, you can look at a system and see which classes of attacks it could potentially be vulnerable to, and take steps to prevent them.
A virus is generally considered to be an infection that runs code on the host (e.g. a Trojan horse). Viruses need an entry point and a host.
The entry points for a virus include:
- an open interface (e.g. ActiveX) — Neutrino has none
- a security hole (such as buffer overflows) — these are specific to flaws in specific services, based on a common industry-standard code base. These are limited, since we ship only a limited set of standard (BSD) services.
The hosts for a virus are system-call interfaces that are accessible from the point of entry (an infected program), such as sendmail or an HTTP server. The hosts are platform-specific, so a virus for Linux would in all likelihood terminate the host under Neutrino as soon as it tried to do anything damaging.
The viruses that circulate via email are OS-specific, generally targeted at Windows, and can't harm Neutrino systems, since they simply aren't compatible. Most UNIX-style systems aren't susceptible to viruses since the ability to do (much) damage is limited by the host. We have never heard of a true virus that could infect Neutrino.
In addition, since deployed Neutrino systems are highly customized to their designated application, they often don't contain the software that's open to such attacks (e.g. logins, web browsers, email, Telnet and FTP servers).
Neutrino is a UNIX-style operating system, so almost all of the general UNIX security information (whether generic, Linux, BSD, etc.) applies to Neutrino as well. A quick Internet search for UNIX or Linux security will yield plenty of papers. You'll also find many titles at a bookstore or library.
We don't market Neutrino as being either more or less secure than other operating systems in its class. That is, we don't attempt to gain a security certification such as is required for certain specialized applications. However, we do conduct internal security audits of vulnerable programs to correct potential exploits.
For flexibility and familiarity, Neutrino uses the generic UNIX security model of user accounts and file permissions, which is generally sufficient for all our customers. In the embedded space, it's fairly easy to lock down a system to any degree without compromising operation. The ultrasecure systems that need certifications are generally servers, as opposed to embedded devices.
As the above section notes, Neutrino is potentially vulnerable to most of the same threats that other UNIX-style systems face. In addition, there are also some issues that are unique to Neutrino.
This section includes:
Our basic model of operation relies on message passing between the OS kernel, process manager and other services. There are potential local exploits in that area that wouldn't exist in a system where all drivers live in the same address space as the kernel. Of course, the potential weakness is outweighed by the demonstrated strength of this model, since embedded systems generally aren't overly concerned with local attacks.
Our remote debug agent, pdebug, runs on a target system and communicates with the gdb debugger on the host. The pdebug agent can run as a dedicated server on a port, be spawned from inetd with incoming connections, or be spawned by qconn.
The pdebug agent is generally run as root, so anyone can upload, download, or execute any arbitrary code at root's privilege level. This agent was designed to be run on development systems, not production machines. There's no means of authentication or security, and none is planned for the future. See the section on qconn below.
The qconn daemon is a server that runs on a target system and handles all incoming requests from our IDE. The qconn server spawns pdebug for debugging requests, profiles applications, gathers system information, and so on.
Like pdebug, qconn is inherently insecure and is meant for development systems. Unlike for pdebug, we plan to give it a security model with some form of authentication. This will let you leave qconn on production machines in the field to provide services such as remote upgrades and fault correction.
Qnet is Neutrino's transparent networking protocol. It's described in the Using Qnet for Transparent Distributed Processing chapter in this guide, and in Native Networking (Qnet) in the System Architecture guide.
Qnet displays other Neutrino machines on the network in the filesystem and lets you treat remote systems as extensions of the local machine. It does no authentication beyond getting a user ID from the incoming connection, so be careful when running it on a machine that's accessible to public networks.
To make Qnet more secure, you can use the maproot and mapany options, which map incoming connections (root or anyone, respectively) to a specific user ID. For more information, see lsm-qnet.so in the Utilities Reference.
IPsec is a security protocol for the Internet Protocol layer that you can use, for example, to set up a secure tunnel between machines or networks. It consists of these subprotocols:
- AH (Authentication Header)
- Guarantees the integrity of the IP packet and protects it from intermediate alteration or impersonation, by attaching a cryptographic checksum computed by one-way hash functions.
- ESP (Encapsulated Security Payload)
- Protects the IP payload from wire-tapping, by encrypting it using secret-key cryptography algorithms.
IPsec has these modes of operation:
- Protects peer-to-peer communication between end nodes.
- Supports IP-in-IP encapsulation operation and is designed for security gateways, such as VPN configurations.
|The IPsec support is subject to change as the IPsec protocols develop.|
Just as a building or vehicle uses specially constructed walls to prevent the spread of fire, so computer systems use firewalls to prevent or limit access to certain applications or systems and to protect systems from malicious attacks.
To create a firewall under Neutrino, you can use a combination of:
- IP Filtering to control access to your machine
- Network Address Translation (NAT) — known to Linux users as IP masquerading — to connect several computers through a common external interface
For more information, see ftp://ftp3.usa.openbsd.org/pub/OpenBSD/doc/pf-faq.pdf in the OpenBSD documentation.