aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrel Goeddel <dgoeddel@trustedcs.com>2006-02-24 16:44:05 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2006-05-01 06:06:24 -0400
commit376bd9cb357ec945ac893feaeb63af7370a6e70b (patch)
tree7e2848792982dfe30e19a600a41fa5cb49ee6e6e
parent97e94c453073a2aba4bb5e0825ddc5e923debf11 (diff)
[PATCH] support for context based audit filtering
The following patch provides selinux interfaces that will allow the audit system to perform filtering based on the process context (user, role, type, sensitivity, and clearance). These interfaces will allow the selinux module to perform efficient matches based on lower level selinux constructs, rather than relying on context retrievals and string comparisons within the audit module. It also allows for dominance checks on the mls portion of the contexts that are impossible with only string comparisons. Signed-off-by: Darrel Goeddel <dgoeddel@trustedcs.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--include/linux/audit.h5
-rw-r--r--include/linux/selinux.h112
-rw-r--r--security/selinux/Makefile2
-rw-r--r--security/selinux/avc.c13
-rw-r--r--security/selinux/exports.c28
-rw-r--r--security/selinux/ss/mls.c30
-rw-r--r--security/selinux/ss/mls.h4
-rw-r--r--security/selinux/ss/services.c235
8 files changed, 419 insertions, 10 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 39fef6ebb854..740f950397b7 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -145,6 +145,11 @@
145#define AUDIT_PERS 10 145#define AUDIT_PERS 10
146#define AUDIT_ARCH 11 146#define AUDIT_ARCH 11
147#define AUDIT_MSGTYPE 12 147#define AUDIT_MSGTYPE 12
148#define AUDIT_SE_USER 13 /* security label user */
149#define AUDIT_SE_ROLE 14 /* security label role */
150#define AUDIT_SE_TYPE 15 /* security label type */
151#define AUDIT_SE_SEN 16 /* security label sensitivity label */
152#define AUDIT_SE_CLR 17 /* security label clearance label */
148 153
149 /* These are ONLY useful when checking 154 /* These are ONLY useful when checking
150 * at syscall exit time (AUDIT_AT_EXIT). */ 155 * at syscall exit time (AUDIT_AT_EXIT). */
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
new file mode 100644
index 000000000000..9d684b1728b0
--- /dev/null
+++ b/include/linux/selinux.h
@@ -0,0 +1,112 @@
1/*
2 * SELinux services exported to the rest of the kernel.
3 *
4 * Author: James Morris <jmorris@redhat.com>
5 *
6 * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
7 * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2,
11 * as published by the Free Software Foundation.
12 */
13#ifndef _LINUX_SELINUX_H
14#define _LINUX_SELINUX_H
15
16struct selinux_audit_rule;
17struct audit_context;
18
19#ifdef CONFIG_SECURITY_SELINUX
20
21/**
22 * selinux_audit_rule_init - alloc/init an selinux audit rule structure.
23 * @field: the field this rule refers to
24 * @op: the operater the rule uses
25 * @rulestr: the text "target" of the rule
26 * @rule: pointer to the new rule structure returned via this
27 *
28 * Returns 0 if successful, -errno if not. On success, the rule structure
29 * will be allocated internally. The caller must free this structure with
30 * selinux_audit_rule_free() after use.
31 */
32int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
33 struct selinux_audit_rule **rule);
34
35/**
36 * selinux_audit_rule_free - free an selinux audit rule structure.
37 * @rule: pointer to the audit rule to be freed
38 *
39 * This will free all memory associated with the given rule.
40 * If @rule is NULL, no operation is performed.
41 */
42void selinux_audit_rule_free(struct selinux_audit_rule *rule);
43
44/**
45 * selinux_audit_rule_match - determine if a context ID matches a rule.
46 * @ctxid: the context ID to check
47 * @field: the field this rule refers to
48 * @op: the operater the rule uses
49 * @rule: pointer to the audit rule to check against
50 * @actx: the audit context (can be NULL) associated with the check
51 *
52 * Returns 1 if the context id matches the rule, 0 if it does not, and
53 * -errno on failure.
54 */
55int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
56 struct selinux_audit_rule *rule,
57 struct audit_context *actx);
58
59/**
60 * selinux_audit_set_callback - set the callback for policy reloads.
61 * @callback: the function to call when the policy is reloaded
62 *
63 * This sets the function callback function that will update the rules
64 * upon policy reloads. This callback should rebuild all existing rules
65 * using selinux_audit_rule_init().
66 */
67void selinux_audit_set_callback(int (*callback)(void));
68
69/**
70 * selinux_task_ctxid - determine a context ID for a process.
71 * @tsk: the task object
72 * @ctxid: ID value returned via this
73 *
74 * On return, ctxid will contain an ID for the context. This value
75 * should only be used opaquely.
76 */
77void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid);
78
79#else
80
81static inline int selinux_audit_rule_init(u32 field, u32 op,
82 char *rulestr,
83 struct selinux_audit_rule **rule)
84{
85 return -ENOTSUPP;
86}
87
88static inline void selinux_audit_rule_free(struct selinux_audit_rule *rule)
89{
90 return;
91}
92
93static inline int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
94 struct selinux_audit_rule *rule,
95 struct audit_context *actx)
96{
97 return 0;
98}
99
100static inline void selinux_audit_set_callback(int (*callback)(void))
101{
102 return;
103}
104
105static inline void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
106{
107 *ctxid = 0;
108}
109
110#endif /* CONFIG_SECURITY_SELINUX */
111
112#endif /* _LINUX_SELINUX_H */
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 688c0a267b62..faf2e02e4410 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -4,7 +4,7 @@
4 4
5obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/ 5obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
6 6
7selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o 7selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o exports.o
8 8
9selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o 9selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
10 10
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index ac5d69bb3377..a300702da527 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -800,7 +800,7 @@ out:
800int avc_ss_reset(u32 seqno) 800int avc_ss_reset(u32 seqno)
801{ 801{
802 struct avc_callback_node *c; 802 struct avc_callback_node *c;
803 int i, rc = 0; 803 int i, rc = 0, tmprc;
804 unsigned long flag; 804 unsigned long flag;
805 struct avc_node *node; 805 struct avc_node *node;
806 806
@@ -813,15 +813,16 @@ int avc_ss_reset(u32 seqno)
813 813
814 for (c = avc_callbacks; c; c = c->next) { 814 for (c = avc_callbacks; c; c = c->next) {
815 if (c->events & AVC_CALLBACK_RESET) { 815 if (c->events & AVC_CALLBACK_RESET) {
816 rc = c->callback(AVC_CALLBACK_RESET, 816 tmprc = c->callback(AVC_CALLBACK_RESET,
817 0, 0, 0, 0, NULL); 817 0, 0, 0, 0, NULL);
818 if (rc) 818 /* save the first error encountered for the return
819 goto out; 819 value and continue processing the callbacks */
820 if (!rc)
821 rc = tmprc;
820 } 822 }
821 } 823 }
822 824
823 avc_latest_notif_update(seqno, 0); 825 avc_latest_notif_update(seqno, 0);
824out:
825 return rc; 826 return rc;
826} 827}
827 828
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
new file mode 100644
index 000000000000..333c4c7824d8
--- /dev/null
+++ b/security/selinux/exports.c
@@ -0,0 +1,28 @@
1/*
2 * SELinux services exported to the rest of the kernel.
3 *
4 * Author: James Morris <jmorris@redhat.com>
5 *
6 * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
7 * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2,
11 * as published by the Free Software Foundation.
12 */
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/selinux.h>
17
18#include "security.h"
19#include "objsec.h"
20
21void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
22{
23 struct task_security_struct *tsec = tsk->security;
24 if (selinux_enabled)
25 *ctxid = tsec->sid;
26 else
27 *ctxid = 0;
28}
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 84047f69f9c1..7bc5b6440f70 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -8,7 +8,7 @@
8 * 8 *
9 * Support for enhanced MLS infrastructure. 9 * Support for enhanced MLS infrastructure.
10 * 10 *
11 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12 */ 12 */
13 13
14#include <linux/kernel.h> 14#include <linux/kernel.h>
@@ -385,6 +385,34 @@ out:
385} 385}
386 386
387/* 387/*
388 * Set the MLS fields in the security context structure
389 * `context' based on the string representation in
390 * the string `str'. This function will allocate temporary memory with the
391 * given constraints of gfp_mask.
392 */
393int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
394{
395 char *tmpstr, *freestr;
396 int rc;
397
398 if (!selinux_mls_enabled)
399 return -EINVAL;
400
401 /* we need freestr because mls_context_to_sid will change
402 the value of tmpstr */
403 tmpstr = freestr = kstrdup(str, gfp_mask);
404 if (!tmpstr) {
405 rc = -ENOMEM;
406 } else {
407 rc = mls_context_to_sid(':', &tmpstr, context,
408 NULL, SECSID_NULL);
409 kfree(freestr);
410 }
411
412 return rc;
413}
414
415/*
388 * Copies the effective MLS range from `src' into `dst'. 416 * Copies the effective MLS range from `src' into `dst'.
389 */ 417 */
390static inline int mls_scopy_context(struct context *dst, 418static inline int mls_scopy_context(struct context *dst,
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 03de697c8058..fbb42f07dd7c 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -8,7 +8,7 @@
8 * 8 *
9 * Support for enhanced MLS infrastructure. 9 * Support for enhanced MLS infrastructure.
10 * 10 *
11 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 11 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
12 */ 12 */
13 13
14#ifndef _SS_MLS_H_ 14#ifndef _SS_MLS_H_
@@ -27,6 +27,8 @@ int mls_context_to_sid(char oldc,
27 struct sidtab *s, 27 struct sidtab *s,
28 u32 def_sid); 28 u32 def_sid);
29 29
30int mls_from_string(char *str, struct context *context, gfp_t gfp_mask);
31
30int mls_convert_context(struct policydb *oldp, 32int mls_convert_context(struct policydb *oldp,
31 struct policydb *newp, 33 struct policydb *newp,
32 struct context *context); 34 struct context *context);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 61492485de84..7177e98df7f3 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -7,12 +7,13 @@
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> 7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 * 8 *
9 * Support for enhanced MLS infrastructure. 9 * Support for enhanced MLS infrastructure.
10 * Support for context based audit filters.
10 * 11 *
11 * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> 12 * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
12 * 13 *
13 * Added conditional policy language extensions 14 * Added conditional policy language extensions
14 * 15 *
15 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 16 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
16 * Copyright (C) 2003 - 2004 Tresys Technology, LLC 17 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
17 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 18 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
18 * This program is free software; you can redistribute it and/or modify 19 * This program is free software; you can redistribute it and/or modify
@@ -1811,3 +1812,235 @@ out:
1811 POLICY_RDUNLOCK; 1812 POLICY_RDUNLOCK;
1812 return rc; 1813 return rc;
1813} 1814}
1815
1816struct selinux_audit_rule {
1817 u32 au_seqno;
1818 struct context au_ctxt;
1819};
1820
1821void selinux_audit_rule_free(struct selinux_audit_rule *rule)
1822{
1823 if (rule) {
1824 context_destroy(&rule->au_ctxt);
1825 kfree(rule);
1826 }
1827}
1828
1829int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
1830 struct selinux_audit_rule **rule)
1831{
1832 struct selinux_audit_rule *tmprule;
1833 struct role_datum *roledatum;
1834 struct type_datum *typedatum;
1835 struct user_datum *userdatum;
1836 int rc = 0;
1837
1838 *rule = NULL;
1839
1840 if (!ss_initialized)
1841 return -ENOTSUPP;
1842
1843 switch (field) {
1844 case AUDIT_SE_USER:
1845 case AUDIT_SE_ROLE:
1846 case AUDIT_SE_TYPE:
1847 /* only 'equals' and 'not equals' fit user, role, and type */
1848 if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
1849 return -EINVAL;
1850 break;
1851 case AUDIT_SE_SEN:
1852 case AUDIT_SE_CLR:
1853 /* we do not allow a range, indicated by the presense of '-' */
1854 if (strchr(rulestr, '-'))
1855 return -EINVAL;
1856 break;
1857 default:
1858 /* only the above fields are valid */
1859 return -EINVAL;
1860 }
1861
1862 tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
1863 if (!tmprule)
1864 return -ENOMEM;
1865
1866 context_init(&tmprule->au_ctxt);
1867
1868 POLICY_RDLOCK;
1869
1870 tmprule->au_seqno = latest_granting;
1871
1872 switch (field) {
1873 case AUDIT_SE_USER:
1874 userdatum = hashtab_search(policydb.p_users.table, rulestr);
1875 if (!userdatum)
1876 rc = -EINVAL;
1877 else
1878 tmprule->au_ctxt.user = userdatum->value;
1879 break;
1880 case AUDIT_SE_ROLE:
1881 roledatum = hashtab_search(policydb.p_roles.table, rulestr);
1882 if (!roledatum)
1883 rc = -EINVAL;
1884 else
1885 tmprule->au_ctxt.role = roledatum->value;
1886 break;
1887 case AUDIT_SE_TYPE:
1888 typedatum = hashtab_search(policydb.p_types.table, rulestr);
1889 if (!typedatum)
1890 rc = -EINVAL;
1891 else
1892 tmprule->au_ctxt.type = typedatum->value;
1893 break;
1894 case AUDIT_SE_SEN:
1895 case AUDIT_SE_CLR:
1896 rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
1897 break;
1898 }
1899
1900 POLICY_RDUNLOCK;
1901
1902 if (rc) {
1903 selinux_audit_rule_free(tmprule);
1904 tmprule = NULL;
1905 }
1906
1907 *rule = tmprule;
1908
1909 return rc;
1910}
1911
1912int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
1913 struct selinux_audit_rule *rule,
1914 struct audit_context *actx)
1915{
1916 struct context *ctxt;
1917 struct mls_level *level;
1918 int match = 0;
1919
1920 if (!rule) {
1921 audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
1922 "selinux_audit_rule_match: missing rule\n");
1923 return -ENOENT;
1924 }
1925
1926 POLICY_RDLOCK;
1927
1928 if (rule->au_seqno < latest_granting) {
1929 audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
1930 "selinux_audit_rule_match: stale rule\n");
1931 match = -ESTALE;
1932 goto out;
1933 }
1934
1935 ctxt = sidtab_search(&sidtab, ctxid);
1936 if (!ctxt) {
1937 audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
1938 "selinux_audit_rule_match: unrecognized SID %d\n",
1939 ctxid);
1940 match = -ENOENT;
1941 goto out;
1942 }
1943
1944 /* a field/op pair that is not caught here will simply fall through
1945 without a match */
1946 switch (field) {
1947 case AUDIT_SE_USER:
1948 switch (op) {
1949 case AUDIT_EQUAL:
1950 match = (ctxt->user == rule->au_ctxt.user);
1951 break;
1952 case AUDIT_NOT_EQUAL:
1953 match = (ctxt->user != rule->au_ctxt.user);
1954 break;
1955 }
1956 break;
1957 case AUDIT_SE_ROLE:
1958 switch (op) {
1959 case AUDIT_EQUAL:
1960 match = (ctxt->role == rule->au_ctxt.role);
1961 break;
1962 case AUDIT_NOT_EQUAL:
1963 match = (ctxt->role != rule->au_ctxt.role);
1964 break;
1965 }
1966 break;
1967 case AUDIT_SE_TYPE:
1968 switch (op) {
1969 case AUDIT_EQUAL:
1970 match = (ctxt->type == rule->au_ctxt.type);
1971 break;
1972 case AUDIT_NOT_EQUAL:
1973 match = (ctxt->type != rule->au_ctxt.type);
1974 break;
1975 }
1976 break;
1977 case AUDIT_SE_SEN:
1978 case AUDIT_SE_CLR:
1979 level = (op == AUDIT_SE_SEN ?
1980 &ctxt->range.level[0] : &ctxt->range.level[1]);
1981 switch (op) {
1982 case AUDIT_EQUAL:
1983 match = mls_level_eq(&rule->au_ctxt.range.level[0],
1984 level);
1985 break;
1986 case AUDIT_NOT_EQUAL:
1987 match = !mls_level_eq(&rule->au_ctxt.range.level[0],
1988 level);
1989 break;
1990 case AUDIT_LESS_THAN:
1991 match = (mls_level_dom(&rule->au_ctxt.range.level[0],
1992 level) &&
1993 !mls_level_eq(&rule->au_ctxt.range.level[0],
1994 level));
1995 break;
1996 case AUDIT_LESS_THAN_OR_EQUAL:
1997 match = mls_level_dom(&rule->au_ctxt.range.level[0],
1998 level);
1999 break;
2000 case AUDIT_GREATER_THAN:
2001 match = (mls_level_dom(level,
2002 &rule->au_ctxt.range.level[0]) &&
2003 !mls_level_eq(level,
2004 &rule->au_ctxt.range.level[0]));
2005 break;
2006 case AUDIT_GREATER_THAN_OR_EQUAL:
2007 match = mls_level_dom(level,
2008 &rule->au_ctxt.range.level[0]);
2009 break;
2010 }
2011 }
2012
2013out:
2014 POLICY_RDUNLOCK;
2015 return match;
2016}
2017
2018static int (*aurule_callback)(void) = NULL;
2019
2020static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
2021 u16 class, u32 perms, u32 *retained)
2022{
2023 int err = 0;
2024
2025 if (event == AVC_CALLBACK_RESET && aurule_callback)
2026 err = aurule_callback();
2027 return err;
2028}
2029
2030static int __init aurule_init(void)
2031{
2032 int err;
2033
2034 err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET,
2035 SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
2036 if (err)
2037 panic("avc_add_callback() failed, error %d\n", err);
2038
2039 return err;
2040}
2041__initcall(aurule_init);
2042
2043void selinux_audit_set_callback(int (*callback)(void))
2044{
2045 aurule_callback = callback;
2046}