diff options
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r-- | security/selinux/ss/services.c | 76 |
1 files changed, 44 insertions, 32 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d106733ad987..4bca49414a40 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1232,6 +1232,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
1232 | struct context context; | 1232 | struct context context; |
1233 | int rc = 0; | 1233 | int rc = 0; |
1234 | 1234 | ||
1235 | /* An empty security context is never valid. */ | ||
1236 | if (!scontext_len) | ||
1237 | return -EINVAL; | ||
1238 | |||
1235 | if (!ss_initialized) { | 1239 | if (!ss_initialized) { |
1236 | int i; | 1240 | int i; |
1237 | 1241 | ||
@@ -1285,16 +1289,18 @@ out: | |||
1285 | * @scontext: security context | 1289 | * @scontext: security context |
1286 | * @scontext_len: length in bytes | 1290 | * @scontext_len: length in bytes |
1287 | * @sid: security identifier, SID | 1291 | * @sid: security identifier, SID |
1292 | * @gfp: context for the allocation | ||
1288 | * | 1293 | * |
1289 | * Obtains a SID associated with the security context that | 1294 | * Obtains a SID associated with the security context that |
1290 | * has the string representation specified by @scontext. | 1295 | * has the string representation specified by @scontext. |
1291 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient | 1296 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient |
1292 | * memory is available, or 0 on success. | 1297 | * memory is available, or 0 on success. |
1293 | */ | 1298 | */ |
1294 | int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) | 1299 | int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid, |
1300 | gfp_t gfp) | ||
1295 | { | 1301 | { |
1296 | return security_context_to_sid_core(scontext, scontext_len, | 1302 | return security_context_to_sid_core(scontext, scontext_len, |
1297 | sid, SECSID_NULL, GFP_KERNEL, 0); | 1303 | sid, SECSID_NULL, gfp, 0); |
1298 | } | 1304 | } |
1299 | 1305 | ||
1300 | /** | 1306 | /** |
@@ -1831,7 +1837,7 @@ static int security_preserve_bools(struct policydb *p); | |||
1831 | */ | 1837 | */ |
1832 | int security_load_policy(void *data, size_t len) | 1838 | int security_load_policy(void *data, size_t len) |
1833 | { | 1839 | { |
1834 | struct policydb oldpolicydb, newpolicydb; | 1840 | struct policydb *oldpolicydb, *newpolicydb; |
1835 | struct sidtab oldsidtab, newsidtab; | 1841 | struct sidtab oldsidtab, newsidtab; |
1836 | struct selinux_mapping *oldmap, *map = NULL; | 1842 | struct selinux_mapping *oldmap, *map = NULL; |
1837 | struct convert_context_args args; | 1843 | struct convert_context_args args; |
@@ -1840,12 +1846,19 @@ int security_load_policy(void *data, size_t len) | |||
1840 | int rc = 0; | 1846 | int rc = 0; |
1841 | struct policy_file file = { data, len }, *fp = &file; | 1847 | struct policy_file file = { data, len }, *fp = &file; |
1842 | 1848 | ||
1849 | oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); | ||
1850 | if (!oldpolicydb) { | ||
1851 | rc = -ENOMEM; | ||
1852 | goto out; | ||
1853 | } | ||
1854 | newpolicydb = oldpolicydb + 1; | ||
1855 | |||
1843 | if (!ss_initialized) { | 1856 | if (!ss_initialized) { |
1844 | avtab_cache_init(); | 1857 | avtab_cache_init(); |
1845 | rc = policydb_read(&policydb, fp); | 1858 | rc = policydb_read(&policydb, fp); |
1846 | if (rc) { | 1859 | if (rc) { |
1847 | avtab_cache_destroy(); | 1860 | avtab_cache_destroy(); |
1848 | return rc; | 1861 | goto out; |
1849 | } | 1862 | } |
1850 | 1863 | ||
1851 | policydb.len = len; | 1864 | policydb.len = len; |
@@ -1855,14 +1868,14 @@ int security_load_policy(void *data, size_t len) | |||
1855 | if (rc) { | 1868 | if (rc) { |
1856 | policydb_destroy(&policydb); | 1869 | policydb_destroy(&policydb); |
1857 | avtab_cache_destroy(); | 1870 | avtab_cache_destroy(); |
1858 | return rc; | 1871 | goto out; |
1859 | } | 1872 | } |
1860 | 1873 | ||
1861 | rc = policydb_load_isids(&policydb, &sidtab); | 1874 | rc = policydb_load_isids(&policydb, &sidtab); |
1862 | if (rc) { | 1875 | if (rc) { |
1863 | policydb_destroy(&policydb); | 1876 | policydb_destroy(&policydb); |
1864 | avtab_cache_destroy(); | 1877 | avtab_cache_destroy(); |
1865 | return rc; | 1878 | goto out; |
1866 | } | 1879 | } |
1867 | 1880 | ||
1868 | security_load_policycaps(); | 1881 | security_load_policycaps(); |
@@ -1874,36 +1887,36 @@ int security_load_policy(void *data, size_t len) | |||
1874 | selinux_status_update_policyload(seqno); | 1887 | selinux_status_update_policyload(seqno); |
1875 | selinux_netlbl_cache_invalidate(); | 1888 | selinux_netlbl_cache_invalidate(); |
1876 | selinux_xfrm_notify_policyload(); | 1889 | selinux_xfrm_notify_policyload(); |
1877 | return 0; | 1890 | goto out; |
1878 | } | 1891 | } |
1879 | 1892 | ||
1880 | #if 0 | 1893 | #if 0 |
1881 | sidtab_hash_eval(&sidtab, "sids"); | 1894 | sidtab_hash_eval(&sidtab, "sids"); |
1882 | #endif | 1895 | #endif |
1883 | 1896 | ||
1884 | rc = policydb_read(&newpolicydb, fp); | 1897 | rc = policydb_read(newpolicydb, fp); |
1885 | if (rc) | 1898 | if (rc) |
1886 | return rc; | 1899 | goto out; |
1887 | 1900 | ||
1888 | newpolicydb.len = len; | 1901 | newpolicydb->len = len; |
1889 | /* If switching between different policy types, log MLS status */ | 1902 | /* If switching between different policy types, log MLS status */ |
1890 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | 1903 | if (policydb.mls_enabled && !newpolicydb->mls_enabled) |
1891 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); | 1904 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); |
1892 | else if (!policydb.mls_enabled && newpolicydb.mls_enabled) | 1905 | else if (!policydb.mls_enabled && newpolicydb->mls_enabled) |
1893 | printk(KERN_INFO "SELinux: Enabling MLS support...\n"); | 1906 | printk(KERN_INFO "SELinux: Enabling MLS support...\n"); |
1894 | 1907 | ||
1895 | rc = policydb_load_isids(&newpolicydb, &newsidtab); | 1908 | rc = policydb_load_isids(newpolicydb, &newsidtab); |
1896 | if (rc) { | 1909 | if (rc) { |
1897 | printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); | 1910 | printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); |
1898 | policydb_destroy(&newpolicydb); | 1911 | policydb_destroy(newpolicydb); |
1899 | return rc; | 1912 | goto out; |
1900 | } | 1913 | } |
1901 | 1914 | ||
1902 | rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); | 1915 | rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size); |
1903 | if (rc) | 1916 | if (rc) |
1904 | goto err; | 1917 | goto err; |
1905 | 1918 | ||
1906 | rc = security_preserve_bools(&newpolicydb); | 1919 | rc = security_preserve_bools(newpolicydb); |
1907 | if (rc) { | 1920 | if (rc) { |
1908 | printk(KERN_ERR "SELinux: unable to preserve booleans\n"); | 1921 | printk(KERN_ERR "SELinux: unable to preserve booleans\n"); |
1909 | goto err; | 1922 | goto err; |
@@ -1921,7 +1934,7 @@ int security_load_policy(void *data, size_t len) | |||
1921 | * in the new SID table. | 1934 | * in the new SID table. |
1922 | */ | 1935 | */ |
1923 | args.oldp = &policydb; | 1936 | args.oldp = &policydb; |
1924 | args.newp = &newpolicydb; | 1937 | args.newp = newpolicydb; |
1925 | rc = sidtab_map(&newsidtab, convert_context, &args); | 1938 | rc = sidtab_map(&newsidtab, convert_context, &args); |
1926 | if (rc) { | 1939 | if (rc) { |
1927 | printk(KERN_ERR "SELinux: unable to convert the internal" | 1940 | printk(KERN_ERR "SELinux: unable to convert the internal" |
@@ -1931,12 +1944,12 @@ int security_load_policy(void *data, size_t len) | |||
1931 | } | 1944 | } |
1932 | 1945 | ||
1933 | /* Save the old policydb and SID table to free later. */ | 1946 | /* Save the old policydb and SID table to free later. */ |
1934 | memcpy(&oldpolicydb, &policydb, sizeof policydb); | 1947 | memcpy(oldpolicydb, &policydb, sizeof(policydb)); |
1935 | sidtab_set(&oldsidtab, &sidtab); | 1948 | sidtab_set(&oldsidtab, &sidtab); |
1936 | 1949 | ||
1937 | /* Install the new policydb and SID table. */ | 1950 | /* Install the new policydb and SID table. */ |
1938 | write_lock_irq(&policy_rwlock); | 1951 | write_lock_irq(&policy_rwlock); |
1939 | memcpy(&policydb, &newpolicydb, sizeof policydb); | 1952 | memcpy(&policydb, newpolicydb, sizeof(policydb)); |
1940 | sidtab_set(&sidtab, &newsidtab); | 1953 | sidtab_set(&sidtab, &newsidtab); |
1941 | security_load_policycaps(); | 1954 | security_load_policycaps(); |
1942 | oldmap = current_mapping; | 1955 | oldmap = current_mapping; |
@@ -1946,7 +1959,7 @@ int security_load_policy(void *data, size_t len) | |||
1946 | write_unlock_irq(&policy_rwlock); | 1959 | write_unlock_irq(&policy_rwlock); |
1947 | 1960 | ||
1948 | /* Free the old policydb and SID table. */ | 1961 | /* Free the old policydb and SID table. */ |
1949 | policydb_destroy(&oldpolicydb); | 1962 | policydb_destroy(oldpolicydb); |
1950 | sidtab_destroy(&oldsidtab); | 1963 | sidtab_destroy(&oldsidtab); |
1951 | kfree(oldmap); | 1964 | kfree(oldmap); |
1952 | 1965 | ||
@@ -1956,14 +1969,17 @@ int security_load_policy(void *data, size_t len) | |||
1956 | selinux_netlbl_cache_invalidate(); | 1969 | selinux_netlbl_cache_invalidate(); |
1957 | selinux_xfrm_notify_policyload(); | 1970 | selinux_xfrm_notify_policyload(); |
1958 | 1971 | ||
1959 | return 0; | 1972 | rc = 0; |
1973 | goto out; | ||
1960 | 1974 | ||
1961 | err: | 1975 | err: |
1962 | kfree(map); | 1976 | kfree(map); |
1963 | sidtab_destroy(&newsidtab); | 1977 | sidtab_destroy(&newsidtab); |
1964 | policydb_destroy(&newpolicydb); | 1978 | policydb_destroy(newpolicydb); |
1965 | return rc; | ||
1966 | 1979 | ||
1980 | out: | ||
1981 | kfree(oldpolicydb); | ||
1982 | return rc; | ||
1967 | } | 1983 | } |
1968 | 1984 | ||
1969 | size_t security_policydb_len(void) | 1985 | size_t security_policydb_len(void) |
@@ -2938,25 +2954,21 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, | |||
2938 | struct selinux_audit_rule *rule = vrule; | 2954 | struct selinux_audit_rule *rule = vrule; |
2939 | int match = 0; | 2955 | int match = 0; |
2940 | 2956 | ||
2941 | if (!rule) { | 2957 | if (unlikely(!rule)) { |
2942 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 2958 | WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n"); |
2943 | "selinux_audit_rule_match: missing rule\n"); | ||
2944 | return -ENOENT; | 2959 | return -ENOENT; |
2945 | } | 2960 | } |
2946 | 2961 | ||
2947 | read_lock(&policy_rwlock); | 2962 | read_lock(&policy_rwlock); |
2948 | 2963 | ||
2949 | if (rule->au_seqno < latest_granting) { | 2964 | if (rule->au_seqno < latest_granting) { |
2950 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
2951 | "selinux_audit_rule_match: stale rule\n"); | ||
2952 | match = -ESTALE; | 2965 | match = -ESTALE; |
2953 | goto out; | 2966 | goto out; |
2954 | } | 2967 | } |
2955 | 2968 | ||
2956 | ctxt = sidtab_search(&sidtab, sid); | 2969 | ctxt = sidtab_search(&sidtab, sid); |
2957 | if (!ctxt) { | 2970 | if (unlikely(!ctxt)) { |
2958 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 2971 | WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", |
2959 | "selinux_audit_rule_match: unrecognized SID %d\n", | ||
2960 | sid); | 2972 | sid); |
2961 | match = -ENOENT; | 2973 | match = -ENOENT; |
2962 | goto out; | 2974 | goto out; |