aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-12-27 15:01:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-12-27 15:01:58 -0500
commitfb2a624d5fe8b9206d14bff52da7a368a3a8374c (patch)
tree634271fdc71329712acc0b95c21209b132409bac
parent047ce6d380e8e66cfb6cbc22e873af89dd0c216c (diff)
parentee1a84fdfeedfd7362e9a8a8f15fedc3482ade2d (diff)
Merge tag 'selinux-pr-20181224' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux
Pull selinux patches from Paul Moore: "I already used my best holiday pull request lines in the audit pull request, so this one is going to be a bit more boring, sorry about that. To make up for this, we do have a birthday of sorts to celebrate: SELinux turns 18 years old this December. Perhaps not the most exciting thing in the world for most people, but I think it's safe to say that anyone reading this email doesn't exactly fall into the "most people" category. Back to business and the pull request itself: Ondrej has five patches in this pull request and I lump them into three categories: one patch to always allow submounts (using similar logic to elsewhere in the kernel), one to fix some issues with the SELinux policydb, and the others to cleanup and improve the SELinux sidtab. The other patches from Alexey and Petr and trivial fixes that are adequately described in their respective subject lines. With this last pull request of the year, I want to thank everyone who has contributed patches, testing, and reviews to the SELinux project this year, and the past 18 years. Like any good open source effort, SELinux is only as good as the community which supports it, and I'm very happy that we have the community we do - thank you all!" * tag 'selinux-pr-20181224' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux: selinux: overhaul sidtab to fix bug and improve performance selinux: use separate table for initial SID lookup selinux: make "selinux_policycap_names[]" const char * selinux: always allow mounting submounts selinux: refactor sidtab conversion Documentation: Update SELinux reference policy URL selinux: policydb - fix byte order and alignment issues
-rw-r--r--Documentation/admin-guide/LSM/SELinux.rst2
-rw-r--r--security/selinux/hooks.c2
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/ss/mls.c24
-rw-r--r--security/selinux/ss/mls.h3
-rw-r--r--security/selinux/ss/policydb.c61
-rw-r--r--security/selinux/ss/services.c222
-rw-r--r--security/selinux/ss/services.h2
-rw-r--r--security/selinux/ss/sidtab.c609
-rw-r--r--security/selinux/ss/sidtab.h96
10 files changed, 626 insertions, 397 deletions
diff --git a/Documentation/admin-guide/LSM/SELinux.rst b/Documentation/admin-guide/LSM/SELinux.rst
index f722c9b4173a..520a1c2c6fd2 100644
--- a/Documentation/admin-guide/LSM/SELinux.rst
+++ b/Documentation/admin-guide/LSM/SELinux.rst
@@ -6,7 +6,7 @@ If you want to use SELinux, chances are you will want
6to use the distro-provided policies, or install the 6to use the distro-provided policies, or install the
7latest reference policy release from 7latest reference policy release from
8 8
9 http://oss.tresys.com/projects/refpolicy 9 https://github.com/SELinuxProject/refpolicy
10 10
11However, if you want to install a dummy policy for 11However, if you want to install a dummy policy for
12testing, you can do using ``mdp`` provided under 12testing, you can do using ``mdp`` provided under
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a67459eb62d5..0f27db6d94a9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2934,7 +2934,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
2934 return rc; 2934 return rc;
2935 2935
2936 /* Allow all mounts performed by the kernel */ 2936 /* Allow all mounts performed by the kernel */
2937 if (flags & MS_KERNMOUNT) 2937 if (flags & (MS_KERNMOUNT | MS_SUBMOUNT))
2938 return 0; 2938 return 0;
2939 2939
2940 ad.type = LSM_AUDIT_DATA_DENTRY; 2940 ad.type = LSM_AUDIT_DATA_DENTRY;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 23e762d529fa..ba8eedf42b90 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -81,7 +81,7 @@ enum {
81}; 81};
82#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) 82#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
83 83
84extern char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX]; 84extern const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
85 85
86/* 86/*
87 * type_datum properties 87 * type_datum properties
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index b7efa2296969..5e05f5b902d7 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -440,16 +440,17 @@ int mls_setup_user_range(struct policydb *p,
440 440
441/* 441/*
442 * Convert the MLS fields in the security context 442 * Convert the MLS fields in the security context
443 * structure `c' from the values specified in the 443 * structure `oldc' from the values specified in the
444 * policy `oldp' to the values specified in the policy `newp'. 444 * policy `oldp' to the values specified in the policy `newp',
445 * storing the resulting context in `newc'.
445 */ 446 */
446int mls_convert_context(struct policydb *oldp, 447int mls_convert_context(struct policydb *oldp,
447 struct policydb *newp, 448 struct policydb *newp,
448 struct context *c) 449 struct context *oldc,
450 struct context *newc)
449{ 451{
450 struct level_datum *levdatum; 452 struct level_datum *levdatum;
451 struct cat_datum *catdatum; 453 struct cat_datum *catdatum;
452 struct ebitmap bitmap;
453 struct ebitmap_node *node; 454 struct ebitmap_node *node;
454 int l, i; 455 int l, i;
455 456
@@ -459,28 +460,25 @@ int mls_convert_context(struct policydb *oldp,
459 for (l = 0; l < 2; l++) { 460 for (l = 0; l < 2; l++) {
460 levdatum = hashtab_search(newp->p_levels.table, 461 levdatum = hashtab_search(newp->p_levels.table,
461 sym_name(oldp, SYM_LEVELS, 462 sym_name(oldp, SYM_LEVELS,
462 c->range.level[l].sens - 1)); 463 oldc->range.level[l].sens - 1));
463 464
464 if (!levdatum) 465 if (!levdatum)
465 return -EINVAL; 466 return -EINVAL;
466 c->range.level[l].sens = levdatum->level->sens; 467 newc->range.level[l].sens = levdatum->level->sens;
467 468
468 ebitmap_init(&bitmap); 469 ebitmap_for_each_positive_bit(&oldc->range.level[l].cat,
469 ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) { 470 node, i) {
470 int rc; 471 int rc;
471 472
472 catdatum = hashtab_search(newp->p_cats.table, 473 catdatum = hashtab_search(newp->p_cats.table,
473 sym_name(oldp, SYM_CATS, i)); 474 sym_name(oldp, SYM_CATS, i));
474 if (!catdatum) 475 if (!catdatum)
475 return -EINVAL; 476 return -EINVAL;
476 rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1); 477 rc = ebitmap_set_bit(&newc->range.level[l].cat,
478 catdatum->value - 1, 1);
477 if (rc) 479 if (rc)
478 return rc; 480 return rc;
479
480 cond_resched();
481 } 481 }
482 ebitmap_destroy(&c->range.level[l].cat);
483 c->range.level[l].cat = bitmap;
484 } 482 }
485 483
486 return 0; 484 return 0;
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 67093647576d..7954b1e60b64 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -46,7 +46,8 @@ int mls_range_set(struct context *context, struct mls_range *range);
46 46
47int mls_convert_context(struct policydb *oldp, 47int mls_convert_context(struct policydb *oldp,
48 struct policydb *newp, 48 struct policydb *newp,
49 struct context *context); 49 struct context *oldc,
50 struct context *newc);
50 51
51int mls_compute_sid(struct policydb *p, 52int mls_compute_sid(struct policydb *p,
52 struct context *scontext, 53 struct context *scontext,
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index f4eadd3f7350..a50d625e7946 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -909,13 +909,21 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
909 if (!c->context[0].user) { 909 if (!c->context[0].user) {
910 pr_err("SELinux: SID %s was never defined.\n", 910 pr_err("SELinux: SID %s was never defined.\n",
911 c->u.name); 911 c->u.name);
912 sidtab_destroy(s);
913 goto out;
914 }
915 if (c->sid[0] == SECSID_NULL || c->sid[0] > SECINITSID_NUM) {
916 pr_err("SELinux: Initial SID %s out of range.\n",
917 c->u.name);
918 sidtab_destroy(s);
912 goto out; 919 goto out;
913 } 920 }
914 921
915 rc = sidtab_insert(s, c->sid[0], &c->context[0]); 922 rc = sidtab_set_initial(s, c->sid[0], &c->context[0]);
916 if (rc) { 923 if (rc) {
917 pr_err("SELinux: unable to load initial SID %s.\n", 924 pr_err("SELinux: unable to load initial SID %s.\n",
918 c->u.name); 925 c->u.name);
926 sidtab_destroy(s);
919 goto out; 927 goto out;
920 } 928 }
921 } 929 }
@@ -2108,6 +2116,7 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
2108{ 2116{
2109 int i, j, rc; 2117 int i, j, rc;
2110 u32 nel, len; 2118 u32 nel, len;
2119 __be64 prefixbuf[1];
2111 __le32 buf[3]; 2120 __le32 buf[3];
2112 struct ocontext *l, *c; 2121 struct ocontext *l, *c;
2113 u32 nodebuf[8]; 2122 u32 nodebuf[8];
@@ -2217,21 +2226,30 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
2217 goto out; 2226 goto out;
2218 break; 2227 break;
2219 } 2228 }
2220 case OCON_IBPKEY: 2229 case OCON_IBPKEY: {
2221 rc = next_entry(nodebuf, fp, sizeof(u32) * 4); 2230 u32 pkey_lo, pkey_hi;
2231
2232 rc = next_entry(prefixbuf, fp, sizeof(u64));
2233 if (rc)
2234 goto out;
2235
2236 /* we need to have subnet_prefix in CPU order */
2237 c->u.ibpkey.subnet_prefix = be64_to_cpu(prefixbuf[0]);
2238
2239 rc = next_entry(buf, fp, sizeof(u32) * 2);
2222 if (rc) 2240 if (rc)
2223 goto out; 2241 goto out;
2224 2242
2225 c->u.ibpkey.subnet_prefix = be64_to_cpu(*((__be64 *)nodebuf)); 2243 pkey_lo = le32_to_cpu(buf[0]);
2244 pkey_hi = le32_to_cpu(buf[1]);
2226 2245
2227 if (nodebuf[2] > 0xffff || 2246 if (pkey_lo > U16_MAX || pkey_hi > U16_MAX) {
2228 nodebuf[3] > 0xffff) {
2229 rc = -EINVAL; 2247 rc = -EINVAL;
2230 goto out; 2248 goto out;
2231 } 2249 }
2232 2250
2233 c->u.ibpkey.low_pkey = le32_to_cpu(nodebuf[2]); 2251 c->u.ibpkey.low_pkey = pkey_lo;
2234 c->u.ibpkey.high_pkey = le32_to_cpu(nodebuf[3]); 2252 c->u.ibpkey.high_pkey = pkey_hi;
2235 2253
2236 rc = context_read_and_validate(&c->context[0], 2254 rc = context_read_and_validate(&c->context[0],
2237 p, 2255 p,
@@ -2239,7 +2257,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
2239 if (rc) 2257 if (rc)
2240 goto out; 2258 goto out;
2241 break; 2259 break;
2242 case OCON_IBENDPORT: 2260 }
2261 case OCON_IBENDPORT: {
2262 u32 port;
2263
2243 rc = next_entry(buf, fp, sizeof(u32) * 2); 2264 rc = next_entry(buf, fp, sizeof(u32) * 2);
2244 if (rc) 2265 if (rc)
2245 goto out; 2266 goto out;
@@ -2249,12 +2270,13 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
2249 if (rc) 2270 if (rc)
2250 goto out; 2271 goto out;
2251 2272
2252 if (buf[1] > 0xff || buf[1] == 0) { 2273 port = le32_to_cpu(buf[1]);
2274 if (port > U8_MAX || port == 0) {
2253 rc = -EINVAL; 2275 rc = -EINVAL;
2254 goto out; 2276 goto out;
2255 } 2277 }
2256 2278
2257 c->u.ibendport.port = le32_to_cpu(buf[1]); 2279 c->u.ibendport.port = port;
2258 2280
2259 rc = context_read_and_validate(&c->context[0], 2281 rc = context_read_and_validate(&c->context[0],
2260 p, 2282 p,
@@ -2262,7 +2284,8 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
2262 if (rc) 2284 if (rc)
2263 goto out; 2285 goto out;
2264 break; 2286 break;
2265 } 2287 } /* end case */
2288 } /* end switch */
2266 } 2289 }
2267 } 2290 }
2268 rc = 0; 2291 rc = 0;
@@ -3105,6 +3128,7 @@ static int ocontext_write(struct policydb *p, struct policydb_compat_info *info,
3105{ 3128{
3106 unsigned int i, j, rc; 3129 unsigned int i, j, rc;
3107 size_t nel, len; 3130 size_t nel, len;
3131 __be64 prefixbuf[1];
3108 __le32 buf[3]; 3132 __le32 buf[3];
3109 u32 nodebuf[8]; 3133 u32 nodebuf[8];
3110 struct ocontext *c; 3134 struct ocontext *c;
@@ -3192,12 +3216,17 @@ static int ocontext_write(struct policydb *p, struct policydb_compat_info *info,
3192 return rc; 3216 return rc;
3193 break; 3217 break;
3194 case OCON_IBPKEY: 3218 case OCON_IBPKEY:
3195 *((__be64 *)nodebuf) = cpu_to_be64(c->u.ibpkey.subnet_prefix); 3219 /* subnet_prefix is in CPU order */
3220 prefixbuf[0] = cpu_to_be64(c->u.ibpkey.subnet_prefix);
3196 3221
3197 nodebuf[2] = cpu_to_le32(c->u.ibpkey.low_pkey); 3222 rc = put_entry(prefixbuf, sizeof(u64), 1, fp);
3198 nodebuf[3] = cpu_to_le32(c->u.ibpkey.high_pkey); 3223 if (rc)
3224 return rc;
3199 3225
3200 rc = put_entry(nodebuf, sizeof(u32), 4, fp); 3226 buf[0] = cpu_to_le32(c->u.ibpkey.low_pkey);
3227 buf[1] = cpu_to_le32(c->u.ibpkey.high_pkey);
3228
3229 rc = put_entry(buf, sizeof(u32), 2, fp);
3201 if (rc) 3230 if (rc)
3202 return rc; 3231 return rc;
3203 rc = context_write(p, &c->context[0], fp); 3232 rc = context_write(p, &c->context[0], fp);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 12e414394530..dd44126c8d14 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -71,7 +71,7 @@
71#include "audit.h" 71#include "audit.h"
72 72
73/* Policy capability names */ 73/* Policy capability names */
74char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { 74const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
75 "network_peer_controls", 75 "network_peer_controls",
76 "open_perms", 76 "open_perms",
77 "extended_socket_class", 77 "extended_socket_class",
@@ -776,7 +776,7 @@ static int security_compute_validatetrans(struct selinux_state *state,
776 read_lock(&state->ss->policy_rwlock); 776 read_lock(&state->ss->policy_rwlock);
777 777
778 policydb = &state->ss->policydb; 778 policydb = &state->ss->policydb;
779 sidtab = &state->ss->sidtab; 779 sidtab = state->ss->sidtab;
780 780
781 if (!user) 781 if (!user)
782 tclass = unmap_class(&state->ss->map, orig_tclass); 782 tclass = unmap_class(&state->ss->map, orig_tclass);
@@ -876,7 +876,7 @@ int security_bounded_transition(struct selinux_state *state,
876 read_lock(&state->ss->policy_rwlock); 876 read_lock(&state->ss->policy_rwlock);
877 877
878 policydb = &state->ss->policydb; 878 policydb = &state->ss->policydb;
879 sidtab = &state->ss->sidtab; 879 sidtab = state->ss->sidtab;
880 880
881 rc = -EINVAL; 881 rc = -EINVAL;
882 old_context = sidtab_search(sidtab, old_sid); 882 old_context = sidtab_search(sidtab, old_sid);
@@ -1034,7 +1034,7 @@ void security_compute_xperms_decision(struct selinux_state *state,
1034 goto allow; 1034 goto allow;
1035 1035
1036 policydb = &state->ss->policydb; 1036 policydb = &state->ss->policydb;
1037 sidtab = &state->ss->sidtab; 1037 sidtab = state->ss->sidtab;
1038 1038
1039 scontext = sidtab_search(sidtab, ssid); 1039 scontext = sidtab_search(sidtab, ssid);
1040 if (!scontext) { 1040 if (!scontext) {
@@ -1123,7 +1123,7 @@ void security_compute_av(struct selinux_state *state,
1123 goto allow; 1123 goto allow;
1124 1124
1125 policydb = &state->ss->policydb; 1125 policydb = &state->ss->policydb;
1126 sidtab = &state->ss->sidtab; 1126 sidtab = state->ss->sidtab;
1127 1127
1128 scontext = sidtab_search(sidtab, ssid); 1128 scontext = sidtab_search(sidtab, ssid);
1129 if (!scontext) { 1129 if (!scontext) {
@@ -1177,7 +1177,7 @@ void security_compute_av_user(struct selinux_state *state,
1177 goto allow; 1177 goto allow;
1178 1178
1179 policydb = &state->ss->policydb; 1179 policydb = &state->ss->policydb;
1180 sidtab = &state->ss->sidtab; 1180 sidtab = state->ss->sidtab;
1181 1181
1182 scontext = sidtab_search(sidtab, ssid); 1182 scontext = sidtab_search(sidtab, ssid);
1183 if (!scontext) { 1183 if (!scontext) {
@@ -1315,7 +1315,7 @@ static int security_sid_to_context_core(struct selinux_state *state,
1315 } 1315 }
1316 read_lock(&state->ss->policy_rwlock); 1316 read_lock(&state->ss->policy_rwlock);
1317 policydb = &state->ss->policydb; 1317 policydb = &state->ss->policydb;
1318 sidtab = &state->ss->sidtab; 1318 sidtab = state->ss->sidtab;
1319 if (force) 1319 if (force)
1320 context = sidtab_search_force(sidtab, sid); 1320 context = sidtab_search_force(sidtab, sid);
1321 else 1321 else
@@ -1483,7 +1483,7 @@ static int security_context_to_sid_core(struct selinux_state *state,
1483 } 1483 }
1484 read_lock(&state->ss->policy_rwlock); 1484 read_lock(&state->ss->policy_rwlock);
1485 policydb = &state->ss->policydb; 1485 policydb = &state->ss->policydb;
1486 sidtab = &state->ss->sidtab; 1486 sidtab = state->ss->sidtab;
1487 rc = string_to_context_struct(policydb, sidtab, scontext2, 1487 rc = string_to_context_struct(policydb, sidtab, scontext2,
1488 &context, def_sid); 1488 &context, def_sid);
1489 if (rc == -EINVAL && force) { 1489 if (rc == -EINVAL && force) {
@@ -1668,7 +1668,7 @@ static int security_compute_sid(struct selinux_state *state,
1668 } 1668 }
1669 1669
1670 policydb = &state->ss->policydb; 1670 policydb = &state->ss->policydb;
1671 sidtab = &state->ss->sidtab; 1671 sidtab = state->ss->sidtab;
1672 1672
1673 scontext = sidtab_search(sidtab, ssid); 1673 scontext = sidtab_search(sidtab, ssid);
1674 if (!scontext) { 1674 if (!scontext) {
@@ -1880,19 +1880,6 @@ int security_change_sid(struct selinux_state *state,
1880 out_sid, false); 1880 out_sid, false);
1881} 1881}
1882 1882
1883/* Clone the SID into the new SID table. */
1884static int clone_sid(u32 sid,
1885 struct context *context,
1886 void *arg)
1887{
1888 struct sidtab *s = arg;
1889
1890 if (sid > SECINITSID_NUM)
1891 return sidtab_insert(s, sid, context);
1892 else
1893 return 0;
1894}
1895
1896static inline int convert_context_handle_invalid_context( 1883static inline int convert_context_handle_invalid_context(
1897 struct selinux_state *state, 1884 struct selinux_state *state,
1898 struct context *context) 1885 struct context *context)
@@ -1920,101 +1907,84 @@ struct convert_context_args {
1920 1907
1921/* 1908/*
1922 * Convert the values in the security context 1909 * Convert the values in the security context
1923 * structure `c' from the values specified 1910 * structure `oldc' from the values specified
1924 * in the policy `p->oldp' to the values specified 1911 * in the policy `p->oldp' to the values specified
1925 * in the policy `p->newp'. Verify that the 1912 * in the policy `p->newp', storing the new context
1926 * context is valid under the new policy. 1913 * in `newc'. Verify that the context is valid
1914 * under the new policy.
1927 */ 1915 */
1928static int convert_context(u32 key, 1916static int convert_context(struct context *oldc, struct context *newc, void *p)
1929 struct context *c,
1930 void *p)
1931{ 1917{
1932 struct convert_context_args *args; 1918 struct convert_context_args *args;
1933 struct context oldc;
1934 struct ocontext *oc; 1919 struct ocontext *oc;
1935 struct mls_range *range;
1936 struct role_datum *role; 1920 struct role_datum *role;
1937 struct type_datum *typdatum; 1921 struct type_datum *typdatum;
1938 struct user_datum *usrdatum; 1922 struct user_datum *usrdatum;
1939 char *s; 1923 char *s;
1940 u32 len; 1924 u32 len;
1941 int rc = 0; 1925 int rc;
1942
1943 if (key <= SECINITSID_NUM)
1944 goto out;
1945 1926
1946 args = p; 1927 args = p;
1947 1928
1948 if (c->str) { 1929 if (oldc->str) {
1949 struct context ctx; 1930 s = kstrdup(oldc->str, GFP_KERNEL);
1950
1951 rc = -ENOMEM;
1952 s = kstrdup(c->str, GFP_KERNEL);
1953 if (!s) 1931 if (!s)
1954 goto out; 1932 return -ENOMEM;
1955 1933
1956 rc = string_to_context_struct(args->newp, NULL, s, 1934 rc = string_to_context_struct(args->newp, NULL, s,
1957 &ctx, SECSID_NULL); 1935 newc, SECSID_NULL);
1958 kfree(s); 1936 if (rc == -EINVAL) {
1959 if (!rc) {
1960 pr_info("SELinux: Context %s became valid (mapped).\n",
1961 c->str);
1962 /* Replace string with mapped representation. */
1963 kfree(c->str);
1964 memcpy(c, &ctx, sizeof(*c));
1965 goto out;
1966 } else if (rc == -EINVAL) {
1967 /* Retain string representation for later mapping. */ 1937 /* Retain string representation for later mapping. */
1968 rc = 0; 1938 context_init(newc);
1969 goto out; 1939 newc->str = s;
1970 } else { 1940 newc->len = oldc->len;
1941 return 0;
1942 }
1943 kfree(s);
1944 if (rc) {
1971 /* Other error condition, e.g. ENOMEM. */ 1945 /* Other error condition, e.g. ENOMEM. */
1972 pr_err("SELinux: Unable to map context %s, rc = %d.\n", 1946 pr_err("SELinux: Unable to map context %s, rc = %d.\n",
1973 c->str, -rc); 1947 oldc->str, -rc);
1974 goto out; 1948 return rc;
1975 } 1949 }
1950 pr_info("SELinux: Context %s became valid (mapped).\n",
1951 oldc->str);
1952 return 0;
1976 } 1953 }
1977 1954
1978 rc = context_cpy(&oldc, c); 1955 context_init(newc);
1979 if (rc)
1980 goto out;
1981 1956
1982 /* Convert the user. */ 1957 /* Convert the user. */
1983 rc = -EINVAL; 1958 rc = -EINVAL;
1984 usrdatum = hashtab_search(args->newp->p_users.table, 1959 usrdatum = hashtab_search(args->newp->p_users.table,
1985 sym_name(args->oldp, SYM_USERS, c->user - 1)); 1960 sym_name(args->oldp,
1961 SYM_USERS, oldc->user - 1));
1986 if (!usrdatum) 1962 if (!usrdatum)
1987 goto bad; 1963 goto bad;
1988 c->user = usrdatum->value; 1964 newc->user = usrdatum->value;
1989 1965
1990 /* Convert the role. */ 1966 /* Convert the role. */
1991 rc = -EINVAL; 1967 rc = -EINVAL;
1992 role = hashtab_search(args->newp->p_roles.table, 1968 role = hashtab_search(args->newp->p_roles.table,
1993 sym_name(args->oldp, SYM_ROLES, c->role - 1)); 1969 sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
1994 if (!role) 1970 if (!role)
1995 goto bad; 1971 goto bad;
1996 c->role = role->value; 1972 newc->role = role->value;
1997 1973
1998 /* Convert the type. */ 1974 /* Convert the type. */
1999 rc = -EINVAL; 1975 rc = -EINVAL;
2000 typdatum = hashtab_search(args->newp->p_types.table, 1976 typdatum = hashtab_search(args->newp->p_types.table,
2001 sym_name(args->oldp, SYM_TYPES, c->type - 1)); 1977 sym_name(args->oldp,
1978 SYM_TYPES, oldc->type - 1));
2002 if (!typdatum) 1979 if (!typdatum)
2003 goto bad; 1980 goto bad;
2004 c->type = typdatum->value; 1981 newc->type = typdatum->value;
2005 1982
2006 /* Convert the MLS fields if dealing with MLS policies */ 1983 /* Convert the MLS fields if dealing with MLS policies */
2007 if (args->oldp->mls_enabled && args->newp->mls_enabled) { 1984 if (args->oldp->mls_enabled && args->newp->mls_enabled) {
2008 rc = mls_convert_context(args->oldp, args->newp, c); 1985 rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
2009 if (rc) 1986 if (rc)
2010 goto bad; 1987 goto bad;
2011 } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) {
2012 /*
2013 * Switching between MLS and non-MLS policy:
2014 * free any storage used by the MLS fields in the
2015 * context for all existing entries in the sidtab.
2016 */
2017 mls_context_destroy(c);
2018 } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { 1988 } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
2019 /* 1989 /*
2020 * Switching between non-MLS and MLS policy: 1990 * Switching between non-MLS and MLS policy:
@@ -2032,38 +2002,30 @@ static int convert_context(u32 key,
2032 " the initial SIDs list\n"); 2002 " the initial SIDs list\n");
2033 goto bad; 2003 goto bad;
2034 } 2004 }
2035 range = &oc->context[0].range; 2005 rc = mls_range_set(newc, &oc->context[0].range);
2036 rc = mls_range_set(c, range);
2037 if (rc) 2006 if (rc)
2038 goto bad; 2007 goto bad;
2039 } 2008 }
2040 2009
2041 /* Check the validity of the new context. */ 2010 /* Check the validity of the new context. */
2042 if (!policydb_context_isvalid(args->newp, c)) { 2011 if (!policydb_context_isvalid(args->newp, newc)) {
2043 rc = convert_context_handle_invalid_context(args->state, 2012 rc = convert_context_handle_invalid_context(args->state, oldc);
2044 &oldc);
2045 if (rc) 2013 if (rc)
2046 goto bad; 2014 goto bad;
2047 } 2015 }
2048 2016
2049 context_destroy(&oldc); 2017 return 0;
2050
2051 rc = 0;
2052out:
2053 return rc;
2054bad: 2018bad:
2055 /* Map old representation to string and save it. */ 2019 /* Map old representation to string and save it. */
2056 rc = context_struct_to_string(args->oldp, &oldc, &s, &len); 2020 rc = context_struct_to_string(args->oldp, oldc, &s, &len);
2057 if (rc) 2021 if (rc)
2058 return rc; 2022 return rc;
2059 context_destroy(&oldc); 2023 context_destroy(newc);
2060 context_destroy(c); 2024 newc->str = s;
2061 c->str = s; 2025 newc->len = len;
2062 c->len = len;
2063 pr_info("SELinux: Context %s became invalid (unmapped).\n", 2026 pr_info("SELinux: Context %s became invalid (unmapped).\n",
2064 c->str); 2027 newc->str);
2065 rc = 0; 2028 return 0;
2066 goto out;
2067} 2029}
2068 2030
2069static void security_load_policycaps(struct selinux_state *state) 2031static void security_load_policycaps(struct selinux_state *state)
@@ -2103,11 +2065,11 @@ static int security_preserve_bools(struct selinux_state *state,
2103int security_load_policy(struct selinux_state *state, void *data, size_t len) 2065int security_load_policy(struct selinux_state *state, void *data, size_t len)
2104{ 2066{
2105 struct policydb *policydb; 2067 struct policydb *policydb;
2106 struct sidtab *sidtab; 2068 struct sidtab *oldsidtab, *newsidtab;
2107 struct policydb *oldpolicydb, *newpolicydb; 2069 struct policydb *oldpolicydb, *newpolicydb;
2108 struct sidtab oldsidtab, newsidtab;
2109 struct selinux_mapping *oldmapping; 2070 struct selinux_mapping *oldmapping;
2110 struct selinux_map newmap; 2071 struct selinux_map newmap;
2072 struct sidtab_convert_params convert_params;
2111 struct convert_context_args args; 2073 struct convert_context_args args;
2112 u32 seqno; 2074 u32 seqno;
2113 int rc = 0; 2075 int rc = 0;
@@ -2121,27 +2083,37 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2121 newpolicydb = oldpolicydb + 1; 2083 newpolicydb = oldpolicydb + 1;
2122 2084
2123 policydb = &state->ss->policydb; 2085 policydb = &state->ss->policydb;
2124 sidtab = &state->ss->sidtab; 2086
2087 newsidtab = kmalloc(sizeof(*newsidtab), GFP_KERNEL);
2088 if (!newsidtab) {
2089 rc = -ENOMEM;
2090 goto out;
2091 }
2125 2092
2126 if (!state->initialized) { 2093 if (!state->initialized) {
2127 rc = policydb_read(policydb, fp); 2094 rc = policydb_read(policydb, fp);
2128 if (rc) 2095 if (rc) {
2096 kfree(newsidtab);
2129 goto out; 2097 goto out;
2098 }
2130 2099
2131 policydb->len = len; 2100 policydb->len = len;
2132 rc = selinux_set_mapping(policydb, secclass_map, 2101 rc = selinux_set_mapping(policydb, secclass_map,
2133 &state->ss->map); 2102 &state->ss->map);
2134 if (rc) { 2103 if (rc) {
2104 kfree(newsidtab);
2135 policydb_destroy(policydb); 2105 policydb_destroy(policydb);
2136 goto out; 2106 goto out;
2137 } 2107 }
2138 2108
2139 rc = policydb_load_isids(policydb, sidtab); 2109 rc = policydb_load_isids(policydb, newsidtab);
2140 if (rc) { 2110 if (rc) {
2111 kfree(newsidtab);
2141 policydb_destroy(policydb); 2112 policydb_destroy(policydb);
2142 goto out; 2113 goto out;
2143 } 2114 }
2144 2115
2116 state->ss->sidtab = newsidtab;
2145 security_load_policycaps(state); 2117 security_load_policycaps(state);
2146 state->initialized = 1; 2118 state->initialized = 1;
2147 seqno = ++state->ss->latest_granting; 2119 seqno = ++state->ss->latest_granting;
@@ -2154,13 +2126,11 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2154 goto out; 2126 goto out;
2155 } 2127 }
2156 2128
2157#if 0
2158 sidtab_hash_eval(sidtab, "sids");
2159#endif
2160
2161 rc = policydb_read(newpolicydb, fp); 2129 rc = policydb_read(newpolicydb, fp);
2162 if (rc) 2130 if (rc) {
2131 kfree(newsidtab);
2163 goto out; 2132 goto out;
2133 }
2164 2134
2165 newpolicydb->len = len; 2135 newpolicydb->len = len;
2166 /* If switching between different policy types, log MLS status */ 2136 /* If switching between different policy types, log MLS status */
@@ -2169,10 +2139,11 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2169 else if (!policydb->mls_enabled && newpolicydb->mls_enabled) 2139 else if (!policydb->mls_enabled && newpolicydb->mls_enabled)
2170 pr_info("SELinux: Enabling MLS support...\n"); 2140 pr_info("SELinux: Enabling MLS support...\n");
2171 2141
2172 rc = policydb_load_isids(newpolicydb, &newsidtab); 2142 rc = policydb_load_isids(newpolicydb, newsidtab);
2173 if (rc) { 2143 if (rc) {
2174 pr_err("SELinux: unable to load the initial SIDs\n"); 2144 pr_err("SELinux: unable to load the initial SIDs\n");
2175 policydb_destroy(newpolicydb); 2145 policydb_destroy(newpolicydb);
2146 kfree(newsidtab);
2176 goto out; 2147 goto out;
2177 } 2148 }
2178 2149
@@ -2186,12 +2157,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2186 goto err; 2157 goto err;
2187 } 2158 }
2188 2159
2189 /* Clone the SID table. */ 2160 oldsidtab = state->ss->sidtab;
2190 sidtab_shutdown(sidtab);
2191
2192 rc = sidtab_map(sidtab, clone_sid, &newsidtab);
2193 if (rc)
2194 goto err;
2195 2161
2196 /* 2162 /*
2197 * Convert the internal representations of contexts 2163 * Convert the internal representations of contexts
@@ -2200,7 +2166,12 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2200 args.state = state; 2166 args.state = state;
2201 args.oldp = policydb; 2167 args.oldp = policydb;
2202 args.newp = newpolicydb; 2168 args.newp = newpolicydb;
2203 rc = sidtab_map(&newsidtab, convert_context, &args); 2169
2170 convert_params.func = convert_context;
2171 convert_params.args = &args;
2172 convert_params.target = newsidtab;
2173
2174 rc = sidtab_convert(oldsidtab, &convert_params);
2204 if (rc) { 2175 if (rc) {
2205 pr_err("SELinux: unable to convert the internal" 2176 pr_err("SELinux: unable to convert the internal"
2206 " representation of contexts in the new SID" 2177 " representation of contexts in the new SID"
@@ -2210,12 +2181,11 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2210 2181
2211 /* Save the old policydb and SID table to free later. */ 2182 /* Save the old policydb and SID table to free later. */
2212 memcpy(oldpolicydb, policydb, sizeof(*policydb)); 2183 memcpy(oldpolicydb, policydb, sizeof(*policydb));
2213 sidtab_set(&oldsidtab, sidtab);
2214 2184
2215 /* Install the new policydb and SID table. */ 2185 /* Install the new policydb and SID table. */
2216 write_lock_irq(&state->ss->policy_rwlock); 2186 write_lock_irq(&state->ss->policy_rwlock);
2217 memcpy(policydb, newpolicydb, sizeof(*policydb)); 2187 memcpy(policydb, newpolicydb, sizeof(*policydb));
2218 sidtab_set(sidtab, &newsidtab); 2188 state->ss->sidtab = newsidtab;
2219 security_load_policycaps(state); 2189 security_load_policycaps(state);
2220 oldmapping = state->ss->map.mapping; 2190 oldmapping = state->ss->map.mapping;
2221 state->ss->map.mapping = newmap.mapping; 2191 state->ss->map.mapping = newmap.mapping;
@@ -2225,7 +2195,8 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2225 2195
2226 /* Free the old policydb and SID table. */ 2196 /* Free the old policydb and SID table. */
2227 policydb_destroy(oldpolicydb); 2197 policydb_destroy(oldpolicydb);
2228 sidtab_destroy(&oldsidtab); 2198 sidtab_destroy(oldsidtab);
2199 kfree(oldsidtab);
2229 kfree(oldmapping); 2200 kfree(oldmapping);
2230 2201
2231 avc_ss_reset(state->avc, seqno); 2202 avc_ss_reset(state->avc, seqno);
@@ -2239,7 +2210,8 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2239 2210
2240err: 2211err:
2241 kfree(newmap.mapping); 2212 kfree(newmap.mapping);
2242 sidtab_destroy(&newsidtab); 2213 sidtab_destroy(newsidtab);
2214 kfree(newsidtab);
2243 policydb_destroy(newpolicydb); 2215 policydb_destroy(newpolicydb);
2244 2216
2245out: 2217out:
@@ -2276,7 +2248,7 @@ int security_port_sid(struct selinux_state *state,
2276 read_lock(&state->ss->policy_rwlock); 2248 read_lock(&state->ss->policy_rwlock);
2277 2249
2278 policydb = &state->ss->policydb; 2250 policydb = &state->ss->policydb;
2279 sidtab = &state->ss->sidtab; 2251 sidtab = state->ss->sidtab;
2280 2252
2281 c = policydb->ocontexts[OCON_PORT]; 2253 c = policydb->ocontexts[OCON_PORT];
2282 while (c) { 2254 while (c) {
@@ -2322,7 +2294,7 @@ int security_ib_pkey_sid(struct selinux_state *state,
2322 read_lock(&state->ss->policy_rwlock); 2294 read_lock(&state->ss->policy_rwlock);
2323 2295
2324 policydb = &state->ss->policydb; 2296 policydb = &state->ss->policydb;
2325 sidtab = &state->ss->sidtab; 2297 sidtab = state->ss->sidtab;
2326 2298
2327 c = policydb->ocontexts[OCON_IBPKEY]; 2299 c = policydb->ocontexts[OCON_IBPKEY];
2328 while (c) { 2300 while (c) {
@@ -2368,7 +2340,7 @@ int security_ib_endport_sid(struct selinux_state *state,
2368 read_lock(&state->ss->policy_rwlock); 2340 read_lock(&state->ss->policy_rwlock);
2369 2341
2370 policydb = &state->ss->policydb; 2342 policydb = &state->ss->policydb;
2371 sidtab = &state->ss->sidtab; 2343 sidtab = state->ss->sidtab;
2372 2344
2373 c = policydb->ocontexts[OCON_IBENDPORT]; 2345 c = policydb->ocontexts[OCON_IBENDPORT];
2374 while (c) { 2346 while (c) {
@@ -2414,7 +2386,7 @@ int security_netif_sid(struct selinux_state *state,
2414 read_lock(&state->ss->policy_rwlock); 2386 read_lock(&state->ss->policy_rwlock);
2415 2387
2416 policydb = &state->ss->policydb; 2388 policydb = &state->ss->policydb;
2417 sidtab = &state->ss->sidtab; 2389 sidtab = state->ss->sidtab;
2418 2390
2419 c = policydb->ocontexts[OCON_NETIF]; 2391 c = policydb->ocontexts[OCON_NETIF];
2420 while (c) { 2392 while (c) {
@@ -2479,7 +2451,7 @@ int security_node_sid(struct selinux_state *state,
2479 read_lock(&state->ss->policy_rwlock); 2451 read_lock(&state->ss->policy_rwlock);
2480 2452
2481 policydb = &state->ss->policydb; 2453 policydb = &state->ss->policydb;
2482 sidtab = &state->ss->sidtab; 2454 sidtab = state->ss->sidtab;
2483 2455
2484 switch (domain) { 2456 switch (domain) {
2485 case AF_INET: { 2457 case AF_INET: {
@@ -2579,7 +2551,7 @@ int security_get_user_sids(struct selinux_state *state,
2579 read_lock(&state->ss->policy_rwlock); 2551 read_lock(&state->ss->policy_rwlock);
2580 2552
2581 policydb = &state->ss->policydb; 2553 policydb = &state->ss->policydb;
2582 sidtab = &state->ss->sidtab; 2554 sidtab = state->ss->sidtab;
2583 2555
2584 context_init(&usercon); 2556 context_init(&usercon);
2585 2557
@@ -2681,7 +2653,7 @@ static inline int __security_genfs_sid(struct selinux_state *state,
2681 u32 *sid) 2653 u32 *sid)
2682{ 2654{
2683 struct policydb *policydb = &state->ss->policydb; 2655 struct policydb *policydb = &state->ss->policydb;
2684 struct sidtab *sidtab = &state->ss->sidtab; 2656 struct sidtab *sidtab = state->ss->sidtab;
2685 int len; 2657 int len;
2686 u16 sclass; 2658 u16 sclass;
2687 struct genfs *genfs; 2659 struct genfs *genfs;
@@ -2767,7 +2739,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
2767 read_lock(&state->ss->policy_rwlock); 2739 read_lock(&state->ss->policy_rwlock);
2768 2740
2769 policydb = &state->ss->policydb; 2741 policydb = &state->ss->policydb;
2770 sidtab = &state->ss->sidtab; 2742 sidtab = state->ss->sidtab;
2771 2743
2772 c = policydb->ocontexts[OCON_FSUSE]; 2744 c = policydb->ocontexts[OCON_FSUSE];
2773 while (c) { 2745 while (c) {
@@ -2973,7 +2945,7 @@ int security_sid_mls_copy(struct selinux_state *state,
2973 u32 sid, u32 mls_sid, u32 *new_sid) 2945 u32 sid, u32 mls_sid, u32 *new_sid)
2974{ 2946{
2975 struct policydb *policydb = &state->ss->policydb; 2947 struct policydb *policydb = &state->ss->policydb;
2976 struct sidtab *sidtab = &state->ss->sidtab; 2948 struct sidtab *sidtab = state->ss->sidtab;
2977 struct context *context1; 2949 struct context *context1;
2978 struct context *context2; 2950 struct context *context2;
2979 struct context newcon; 2951 struct context newcon;
@@ -3064,7 +3036,7 @@ int security_net_peersid_resolve(struct selinux_state *state,
3064 u32 *peer_sid) 3036 u32 *peer_sid)
3065{ 3037{
3066 struct policydb *policydb = &state->ss->policydb; 3038 struct policydb *policydb = &state->ss->policydb;
3067 struct sidtab *sidtab = &state->ss->sidtab; 3039 struct sidtab *sidtab = state->ss->sidtab;
3068 int rc; 3040 int rc;
3069 struct context *nlbl_ctx; 3041 struct context *nlbl_ctx;
3070 struct context *xfrm_ctx; 3042 struct context *xfrm_ctx;
@@ -3425,7 +3397,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
3425 goto out; 3397 goto out;
3426 } 3398 }
3427 3399
3428 ctxt = sidtab_search(&state->ss->sidtab, sid); 3400 ctxt = sidtab_search(state->ss->sidtab, sid);
3429 if (unlikely(!ctxt)) { 3401 if (unlikely(!ctxt)) {
3430 WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", 3402 WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
3431 sid); 3403 sid);
@@ -3588,7 +3560,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
3588 u32 *sid) 3560 u32 *sid)
3589{ 3561{
3590 struct policydb *policydb = &state->ss->policydb; 3562 struct policydb *policydb = &state->ss->policydb;
3591 struct sidtab *sidtab = &state->ss->sidtab; 3563 struct sidtab *sidtab = state->ss->sidtab;
3592 int rc; 3564 int rc;
3593 struct context *ctx; 3565 struct context *ctx;
3594 struct context ctx_new; 3566 struct context ctx_new;
@@ -3666,7 +3638,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state,
3666 read_lock(&state->ss->policy_rwlock); 3638 read_lock(&state->ss->policy_rwlock);
3667 3639
3668 rc = -ENOENT; 3640 rc = -ENOENT;
3669 ctx = sidtab_search(&state->ss->sidtab, sid); 3641 ctx = sidtab_search(state->ss->sidtab, sid);
3670 if (ctx == NULL) 3642 if (ctx == NULL)
3671 goto out; 3643 goto out;
3672 3644
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
index 24c7bdcc8075..9a36de860368 100644
--- a/security/selinux/ss/services.h
+++ b/security/selinux/ss/services.h
@@ -24,7 +24,7 @@ struct selinux_map {
24}; 24};
25 25
26struct selinux_ss { 26struct selinux_ss {
27 struct sidtab sidtab; 27 struct sidtab *sidtab;
28 struct policydb policydb; 28 struct policydb policydb;
29 rwlock_t policy_rwlock; 29 rwlock_t policy_rwlock;
30 u32 latest_granting; 30 u32 latest_granting;
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index fd75a12fa8fc..e63a90ff2728 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -2,108 +2,164 @@
2/* 2/*
3 * Implementation of the SID table type. 3 * Implementation of the SID table type.
4 * 4 *
5 * Author : Stephen Smalley, <sds@tycho.nsa.gov> 5 * Original author: Stephen Smalley, <sds@tycho.nsa.gov>
6 * Author: Ondrej Mosnacek, <omosnacek@gmail.com>
7 *
8 * Copyright (C) 2018 Red Hat, Inc.
6 */ 9 */
10#include <linux/errno.h>
7#include <linux/kernel.h> 11#include <linux/kernel.h>
8#include <linux/slab.h> 12#include <linux/slab.h>
13#include <linux/sched.h>
9#include <linux/spinlock.h> 14#include <linux/spinlock.h>
10#include <linux/errno.h> 15#include <linux/atomic.h>
11#include "flask.h" 16#include "flask.h"
12#include "security.h" 17#include "security.h"
13#include "sidtab.h" 18#include "sidtab.h"
14 19
15#define SIDTAB_HASH(sid) \
16(sid & SIDTAB_HASH_MASK)
17
18int sidtab_init(struct sidtab *s) 20int sidtab_init(struct sidtab *s)
19{ 21{
20 int i; 22 u32 i;
21 23
22 s->htable = kmalloc_array(SIDTAB_SIZE, sizeof(*s->htable), GFP_ATOMIC); 24 memset(s->roots, 0, sizeof(s->roots));
23 if (!s->htable) 25
24 return -ENOMEM; 26 for (i = 0; i < SIDTAB_RCACHE_SIZE; i++)
25 for (i = 0; i < SIDTAB_SIZE; i++) 27 atomic_set(&s->rcache[i], -1);
26 s->htable[i] = NULL; 28
27 s->nel = 0; 29 for (i = 0; i < SECINITSID_NUM; i++)
28 s->next_sid = 1; 30 s->isids[i].set = 0;
29 s->shutdown = 0; 31
32 atomic_set(&s->count, 0);
33
34 s->convert = NULL;
35
30 spin_lock_init(&s->lock); 36 spin_lock_init(&s->lock);
31 return 0; 37 return 0;
32} 38}
33 39
34int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) 40int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context)
35{ 41{
36 int hvalue; 42 struct sidtab_isid_entry *entry;
37 struct sidtab_node *prev, *cur, *newnode; 43 int rc;
38
39 if (!s)
40 return -ENOMEM;
41
42 hvalue = SIDTAB_HASH(sid);
43 prev = NULL;
44 cur = s->htable[hvalue];
45 while (cur && sid > cur->sid) {
46 prev = cur;
47 cur = cur->next;
48 }
49 44
50 if (cur && sid == cur->sid) 45 if (sid == 0 || sid > SECINITSID_NUM)
51 return -EEXIST; 46 return -EINVAL;
52 47
53 newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC); 48 entry = &s->isids[sid - 1];
54 if (!newnode)
55 return -ENOMEM;
56 49
57 newnode->sid = sid; 50 rc = context_cpy(&entry->context, context);
58 if (context_cpy(&newnode->context, context)) { 51 if (rc)
59 kfree(newnode); 52 return rc;
60 return -ENOMEM;
61 }
62 53
63 if (prev) { 54 entry->set = 1;
64 newnode->next = prev->next; 55 return 0;
65 wmb(); 56}
66 prev->next = newnode; 57
67 } else { 58static u32 sidtab_level_from_count(u32 count)
68 newnode->next = s->htable[hvalue]; 59{
69 wmb(); 60 u32 capacity = SIDTAB_LEAF_ENTRIES;
70 s->htable[hvalue] = newnode; 61 u32 level = 0;
62
63 while (count > capacity) {
64 capacity <<= SIDTAB_INNER_SHIFT;
65 ++level;
71 } 66 }
67 return level;
68}
72 69
73 s->nel++; 70static int sidtab_alloc_roots(struct sidtab *s, u32 level)
74 if (sid >= s->next_sid) 71{
75 s->next_sid = sid + 1; 72 u32 l;
73
74 if (!s->roots[0].ptr_leaf) {
75 s->roots[0].ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
76 GFP_ATOMIC);
77 if (!s->roots[0].ptr_leaf)
78 return -ENOMEM;
79 }
80 for (l = 1; l <= level; ++l)
81 if (!s->roots[l].ptr_inner) {
82 s->roots[l].ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
83 GFP_ATOMIC);
84 if (!s->roots[l].ptr_inner)
85 return -ENOMEM;
86 s->roots[l].ptr_inner->entries[0] = s->roots[l - 1];
87 }
76 return 0; 88 return 0;
77} 89}
78 90
79static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) 91static struct context *sidtab_do_lookup(struct sidtab *s, u32 index, int alloc)
80{ 92{
81 int hvalue; 93 union sidtab_entry_inner *entry;
82 struct sidtab_node *cur; 94 u32 level, capacity_shift, leaf_index = index / SIDTAB_LEAF_ENTRIES;
95
96 /* find the level of the subtree we need */
97 level = sidtab_level_from_count(index + 1);
98 capacity_shift = level * SIDTAB_INNER_SHIFT;
83 99
84 if (!s) 100 /* allocate roots if needed */
101 if (alloc && sidtab_alloc_roots(s, level) != 0)
85 return NULL; 102 return NULL;
86 103
87 hvalue = SIDTAB_HASH(sid); 104 /* lookup inside the subtree */
88 cur = s->htable[hvalue]; 105 entry = &s->roots[level];
89 while (cur && sid > cur->sid) 106 while (level != 0) {
90 cur = cur->next; 107 capacity_shift -= SIDTAB_INNER_SHIFT;
91 108 --level;
92 if (force && cur && sid == cur->sid && cur->context.len) 109
93 return &cur->context; 110 entry = &entry->ptr_inner->entries[leaf_index >> capacity_shift];
94 111 leaf_index &= ((u32)1 << capacity_shift) - 1;
95 if (!cur || sid != cur->sid || cur->context.len) { 112
96 /* Remap invalid SIDs to the unlabeled SID. */ 113 if (!entry->ptr_inner) {
97 sid = SECINITSID_UNLABELED; 114 if (alloc)
98 hvalue = SIDTAB_HASH(sid); 115 entry->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
99 cur = s->htable[hvalue]; 116 GFP_ATOMIC);
100 while (cur && sid > cur->sid) 117 if (!entry->ptr_inner)
101 cur = cur->next; 118 return NULL;
102 if (!cur || sid != cur->sid) 119 }
120 }
121 if (!entry->ptr_leaf) {
122 if (alloc)
123 entry->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
124 GFP_ATOMIC);
125 if (!entry->ptr_leaf)
103 return NULL; 126 return NULL;
104 } 127 }
128 return &entry->ptr_leaf->entries[index % SIDTAB_LEAF_ENTRIES].context;
129}
130
131static struct context *sidtab_lookup(struct sidtab *s, u32 index)
132{
133 u32 count = (u32)atomic_read(&s->count);
134
135 if (index >= count)
136 return NULL;
137
138 /* read entries after reading count */
139 smp_rmb();
140
141 return sidtab_do_lookup(s, index, 0);
142}
143
144static struct context *sidtab_lookup_initial(struct sidtab *s, u32 sid)
145{
146 return s->isids[sid - 1].set ? &s->isids[sid - 1].context : NULL;
147}
148
149static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
150{
151 struct context *context;
152
153 if (sid != 0) {
154 if (sid > SECINITSID_NUM)
155 context = sidtab_lookup(s, sid - (SECINITSID_NUM + 1));
156 else
157 context = sidtab_lookup_initial(s, sid);
158 if (context && (!context->len || force))
159 return context;
160 }
105 161
106 return &cur->context; 162 return sidtab_lookup_initial(s, SECINITSID_UNLABELED);
107} 163}
108 164
109struct context *sidtab_search(struct sidtab *s, u32 sid) 165struct context *sidtab_search(struct sidtab *s, u32 sid)
@@ -116,191 +172,324 @@ struct context *sidtab_search_force(struct sidtab *s, u32 sid)
116 return sidtab_search_core(s, sid, 1); 172 return sidtab_search_core(s, sid, 1);
117} 173}
118 174
119int sidtab_map(struct sidtab *s, 175static int sidtab_find_context(union sidtab_entry_inner entry,
120 int (*apply) (u32 sid, 176 u32 *pos, u32 count, u32 level,
121 struct context *context, 177 struct context *context, u32 *index)
122 void *args),
123 void *args)
124{ 178{
125 int i, rc = 0; 179 int rc;
126 struct sidtab_node *cur; 180 u32 i;
127 181
128 if (!s) 182 if (level != 0) {
129 goto out; 183 struct sidtab_node_inner *node = entry.ptr_inner;
184
185 i = 0;
186 while (i < SIDTAB_INNER_ENTRIES && *pos < count) {
187 rc = sidtab_find_context(node->entries[i],
188 pos, count, level - 1,
189 context, index);
190 if (rc == 0)
191 return 0;
192 i++;
193 }
194 } else {
195 struct sidtab_node_leaf *node = entry.ptr_leaf;
130 196
131 for (i = 0; i < SIDTAB_SIZE; i++) { 197 i = 0;
132 cur = s->htable[i]; 198 while (i < SIDTAB_LEAF_ENTRIES && *pos < count) {
133 while (cur) { 199 if (context_cmp(&node->entries[i].context, context)) {
134 rc = apply(cur->sid, &cur->context, args); 200 *index = *pos;
135 if (rc) 201 return 0;
136 goto out; 202 }
137 cur = cur->next; 203 (*pos)++;
204 i++;
138 } 205 }
139 } 206 }
140out: 207 return -ENOENT;
141 return rc;
142} 208}
143 209
144static void sidtab_update_cache(struct sidtab *s, struct sidtab_node *n, int loc) 210static void sidtab_rcache_update(struct sidtab *s, u32 index, u32 pos)
145{ 211{
146 BUG_ON(loc >= SIDTAB_CACHE_LEN); 212 while (pos > 0) {
147 213 atomic_set(&s->rcache[pos], atomic_read(&s->rcache[pos - 1]));
148 while (loc > 0) { 214 --pos;
149 s->cache[loc] = s->cache[loc - 1];
150 loc--;
151 } 215 }
152 s->cache[0] = n; 216 atomic_set(&s->rcache[0], (int)index);
153} 217}
154 218
155static inline u32 sidtab_search_context(struct sidtab *s, 219static void sidtab_rcache_push(struct sidtab *s, u32 index)
156 struct context *context)
157{ 220{
158 int i; 221 sidtab_rcache_update(s, index, SIDTAB_RCACHE_SIZE - 1);
159 struct sidtab_node *cur;
160
161 for (i = 0; i < SIDTAB_SIZE; i++) {
162 cur = s->htable[i];
163 while (cur) {
164 if (context_cmp(&cur->context, context)) {
165 sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1);
166 return cur->sid;
167 }
168 cur = cur->next;
169 }
170 }
171 return 0;
172} 222}
173 223
174static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context) 224static int sidtab_rcache_search(struct sidtab *s, struct context *context,
225 u32 *index)
175{ 226{
176 int i; 227 u32 i;
177 struct sidtab_node *node;
178 228
179 for (i = 0; i < SIDTAB_CACHE_LEN; i++) { 229 for (i = 0; i < SIDTAB_RCACHE_SIZE; i++) {
180 node = s->cache[i]; 230 int v = atomic_read(&s->rcache[i]);
181 if (unlikely(!node)) 231
232 if (v < 0)
233 continue;
234
235 if (context_cmp(sidtab_do_lookup(s, (u32)v, 0), context)) {
236 sidtab_rcache_update(s, (u32)v, i);
237 *index = (u32)v;
182 return 0; 238 return 0;
183 if (context_cmp(&node->context, context)) {
184 sidtab_update_cache(s, node, i);
185 return node->sid;
186 } 239 }
187 } 240 }
188 return 0; 241 return -ENOENT;
189} 242}
190 243
191int sidtab_context_to_sid(struct sidtab *s, 244static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
192 struct context *context, 245 u32 *index)
193 u32 *out_sid)
194{ 246{
195 u32 sid;
196 int ret = 0;
197 unsigned long flags; 247 unsigned long flags;
248 u32 count = (u32)atomic_read(&s->count);
249 u32 count_locked, level, pos;
250 struct sidtab_convert_params *convert;
251 struct context *dst, *dst_convert;
252 int rc;
253
254 rc = sidtab_rcache_search(s, context, index);
255 if (rc == 0)
256 return 0;
257
258 level = sidtab_level_from_count(count);
259
260 /* read entries after reading count */
261 smp_rmb();
262
263 pos = 0;
264 rc = sidtab_find_context(s->roots[level], &pos, count, level,
265 context, index);
266 if (rc == 0) {
267 sidtab_rcache_push(s, *index);
268 return 0;
269 }
198 270
199 *out_sid = SECSID_NULL; 271 /* lock-free search failed: lock, re-search, and insert if not found */
272 spin_lock_irqsave(&s->lock, flags);
200 273
201 sid = sidtab_search_cache(s, context); 274 convert = s->convert;
202 if (!sid) 275 count_locked = (u32)atomic_read(&s->count);
203 sid = sidtab_search_context(s, context); 276 level = sidtab_level_from_count(count_locked);
204 if (!sid) { 277
205 spin_lock_irqsave(&s->lock, flags); 278 /* if count has changed before we acquired the lock, then catch up */
206 /* Rescan now that we hold the lock. */ 279 while (count < count_locked) {
207 sid = sidtab_search_context(s, context); 280 if (context_cmp(sidtab_do_lookup(s, count, 0), context)) {
208 if (sid) 281 sidtab_rcache_push(s, count);
209 goto unlock_out; 282 *index = count;
210 /* No SID exists for the context. Allocate a new one. */ 283 rc = 0;
211 if (s->next_sid == UINT_MAX || s->shutdown) { 284 goto out_unlock;
212 ret = -ENOMEM;
213 goto unlock_out;
214 } 285 }
215 sid = s->next_sid++; 286 ++count;
216 if (context->len)
217 pr_info("SELinux: Context %s is not valid (left unmapped).\n",
218 context->str);
219 ret = sidtab_insert(s, sid, context);
220 if (ret)
221 s->next_sid--;
222unlock_out:
223 spin_unlock_irqrestore(&s->lock, flags);
224 } 287 }
225 288
226 if (ret) 289 /* insert context into new entry */
227 return ret; 290 rc = -ENOMEM;
291 dst = sidtab_do_lookup(s, count, 1);
292 if (!dst)
293 goto out_unlock;
294
295 rc = context_cpy(dst, context);
296 if (rc)
297 goto out_unlock;
298
299 /*
300 * if we are building a new sidtab, we need to convert the context
301 * and insert it there as well
302 */
303 if (convert) {
304 rc = -ENOMEM;
305 dst_convert = sidtab_do_lookup(convert->target, count, 1);
306 if (!dst_convert) {
307 context_destroy(dst);
308 goto out_unlock;
309 }
228 310
229 *out_sid = sid; 311 rc = convert->func(context, dst_convert, convert->args);
230 return 0; 312 if (rc) {
313 context_destroy(dst);
314 goto out_unlock;
315 }
316
317 /* at this point we know the insert won't fail */
318 atomic_set(&convert->target->count, count + 1);
319 }
320
321 if (context->len)
322 pr_info("SELinux: Context %s is not valid (left unmapped).\n",
323 context->str);
324
325 sidtab_rcache_push(s, count);
326 *index = count;
327
328 /* write entries before writing new count */
329 smp_wmb();
330
331 atomic_set(&s->count, count + 1);
332
333 rc = 0;
334out_unlock:
335 spin_unlock_irqrestore(&s->lock, flags);
336 return rc;
231} 337}
232 338
233void sidtab_hash_eval(struct sidtab *h, char *tag) 339int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
234{ 340{
235 int i, chain_len, slots_used, max_chain_len; 341 int rc;
236 struct sidtab_node *cur; 342 u32 i;
237 343
238 slots_used = 0; 344 for (i = 0; i < SECINITSID_NUM; i++) {
239 max_chain_len = 0; 345 struct sidtab_isid_entry *entry = &s->isids[i];
240 for (i = 0; i < SIDTAB_SIZE; i++) {
241 cur = h->htable[i];
242 if (cur) {
243 slots_used++;
244 chain_len = 0;
245 while (cur) {
246 chain_len++;
247 cur = cur->next;
248 }
249 346
250 if (chain_len > max_chain_len) 347 if (entry->set && context_cmp(context, &entry->context)) {
251 max_chain_len = chain_len; 348 *sid = i + 1;
349 return 0;
252 } 350 }
253 } 351 }
254 352
255 pr_debug("%s: %d entries and %d/%d buckets used, longest " 353 rc = sidtab_reverse_lookup(s, context, sid);
256 "chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE, 354 if (rc)
257 max_chain_len); 355 return rc;
356 *sid += SECINITSID_NUM + 1;
357 return 0;
258} 358}
259 359
260void sidtab_destroy(struct sidtab *s) 360static int sidtab_convert_tree(union sidtab_entry_inner *edst,
361 union sidtab_entry_inner *esrc,
362 u32 *pos, u32 count, u32 level,
363 struct sidtab_convert_params *convert)
261{ 364{
262 int i; 365 int rc;
263 struct sidtab_node *cur, *temp; 366 u32 i;
264 367
265 if (!s) 368 if (level != 0) {
266 return; 369 if (!edst->ptr_inner) {
267 370 edst->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
268 for (i = 0; i < SIDTAB_SIZE; i++) { 371 GFP_KERNEL);
269 cur = s->htable[i]; 372 if (!edst->ptr_inner)
270 while (cur) { 373 return -ENOMEM;
271 temp = cur; 374 }
272 cur = cur->next; 375 i = 0;
273 context_destroy(&temp->context); 376 while (i < SIDTAB_INNER_ENTRIES && *pos < count) {
274 kfree(temp); 377 rc = sidtab_convert_tree(&edst->ptr_inner->entries[i],
378 &esrc->ptr_inner->entries[i],
379 pos, count, level - 1,
380 convert);
381 if (rc)
382 return rc;
383 i++;
384 }
385 } else {
386 if (!edst->ptr_leaf) {
387 edst->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
388 GFP_KERNEL);
389 if (!edst->ptr_leaf)
390 return -ENOMEM;
391 }
392 i = 0;
393 while (i < SIDTAB_LEAF_ENTRIES && *pos < count) {
394 rc = convert->func(&esrc->ptr_leaf->entries[i].context,
395 &edst->ptr_leaf->entries[i].context,
396 convert->args);
397 if (rc)
398 return rc;
399 (*pos)++;
400 i++;
275 } 401 }
276 s->htable[i] = NULL; 402 cond_resched();
277 } 403 }
278 kfree(s->htable); 404 return 0;
279 s->htable = NULL;
280 s->nel = 0;
281 s->next_sid = 1;
282} 405}
283 406
284void sidtab_set(struct sidtab *dst, struct sidtab *src) 407int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params)
285{ 408{
286 unsigned long flags; 409 unsigned long flags;
287 int i; 410 u32 count, level, pos;
288 411 int rc;
289 spin_lock_irqsave(&src->lock, flags); 412
290 dst->htable = src->htable; 413 spin_lock_irqsave(&s->lock, flags);
291 dst->nel = src->nel; 414
292 dst->next_sid = src->next_sid; 415 /* concurrent policy loads are not allowed */
293 dst->shutdown = 0; 416 if (s->convert) {
294 for (i = 0; i < SIDTAB_CACHE_LEN; i++) 417 spin_unlock_irqrestore(&s->lock, flags);
295 dst->cache[i] = NULL; 418 return -EBUSY;
296 spin_unlock_irqrestore(&src->lock, flags); 419 }
420
421 count = (u32)atomic_read(&s->count);
422 level = sidtab_level_from_count(count);
423
424 /* allocate last leaf in the new sidtab (to avoid race with
425 * live convert)
426 */
427 rc = sidtab_do_lookup(params->target, count - 1, 1) ? 0 : -ENOMEM;
428 if (rc) {
429 spin_unlock_irqrestore(&s->lock, flags);
430 return rc;
431 }
432
433 /* set count in case no new entries are added during conversion */
434 atomic_set(&params->target->count, count);
435
436 /* enable live convert of new entries */
437 s->convert = params;
438
439 /* we can safely do the rest of the conversion outside the lock */
440 spin_unlock_irqrestore(&s->lock, flags);
441
442 pr_info("SELinux: Converting %u SID table entries...\n", count);
443
444 /* convert all entries not covered by live convert */
445 pos = 0;
446 rc = sidtab_convert_tree(&params->target->roots[level],
447 &s->roots[level], &pos, count, level, params);
448 if (rc) {
449 /* we need to keep the old table - disable live convert */
450 spin_lock_irqsave(&s->lock, flags);
451 s->convert = NULL;
452 spin_unlock_irqrestore(&s->lock, flags);
453 }
454 return rc;
297} 455}
298 456
299void sidtab_shutdown(struct sidtab *s) 457static void sidtab_destroy_tree(union sidtab_entry_inner entry, u32 level)
300{ 458{
301 unsigned long flags; 459 u32 i;
302 460
303 spin_lock_irqsave(&s->lock, flags); 461 if (level != 0) {
304 s->shutdown = 1; 462 struct sidtab_node_inner *node = entry.ptr_inner;
305 spin_unlock_irqrestore(&s->lock, flags); 463
464 if (!node)
465 return;
466
467 for (i = 0; i < SIDTAB_INNER_ENTRIES; i++)
468 sidtab_destroy_tree(node->entries[i], level - 1);
469 kfree(node);
470 } else {
471 struct sidtab_node_leaf *node = entry.ptr_leaf;
472
473 if (!node)
474 return;
475
476 for (i = 0; i < SIDTAB_LEAF_ENTRIES; i++)
477 context_destroy(&node->entries[i].context);
478 kfree(node);
479 }
480}
481
482void sidtab_destroy(struct sidtab *s)
483{
484 u32 i, level;
485
486 for (i = 0; i < SECINITSID_NUM; i++)
487 if (s->isids[i].set)
488 context_destroy(&s->isids[i].context);
489
490 level = SIDTAB_MAX_LEVEL;
491 while (level && !s->roots[level].ptr_inner)
492 --level;
493
494 sidtab_destroy_tree(s->roots[level], level);
306} 495}
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index a1a1d2617b6f..bbd5c0d1f3bd 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -1,56 +1,96 @@
1/* SPDX-License-Identifier: GPL-2.0 */ 1/* SPDX-License-Identifier: GPL-2.0 */
2/* 2/*
3 * A security identifier table (sidtab) is a hash table 3 * A security identifier table (sidtab) is a lookup table
4 * of security context structures indexed by SID value. 4 * of security context structures indexed by SID value.
5 * 5 *
6 * Author : Stephen Smalley, <sds@tycho.nsa.gov> 6 * Original author: Stephen Smalley, <sds@tycho.nsa.gov>
7 * Author: Ondrej Mosnacek, <omosnacek@gmail.com>
8 *
9 * Copyright (C) 2018 Red Hat, Inc.
7 */ 10 */
8#ifndef _SS_SIDTAB_H_ 11#ifndef _SS_SIDTAB_H_
9#define _SS_SIDTAB_H_ 12#define _SS_SIDTAB_H_
10 13
14#include <linux/spinlock_types.h>
15#include <linux/log2.h>
16
11#include "context.h" 17#include "context.h"
12 18
13struct sidtab_node { 19struct sidtab_entry_leaf {
14 u32 sid; /* security identifier */ 20 struct context context;
15 struct context context; /* security context structure */ 21};
16 struct sidtab_node *next; 22
23struct sidtab_node_inner;
24struct sidtab_node_leaf;
25
26union sidtab_entry_inner {
27 struct sidtab_node_inner *ptr_inner;
28 struct sidtab_node_leaf *ptr_leaf;
29};
30
31/* align node size to page boundary */
32#define SIDTAB_NODE_ALLOC_SHIFT PAGE_SHIFT
33#define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE
34
35#define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size) - 1) + 1))
36
37#define SIDTAB_INNER_SHIFT \
38 (SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner)))
39#define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT)
40#define SIDTAB_LEAF_ENTRIES \
41 (SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry_leaf))
42
43#define SIDTAB_MAX_BITS 31 /* limited to INT_MAX due to atomic_t range */
44#define SIDTAB_MAX (((u32)1 << SIDTAB_MAX_BITS) - 1)
45/* ensure enough tree levels for SIDTAB_MAX entries */
46#define SIDTAB_MAX_LEVEL \
47 DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \
48 SIDTAB_INNER_SHIFT)
49
50struct sidtab_node_leaf {
51 struct sidtab_entry_leaf entries[SIDTAB_LEAF_ENTRIES];
17}; 52};
18 53
19#define SIDTAB_HASH_BITS 7 54struct sidtab_node_inner {
20#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) 55 union sidtab_entry_inner entries[SIDTAB_INNER_ENTRIES];
21#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1) 56};
22 57
23#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS 58struct sidtab_isid_entry {
59 int set;
60 struct context context;
61};
62
63struct sidtab_convert_params {
64 int (*func)(struct context *oldc, struct context *newc, void *args);
65 void *args;
66 struct sidtab *target;
67};
68
69#define SIDTAB_RCACHE_SIZE 3
24 70
25struct sidtab { 71struct sidtab {
26 struct sidtab_node **htable; 72 union sidtab_entry_inner roots[SIDTAB_MAX_LEVEL + 1];
27 unsigned int nel; /* number of elements */ 73 atomic_t count;
28 unsigned int next_sid; /* next SID to allocate */ 74 struct sidtab_convert_params *convert;
29 unsigned char shutdown;
30#define SIDTAB_CACHE_LEN 3
31 struct sidtab_node *cache[SIDTAB_CACHE_LEN];
32 spinlock_t lock; 75 spinlock_t lock;
76
77 /* reverse lookup cache */
78 atomic_t rcache[SIDTAB_RCACHE_SIZE];
79
80 /* index == SID - 1 (no entry for SECSID_NULL) */
81 struct sidtab_isid_entry isids[SECINITSID_NUM];
33}; 82};
34 83
35int sidtab_init(struct sidtab *s); 84int sidtab_init(struct sidtab *s);
36int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); 85int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context);
37struct context *sidtab_search(struct sidtab *s, u32 sid); 86struct context *sidtab_search(struct sidtab *s, u32 sid);
38struct context *sidtab_search_force(struct sidtab *s, u32 sid); 87struct context *sidtab_search_force(struct sidtab *s, u32 sid);
39 88
40int sidtab_map(struct sidtab *s, 89int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params);
41 int (*apply) (u32 sid,
42 struct context *context,
43 void *args),
44 void *args);
45 90
46int sidtab_context_to_sid(struct sidtab *s, 91int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
47 struct context *context,
48 u32 *sid);
49 92
50void sidtab_hash_eval(struct sidtab *h, char *tag);
51void sidtab_destroy(struct sidtab *s); 93void sidtab_destroy(struct sidtab *s);
52void sidtab_set(struct sidtab *dst, struct sidtab *src);
53void sidtab_shutdown(struct sidtab *s);
54 94
55#endif /* _SS_SIDTAB_H_ */ 95#endif /* _SS_SIDTAB_H_ */
56 96