aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorMiloslav Trmac <mitr@redhat.com>2007-07-16 02:40:56 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:47 -0400
commit522ed7767e800cff6c650ec64b0ee0677303119c (patch)
treef65ecb29f2cf885018d3557f840de3ef4be6ec64 /kernel
parent4f27c00bf80f122513d3a5be16ed851573164534 (diff)
Audit: add TTY input auditing
Add TTY input auditing, used to audit system administrator's actions. This is required by various security standards such as DCID 6/3 and PCI to provide non-repudiation of administrator's actions and to allow a review of past actions if the administrator seems to overstep their duties or if the system becomes misconfigured for unknown reasons. These requirements do not make it necessary to audit TTY output as well. Compared to an user-space keylogger, this approach records TTY input using the audit subsystem, correlated with other audit events, and it is completely transparent to the user-space application (e.g. the console ioctls still work). TTY input auditing works on a higher level than auditing all system calls within the session, which would produce an overwhelming amount of mostly useless audit events. Add an "audit_tty" attribute, inherited across fork (). Data read from TTYs by process with the attribute is sent to the audit subsystem by the kernel. The audit netlink interface is extended to allow modifying the audit_tty attribute, and to allow sending explanatory audit events from user-space (for example, a shell might send an event containing the final command, after the interactive command-line editing and history expansion is performed, which might be difficult to decipher from the TTY input alone). Because the "audit_tty" attribute is inherited across fork (), it would be set e.g. for sshd restarted within an audited session. To prevent this, the audit_tty attribute is cleared when a process with no open TTY file descriptors (e.g. after daemon startup) opens a TTY. See https://www.redhat.com/archives/linux-audit/2007-June/msg00000.html for a more detailed rationale document for an older version of this patch. [akpm@linux-foundation.org: build fix] Signed-off-by: Miloslav Trmac <mitr@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: Paul Fulghum <paulkf@microgate.com> Cc: Casey Schaufler <casey@schaufler-ca.com> Cc: Steve Grubb <sgrubb@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.c96
-rw-r--r--kernel/audit.h1
-rw-r--r--kernel/auditsc.c3
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c3
5 files changed, 93 insertions, 12 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index d13276d41410..5ce8851facf7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -58,6 +58,7 @@
58#include <linux/selinux.h> 58#include <linux/selinux.h>
59#include <linux/inotify.h> 59#include <linux/inotify.h>
60#include <linux/freezer.h> 60#include <linux/freezer.h>
61#include <linux/tty.h>
61 62
62#include "audit.h" 63#include "audit.h"
63 64
@@ -423,6 +424,31 @@ static int kauditd_thread(void *dummy)
423 return 0; 424 return 0;
424} 425}
425 426
427static int audit_prepare_user_tty(pid_t pid, uid_t loginuid)
428{
429 struct task_struct *tsk;
430 int err;
431
432 read_lock(&tasklist_lock);
433 tsk = find_task_by_pid(pid);
434 err = -ESRCH;
435 if (!tsk)
436 goto out;
437 err = 0;
438
439 spin_lock_irq(&tsk->sighand->siglock);
440 if (!tsk->signal->audit_tty)
441 err = -EPERM;
442 spin_unlock_irq(&tsk->sighand->siglock);
443 if (err)
444 goto out;
445
446 tty_audit_push_task(tsk, loginuid);
447out:
448 read_unlock(&tasklist_lock);
449 return err;
450}
451
426int audit_send_list(void *_dest) 452int audit_send_list(void *_dest)
427{ 453{
428 struct audit_netlink_list *dest = _dest; 454 struct audit_netlink_list *dest = _dest;
@@ -511,6 +537,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
511 case AUDIT_DEL: 537 case AUDIT_DEL:
512 case AUDIT_DEL_RULE: 538 case AUDIT_DEL_RULE:
513 case AUDIT_SIGNAL_INFO: 539 case AUDIT_SIGNAL_INFO:
540 case AUDIT_TTY_GET:
541 case AUDIT_TTY_SET:
514 if (security_netlink_recv(skb, CAP_AUDIT_CONTROL)) 542 if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
515 err = -EPERM; 543 err = -EPERM;
516 break; 544 break;
@@ -622,6 +650,11 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
622 err = audit_filter_user(&NETLINK_CB(skb), msg_type); 650 err = audit_filter_user(&NETLINK_CB(skb), msg_type);
623 if (err == 1) { 651 if (err == 1) {
624 err = 0; 652 err = 0;
653 if (msg_type == AUDIT_USER_TTY) {
654 err = audit_prepare_user_tty(pid, loginuid);
655 if (err)
656 break;
657 }
625 ab = audit_log_start(NULL, GFP_KERNEL, msg_type); 658 ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
626 if (ab) { 659 if (ab) {
627 audit_log_format(ab, 660 audit_log_format(ab,
@@ -638,8 +671,17 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
638 " subj=%s", ctx); 671 " subj=%s", ctx);
639 kfree(ctx); 672 kfree(ctx);
640 } 673 }
641 audit_log_format(ab, " msg='%.1024s'", 674 if (msg_type != AUDIT_USER_TTY)
642 (char *)data); 675 audit_log_format(ab, " msg='%.1024s'",
676 (char *)data);
677 else {
678 int size;
679
680 audit_log_format(ab, " msg=");
681 size = nlmsg_len(nlh);
682 audit_log_n_untrustedstring(ab, size,
683 data);
684 }
643 audit_set_pid(ab, pid); 685 audit_set_pid(ab, pid);
644 audit_log_end(ab); 686 audit_log_end(ab);
645 } 687 }
@@ -730,6 +772,45 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
730 0, 0, sig_data, sizeof(*sig_data) + len); 772 0, 0, sig_data, sizeof(*sig_data) + len);
731 kfree(sig_data); 773 kfree(sig_data);
732 break; 774 break;
775 case AUDIT_TTY_GET: {
776 struct audit_tty_status s;
777 struct task_struct *tsk;
778
779 read_lock(&tasklist_lock);
780 tsk = find_task_by_pid(pid);
781 if (!tsk)
782 err = -ESRCH;
783 else {
784 spin_lock_irq(&tsk->sighand->siglock);
785 s.enabled = tsk->signal->audit_tty != 0;
786 spin_unlock_irq(&tsk->sighand->siglock);
787 }
788 read_unlock(&tasklist_lock);
789 audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_TTY_GET, 0, 0,
790 &s, sizeof(s));
791 break;
792 }
793 case AUDIT_TTY_SET: {
794 struct audit_tty_status *s;
795 struct task_struct *tsk;
796
797 if (nlh->nlmsg_len < sizeof(struct audit_tty_status))
798 return -EINVAL;
799 s = data;
800 if (s->enabled != 0 && s->enabled != 1)
801 return -EINVAL;
802 read_lock(&tasklist_lock);
803 tsk = find_task_by_pid(pid);
804 if (!tsk)
805 err = -ESRCH;
806 else {
807 spin_lock_irq(&tsk->sighand->siglock);
808 tsk->signal->audit_tty = s->enabled != 0;
809 spin_unlock_irq(&tsk->sighand->siglock);
810 }
811 read_unlock(&tasklist_lock);
812 break;
813 }
733 default: 814 default:
734 err = -EINVAL; 815 err = -EINVAL;
735 break; 816 break;
@@ -1185,7 +1266,7 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
1185} 1266}
1186 1267
1187/** 1268/**
1188 * audit_log_n_unstrustedstring - log a string that may contain random characters 1269 * audit_log_n_untrustedstring - log a string that may contain random characters
1189 * @ab: audit_buffer 1270 * @ab: audit_buffer
1190 * @len: lenth of string (not including trailing null) 1271 * @len: lenth of string (not including trailing null)
1191 * @string: string to be logged 1272 * @string: string to be logged
@@ -1201,25 +1282,24 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
1201const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len, 1282const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
1202 const char *string) 1283 const char *string)
1203{ 1284{
1204 const unsigned char *p = string; 1285 const unsigned char *p;
1205 1286
1206 while (*p) { 1287 for (p = string; p < (const unsigned char *)string + len && *p; p++) {
1207 if (*p == '"' || *p < 0x21 || *p > 0x7f) { 1288 if (*p == '"' || *p < 0x21 || *p > 0x7f) {
1208 audit_log_hex(ab, string, len); 1289 audit_log_hex(ab, string, len);
1209 return string + len + 1; 1290 return string + len + 1;
1210 } 1291 }
1211 p++;
1212 } 1292 }
1213 audit_log_n_string(ab, len, string); 1293 audit_log_n_string(ab, len, string);
1214 return p + 1; 1294 return p + 1;
1215} 1295}
1216 1296
1217/** 1297/**
1218 * audit_log_unstrustedstring - log a string that may contain random characters 1298 * audit_log_untrustedstring - log a string that may contain random characters
1219 * @ab: audit_buffer 1299 * @ab: audit_buffer
1220 * @string: string to be logged 1300 * @string: string to be logged
1221 * 1301 *
1222 * Same as audit_log_n_unstrustedstring(), except that strlen is used to 1302 * Same as audit_log_n_untrustedstring(), except that strlen is used to
1223 * determine string length. 1303 * determine string length.
1224 */ 1304 */
1225const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string) 1305const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
diff --git a/kernel/audit.h b/kernel/audit.h
index 815d6f5c04ee..95877435c347 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -115,7 +115,6 @@ extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
115extern void audit_send_reply(int pid, int seq, int type, 115extern void audit_send_reply(int pid, int seq, int type,
116 int done, int multi, 116 int done, int multi,
117 void *payload, int size); 117 void *payload, int size);
118extern void audit_log_lost(const char *message);
119extern void audit_panic(const char *message); 118extern void audit_panic(const char *message);
120 119
121struct audit_netlink_list { 120struct audit_netlink_list {
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e36481ed61b4..7ccc3da30a91 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -71,9 +71,6 @@
71 71
72extern struct list_head audit_filter_list[]; 72extern struct list_head audit_filter_list[];
73 73
74/* No syscall auditing will take place unless audit_enabled != 0. */
75extern int audit_enabled;
76
77/* AUDIT_NAMES is the number of slots we reserve in the audit_context 74/* AUDIT_NAMES is the number of slots we reserve in the audit_context
78 * for saving names from getname(). */ 75 * for saving names from getname(). */
79#define AUDIT_NAMES 20 76#define AUDIT_NAMES 20
diff --git a/kernel/exit.c b/kernel/exit.c
index 64a5263c8c7b..57626692cd90 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -965,6 +965,8 @@ fastcall NORET_TYPE void do_exit(long code)
965 if (unlikely(tsk->compat_robust_list)) 965 if (unlikely(tsk->compat_robust_list))
966 compat_exit_robust_list(tsk); 966 compat_exit_robust_list(tsk);
967#endif 967#endif
968 if (group_dead)
969 tty_audit_exit();
968 if (unlikely(tsk->audit_context)) 970 if (unlikely(tsk->audit_context))
969 audit_free(tsk); 971 audit_free(tsk);
970 972
diff --git a/kernel/fork.c b/kernel/fork.c
index 344d693fdc78..4015912aaac2 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -49,6 +49,7 @@
49#include <linux/delayacct.h> 49#include <linux/delayacct.h>
50#include <linux/taskstats_kern.h> 50#include <linux/taskstats_kern.h>
51#include <linux/random.h> 51#include <linux/random.h>
52#include <linux/tty.h>
52 53
53#include <asm/pgtable.h> 54#include <asm/pgtable.h>
54#include <asm/pgalloc.h> 55#include <asm/pgalloc.h>
@@ -897,6 +898,8 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
897 } 898 }
898 acct_init_pacct(&sig->pacct); 899 acct_init_pacct(&sig->pacct);
899 900
901 tty_audit_fork(sig);
902
900 return 0; 903 return 0;
901} 904}
902 905