Friday, 1 June
2007
Fri, 1 Jun
'07
5:07 p.m.
Hello,
the attached patches propose a way to audit administrative commands.
Summary
-------
A per-process "audit TTY input" attribute is added. The attribute is
inherited across fork (). A new PAM module is used to turn the
attribute on or off on login. Data read from TTYs by processes with the
attribute is sent to the audit subsystem by the kernel. Optionally,
user-space applications can send advisory audit events describing the
"meaning" of the TTY input.
Fundamental limitations
-----------------------
Only TTY input is logged, so an administrator may execute unknown code
by downloading shell scripts over the network. The act of downloading
the shell script would be audited, however.
For GUI or a complex TUI applications (e.g. emacs or mc), auditing the
TTY input probably does not save enough information to reproduce the
sequence of executed commands. If necessary, these applications may be
extended to send advisory audit events. (Any approach to administrative
action auditing would have to extend these applications).
Why auditing needs to be done by the kernel
-------------------------------------------
If system call auditing is not an option, there are simply too many
applications that can be used to perform non-trivial administrative
tasks that would have to be extended. All shells, most programming
language interpreters, awk, m4, ... . In the worst case, the user might
be using a proprietary shell. The system should also be able to handle
at least the trivial workarounds like (cat | sh).
So, if we can't audit the program actions (system calls), and we can't
in general modify the programs themselves, the only remaining option is
to audit the inputs to the programs - TTY input.
This could be done in user-space by running all administrative sessions
in a pseudo-TTY and auditing the data sent to the pseudo-TTY.
Unfortunately that's not transparent enough, and changes behavior (after
logging on to a text console, /dev/stdin is not a VT and can't be used
to send VT ioctls - for a simple example, see /etc/profile.d/lang.sh on
Fedora/RHEL).
Auditing processes, not TTYs
----------------------------
If actions of ordinary users are not audited, after (su -) there are
both administrative and non-administrative processes with the TTY open.
The answer to the question "should this particular byte of input to
the TTY be audited" depends on whether the byte is processed by an
"administrative process", not on whether the TTY is /dev/tty1 or a PTY
representing a ssh connection, or on whether an administrative process
has ever been executed on the TTY since last hangup.
Audit event generation based on a process-inherited flag has one
additional advantage: If root within a (su -) session runs (su -
unprivileged user), root's actions as the unprivileged user are audited.
A potential problem with is approach is unwanted auditing of TTY input
to system daemons run (or restarted) by an administrator; if the
administrator restarts an *getty daemon, all inputs to the daemon would
be audited. As a special hack, opening a TTY in a process that has no
TTY currently open automatically disables the "audit TTY input" flag.
Closing the current TTY and opening another one does not really make any
sense in a regular application, but daemons which close all file
descriptors on startup would be handled by the hack. If the hack
doesn't handle a specific daemon automatically, the daemon could either
be modified to disable auditing, or its startup scripts could explicitly
close TTYs to activate the hack.
Semantics of the logged data
----------------------------
The data is not logged byte by byte; a per-process buffer of data to be
audited is kept, collecting the characters as they are read by the
application. The contents of the buffer are audited if:
- the buffer is full
- ICANON is enabled and an EOL or EOF character is "delivered" to the
application ("delivering EOF" doesn't actually provide any bytes)
- ICANON is enabled or disabled
- auditing TTY input is disabled for the process
- the process exits
- the process sends an advisory TTY input audit event.
Thus, for applications using ICANON, input is audited line by line. For
applications not using ICANON (e.g. uses readline), it is audited in
blocks of N_TTY_BUF bytes. If the application is not using ICANON, it
may send advisory messages; in that case, each "command" is audited
using both the kernel's audit events containing the exact tty input
(e.g. C-r up RET) and the advisory message (e.g. "yum upgrade"), and the
raw input is always audited before the advisory messages.
As a special case, input read when the TTY is using ICANON without ECHO
is _not_ audited, to avoid storing passwords in the audit log. On the
other hand, non-ICANON input is always audited (e.g. vim/emacs/mc input)
in full. Note that passwords may still be audited if they are echoed,
e.g. when sending CREATE USER commands to a SQL server.
Attached code
-------------
- a kernel patch, against a current-ish Linux tree.
- a patch against audit-1.5.3 to recognize the new netlink message types
- a PAM module which allows enabling/disabling TTY auditing on login
- a patch against readline-5.2 to generate advisory audit events on
returned strings. The exact same patch can be used for the readline
copy included in bash-3.2.
Unresolved questions:
---------------------
The advisory audit events may be emitted by any process for which TTY
input is audited, no additional privileges are necessary. Is it
necessary to separately limit the rate of the generated events, or is
the current kernel rate limit sufficient?
Reading and modifying the "audit TTY input" attribute using a the audit
netlink socket works, but it feels unnatural. Should it be done
differently (e.g. /proc, prctl ())? Is it enough to allow an
administrative process to read/modify its own "audit TTY input"
attribute, or is it necessary to access the attribute of other processes?
I'll be grateful for any comments.
Mirek