diff options
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r-- | security/selinux/ss/services.c | 239 |
1 files changed, 238 insertions, 1 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 61492485de84..c284dbb8b8c0 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 |
@@ -593,6 +594,10 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) | |||
593 | 594 | ||
594 | *scontext_len = strlen(initial_sid_to_string[sid]) + 1; | 595 | *scontext_len = strlen(initial_sid_to_string[sid]) + 1; |
595 | scontextp = kmalloc(*scontext_len,GFP_ATOMIC); | 596 | scontextp = kmalloc(*scontext_len,GFP_ATOMIC); |
597 | if (!scontextp) { | ||
598 | rc = -ENOMEM; | ||
599 | goto out; | ||
600 | } | ||
596 | strcpy(scontextp, initial_sid_to_string[sid]); | 601 | strcpy(scontextp, initial_sid_to_string[sid]); |
597 | *scontext = scontextp; | 602 | *scontext = scontextp; |
598 | goto out; | 603 | goto out; |
@@ -1811,3 +1816,235 @@ out: | |||
1811 | POLICY_RDUNLOCK; | 1816 | POLICY_RDUNLOCK; |
1812 | return rc; | 1817 | return rc; |
1813 | } | 1818 | } |
1819 | |||
1820 | struct selinux_audit_rule { | ||
1821 | u32 au_seqno; | ||
1822 | struct context au_ctxt; | ||
1823 | }; | ||
1824 | |||
1825 | void selinux_audit_rule_free(struct selinux_audit_rule *rule) | ||
1826 | { | ||
1827 | if (rule) { | ||
1828 | context_destroy(&rule->au_ctxt); | ||
1829 | kfree(rule); | ||
1830 | } | ||
1831 | } | ||
1832 | |||
1833 | int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, | ||
1834 | struct selinux_audit_rule **rule) | ||
1835 | { | ||
1836 | struct selinux_audit_rule *tmprule; | ||
1837 | struct role_datum *roledatum; | ||
1838 | struct type_datum *typedatum; | ||
1839 | struct user_datum *userdatum; | ||
1840 | int rc = 0; | ||
1841 | |||
1842 | *rule = NULL; | ||
1843 | |||
1844 | if (!ss_initialized) | ||
1845 | return -ENOTSUPP; | ||
1846 | |||
1847 | switch (field) { | ||
1848 | case AUDIT_SE_USER: | ||
1849 | case AUDIT_SE_ROLE: | ||
1850 | case AUDIT_SE_TYPE: | ||
1851 | /* only 'equals' and 'not equals' fit user, role, and type */ | ||
1852 | if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL) | ||
1853 | return -EINVAL; | ||
1854 | break; | ||
1855 | case AUDIT_SE_SEN: | ||
1856 | case AUDIT_SE_CLR: | ||
1857 | /* we do not allow a range, indicated by the presense of '-' */ | ||
1858 | if (strchr(rulestr, '-')) | ||
1859 | return -EINVAL; | ||
1860 | break; | ||
1861 | default: | ||
1862 | /* only the above fields are valid */ | ||
1863 | return -EINVAL; | ||
1864 | } | ||
1865 | |||
1866 | tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); | ||
1867 | if (!tmprule) | ||
1868 | return -ENOMEM; | ||
1869 | |||
1870 | context_init(&tmprule->au_ctxt); | ||
1871 | |||
1872 | POLICY_RDLOCK; | ||
1873 | |||
1874 | tmprule->au_seqno = latest_granting; | ||
1875 | |||
1876 | switch (field) { | ||
1877 | case AUDIT_SE_USER: | ||
1878 | userdatum = hashtab_search(policydb.p_users.table, rulestr); | ||
1879 | if (!userdatum) | ||
1880 | rc = -EINVAL; | ||
1881 | else | ||
1882 | tmprule->au_ctxt.user = userdatum->value; | ||
1883 | break; | ||
1884 | case AUDIT_SE_ROLE: | ||
1885 | roledatum = hashtab_search(policydb.p_roles.table, rulestr); | ||
1886 | if (!roledatum) | ||
1887 | rc = -EINVAL; | ||
1888 | else | ||
1889 | tmprule->au_ctxt.role = roledatum->value; | ||
1890 | break; | ||
1891 | case AUDIT_SE_TYPE: | ||
1892 | typedatum = hashtab_search(policydb.p_types.table, rulestr); | ||
1893 | if (!typedatum) | ||
1894 | rc = -EINVAL; | ||
1895 | else | ||
1896 | tmprule->au_ctxt.type = typedatum->value; | ||
1897 | break; | ||
1898 | case AUDIT_SE_SEN: | ||
1899 | case AUDIT_SE_CLR: | ||
1900 | rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); | ||
1901 | break; | ||
1902 | } | ||
1903 | |||
1904 | POLICY_RDUNLOCK; | ||
1905 | |||
1906 | if (rc) { | ||
1907 | selinux_audit_rule_free(tmprule); | ||
1908 | tmprule = NULL; | ||
1909 | } | ||
1910 | |||
1911 | *rule = tmprule; | ||
1912 | |||
1913 | return rc; | ||
1914 | } | ||
1915 | |||
1916 | int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op, | ||
1917 | struct selinux_audit_rule *rule, | ||
1918 | struct audit_context *actx) | ||
1919 | { | ||
1920 | struct context *ctxt; | ||
1921 | struct mls_level *level; | ||
1922 | int match = 0; | ||
1923 | |||
1924 | if (!rule) { | ||
1925 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
1926 | "selinux_audit_rule_match: missing rule\n"); | ||
1927 | return -ENOENT; | ||
1928 | } | ||
1929 | |||
1930 | POLICY_RDLOCK; | ||
1931 | |||
1932 | if (rule->au_seqno < latest_granting) { | ||
1933 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
1934 | "selinux_audit_rule_match: stale rule\n"); | ||
1935 | match = -ESTALE; | ||
1936 | goto out; | ||
1937 | } | ||
1938 | |||
1939 | ctxt = sidtab_search(&sidtab, ctxid); | ||
1940 | if (!ctxt) { | ||
1941 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
1942 | "selinux_audit_rule_match: unrecognized SID %d\n", | ||
1943 | ctxid); | ||
1944 | match = -ENOENT; | ||
1945 | goto out; | ||
1946 | } | ||
1947 | |||
1948 | /* a field/op pair that is not caught here will simply fall through | ||
1949 | without a match */ | ||
1950 | switch (field) { | ||
1951 | case AUDIT_SE_USER: | ||
1952 | switch (op) { | ||
1953 | case AUDIT_EQUAL: | ||
1954 | match = (ctxt->user == rule->au_ctxt.user); | ||
1955 | break; | ||
1956 | case AUDIT_NOT_EQUAL: | ||
1957 | match = (ctxt->user != rule->au_ctxt.user); | ||
1958 | break; | ||
1959 | } | ||
1960 | break; | ||
1961 | case AUDIT_SE_ROLE: | ||
1962 | switch (op) { | ||
1963 | case AUDIT_EQUAL: | ||
1964 | match = (ctxt->role == rule->au_ctxt.role); | ||
1965 | break; | ||
1966 | case AUDIT_NOT_EQUAL: | ||
1967 | match = (ctxt->role != rule->au_ctxt.role); | ||
1968 | break; | ||
1969 | } | ||
1970 | break; | ||
1971 | case AUDIT_SE_TYPE: | ||
1972 | switch (op) { | ||
1973 | case AUDIT_EQUAL: | ||
1974 | match = (ctxt->type == rule->au_ctxt.type); | ||
1975 | break; | ||
1976 | case AUDIT_NOT_EQUAL: | ||
1977 | match = (ctxt->type != rule->au_ctxt.type); | ||
1978 | break; | ||
1979 | } | ||
1980 | break; | ||
1981 | case AUDIT_SE_SEN: | ||
1982 | case AUDIT_SE_CLR: | ||
1983 | level = (op == AUDIT_SE_SEN ? | ||
1984 | &ctxt->range.level[0] : &ctxt->range.level[1]); | ||
1985 | switch (op) { | ||
1986 | case AUDIT_EQUAL: | ||
1987 | match = mls_level_eq(&rule->au_ctxt.range.level[0], | ||
1988 | level); | ||
1989 | break; | ||
1990 | case AUDIT_NOT_EQUAL: | ||
1991 | match = !mls_level_eq(&rule->au_ctxt.range.level[0], | ||
1992 | level); | ||
1993 | break; | ||
1994 | case AUDIT_LESS_THAN: | ||
1995 | match = (mls_level_dom(&rule->au_ctxt.range.level[0], | ||
1996 | level) && | ||
1997 | !mls_level_eq(&rule->au_ctxt.range.level[0], | ||
1998 | level)); | ||
1999 | break; | ||
2000 | case AUDIT_LESS_THAN_OR_EQUAL: | ||
2001 | match = mls_level_dom(&rule->au_ctxt.range.level[0], | ||
2002 | level); | ||
2003 | break; | ||
2004 | case AUDIT_GREATER_THAN: | ||
2005 | match = (mls_level_dom(level, | ||
2006 | &rule->au_ctxt.range.level[0]) && | ||
2007 | !mls_level_eq(level, | ||
2008 | &rule->au_ctxt.range.level[0])); | ||
2009 | break; | ||
2010 | case AUDIT_GREATER_THAN_OR_EQUAL: | ||
2011 | match = mls_level_dom(level, | ||
2012 | &rule->au_ctxt.range.level[0]); | ||
2013 | break; | ||
2014 | } | ||
2015 | } | ||
2016 | |||
2017 | out: | ||
2018 | POLICY_RDUNLOCK; | ||
2019 | return match; | ||
2020 | } | ||
2021 | |||
2022 | static int (*aurule_callback)(void) = NULL; | ||
2023 | |||
2024 | static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, | ||
2025 | u16 class, u32 perms, u32 *retained) | ||
2026 | { | ||
2027 | int err = 0; | ||
2028 | |||
2029 | if (event == AVC_CALLBACK_RESET && aurule_callback) | ||
2030 | err = aurule_callback(); | ||
2031 | return err; | ||
2032 | } | ||
2033 | |||
2034 | static int __init aurule_init(void) | ||
2035 | { | ||
2036 | int err; | ||
2037 | |||
2038 | err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET, | ||
2039 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
2040 | if (err) | ||
2041 | panic("avc_add_callback() failed, error %d\n", err); | ||
2042 | |||
2043 | return err; | ||
2044 | } | ||
2045 | __initcall(aurule_init); | ||
2046 | |||
2047 | void selinux_audit_set_callback(int (*callback)(void)) | ||
2048 | { | ||
2049 | aurule_callback = callback; | ||
2050 | } | ||