Site Home Page
The UML Wiki
UML Community Site
The UML roadmap
What it's good for
Case Studies
Kernel Capabilities
Downloading it
Running it
Compiling
Installation
Skas Mode
Incremental Patches
Test Suite
Host memory use
Building filesystems
Troubles
User Contributions
Related Links
The ToDo list
Projects
Diary
Thanks
Contacts
Tutorials
The HOWTO (html)
The HOWTO (text)
Host file access
Device inputs
Sharing filesystems
Creating filesystems
Resizing filesystems
Virtual Networking
Management Console
Kernel Debugging
UML Honeypots
gprof and gcov
Running X
Diagnosing problems
Configuration
Installing Slackware
Porting UML
IO memory emulation
UML on 2G/2G hosts
Adding a UML system call
Running nested UMLs
How you can help
Overview
Documentation
Utilities
Kernel bugs
Kernel projects
Screenshots
A virtual network
An X session
Transcripts
A login session
A debugging session
Slackware installation
Reference
Kernel switches
Slackware README
Papers
ALS 2000 paper (html)
ALS 2000 paper (TeX)
ALS 2000 slides
LCA 2001 slides
OLS 2001 paper (html)
OLS 2001 paper (TeX)
ALS 2001 paper (html)
ALS 2001 paper (TeX)
UML security (html)
LCA 2002 (html)
WVU 2002 (html)
Security Roundtable (html)
OLS 2002 slides
LWE 2005 slides
Fun and Games
Kernel Hangman
Disaster of the Month

tty logging

Setting up tty logging
As an option, UML has the ability to log all data going through UML terminals out to the host. This is primarily useful for honeypots, although other security-related applications might find it useful as well.

The first step in using this is to configure it in. It's enabled with CONFIG_TTY_LOG ('Enable tty logging' under 'Character Devices' in the UML configuration). With this done, UML will automatically log all sessions to the host.

The interval between opening a UML terminal device and closing it is considered to be a session. By default, each session is logged to a separate file in the current directory on the host. The file name is constructed from the current time. There will be a lot of them created during the boot process because each step of bringing the system up opens and closes /dev/console, which makes each line of boot output look like a separate session. Every login will recognized as a session, so those will each appear in its own file. If the user allocates another tty (with su, screen, or some similar tool), that will open a new session, which will get a separate log file on the host.

Customization
There a couple of ways of changing this behavior. To have the log files put in a different directory, use the tty_log_dir switch on the UML command line:
tty_log_dir=dir

The one file per session scheme is the simplest possible way to do logging, but it's limited and may not be suitable for everyone. The main problem is that this definition of session isn't exactly the same as the common notion, which is everything that appears on the user's screen. Utilities which allocate new pseudo-terminals, such as su and screen, will cause new log files to appear, and it won't necessarily be obvious how to splice that into the log of the parent session in order to reconstruct the text seen by the user.

The solution to this problem is to write the logging information out as a single stream of data which contains information about the device that's being used. This is done by specifying the tty_log_fd option on the UML command line:

tty_log_fd=3 3>tty_log_file
This causes UML's file descriptor 3 to be opened to tty_log_file, and the logging data will be written to it.

The logging data is a stream of fixed length records with optional variable length data following.The records have the following form:

struct tty_log_buf {
	int what;
	unsigned long tty;
	int len;
	int direction;
	unsigned long sec;
	unsigned long usec;
};
The 'what' field can have the following values:
                
#define TTY_LOG_OPEN 1
#define TTY_LOG_CLOSE 2
#define TTY_LOG_WRITE 3

              
The 'tty' field is an integer to be used as a unique identifier of the tty. It is actually the address within UML of the tty_struct, but outside UML, it is used as an opaque identifier.

The 'len' field says how much data follows the record. It will be non-zero for TTY_LOG_WRITE and TTY_LOG_OPEN (in UML 2.4.19-40 and later) records, and zero for all others.

If the record type is TTY_LOG_WRITE, then the data that was written to the tty immediately follows the tty_log_buf, and its 'len' field says how much data there will be.

For TTY_LOG_OPEN records, the data length is sizeof(long) and the data is the identifier of the tty that is active in the context of this open. This is what allows character streams from different terminals to be spliced back together to reproduce the stream of text that the user actually saw. This identifier is the 'parent' tty, so the data from the newly opened 'child' tty needs to be inserted at this point into the parent's stream.

The 'direction' field says whether the data was being written to or read from the terminal. It can have one of these values

                
#define TTY_READ 1
#define TTY_WRITE 2

              
The 'sec' and 'usec' fields are a timestamp, which is useful when playing the log back with the original timings. To fully use this functionality, you should use UML version 2.4.19-49 or later. tty logging in skas mode (skas mode is highly recommended for all security-related applications) was broken because of a copy_user bug. Also, TTY_LOG_OPEN wasn't including the parent tty in its data, making session reconstruction impossible.
Log playback
jail/tty_log.pl in the utilities tarball contains a simple log parser. It reads the records written to tty_log_fd, parses them, and prints them out. It should be fairly easy to customize it to do whatever session reconstruction you need.

Also in the utilities tarball is jail/playlog.pl, which is a more user-friendly interface to the log. By default, it will play back the session at its original speed if there is only one session in the log. If there are multiple sessions, it will print out their ids and exit. You must then rerun playlog, specifying which session you want to see. In this case, the command line is

perl playlog.pl log-file [tty-id]
There are some switches which alter its behavior
  • -f - follows a live log, similar to 'tail -f'. This will show the session live, in real time.
  • -n - dumps out the session without recreating the original timing
  • -a - prints out all data, rather than only tty output. This will allow you to see things which didn't echo on the terminal, such as passwords. The downside is that all other user input will be doubled, since those characters are both tty input and tty output.
Hosted at SourceForge Logo