aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Mosnacek <omosnace@redhat.com>2018-11-30 10:24:07 -0500
committerPaul Moore <paul@paul-moore.com>2018-12-05 15:36:12 -0500
commit24ed7fdae669feda4c5e0dadba2467c4c0d297d3 (patch)
treea26c76596744dab9c762d6d5915e9dc67b20e906
parent89f5bebcf0401dac470756869587a50dd72ff7b5 (diff)
selinux: use separate table for initial SID lookup
This moves handling of initial SIDs into a separate table. Note that the SIDs stored in the main table are now shifted by SECINITSID_NUM and converted to/from the actual SIDs transparently by helper functions. This change doesn't make much sense on its own, but it simplifies further sidtab overhaul in a succeeding patch. Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com> Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov> [PM: fixed some checkpatch warnings on line length, whitespace] Signed-off-by: Paul Moore <paul@paul-moore.com>
-rw-r--r--security/selinux/ss/policydb.c10
-rw-r--r--security/selinux/ss/services.c88
-rw-r--r--security/selinux/ss/services.h2
-rw-r--r--security/selinux/ss/sidtab.c168
-rw-r--r--security/selinux/ss/sidtab.h15
5 files changed, 173 insertions, 110 deletions
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index b63ef865ce1e..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 }
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 0458f4cecff8..4ff4b0edbf6b 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -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) {
@@ -1925,10 +1925,7 @@ static int convert_context(u32 key,
1925 struct user_datum *usrdatum; 1925 struct user_datum *usrdatum;
1926 char *s; 1926 char *s;
1927 u32 len; 1927 u32 len;
1928 int rc = 0; 1928 int rc;
1929
1930 if (key <= SECINITSID_NUM)
1931 goto out;
1932 1929
1933 args = p; 1930 args = p;
1934 1931
@@ -2090,9 +2087,8 @@ static int security_preserve_bools(struct selinux_state *state,
2090int security_load_policy(struct selinux_state *state, void *data, size_t len) 2087int security_load_policy(struct selinux_state *state, void *data, size_t len)
2091{ 2088{
2092 struct policydb *policydb; 2089 struct policydb *policydb;
2093 struct sidtab *sidtab; 2090 struct sidtab *oldsidtab, *newsidtab;
2094 struct policydb *oldpolicydb, *newpolicydb; 2091 struct policydb *oldpolicydb, *newpolicydb;
2095 struct sidtab oldsidtab, newsidtab;
2096 struct selinux_mapping *oldmapping; 2092 struct selinux_mapping *oldmapping;
2097 struct selinux_map newmap; 2093 struct selinux_map newmap;
2098 struct convert_context_args args; 2094 struct convert_context_args args;
@@ -2108,27 +2104,37 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2108 newpolicydb = oldpolicydb + 1; 2104 newpolicydb = oldpolicydb + 1;
2109 2105
2110 policydb = &state->ss->policydb; 2106 policydb = &state->ss->policydb;
2111 sidtab = &state->ss->sidtab; 2107
2108 newsidtab = kmalloc(sizeof(*newsidtab), GFP_KERNEL);
2109 if (!newsidtab) {
2110 rc = -ENOMEM;
2111 goto out;
2112 }
2112 2113
2113 if (!state->initialized) { 2114 if (!state->initialized) {
2114 rc = policydb_read(policydb, fp); 2115 rc = policydb_read(policydb, fp);
2115 if (rc) 2116 if (rc) {
2117 kfree(newsidtab);
2116 goto out; 2118 goto out;
2119 }
2117 2120
2118 policydb->len = len; 2121 policydb->len = len;
2119 rc = selinux_set_mapping(policydb, secclass_map, 2122 rc = selinux_set_mapping(policydb, secclass_map,
2120 &state->ss->map); 2123 &state->ss->map);
2121 if (rc) { 2124 if (rc) {
2125 kfree(newsidtab);
2122 policydb_destroy(policydb); 2126 policydb_destroy(policydb);
2123 goto out; 2127 goto out;
2124 } 2128 }
2125 2129
2126 rc = policydb_load_isids(policydb, sidtab); 2130 rc = policydb_load_isids(policydb, newsidtab);
2127 if (rc) { 2131 if (rc) {
2132 kfree(newsidtab);
2128 policydb_destroy(policydb); 2133 policydb_destroy(policydb);
2129 goto out; 2134 goto out;
2130 } 2135 }
2131 2136
2137 state->ss->sidtab = newsidtab;
2132 security_load_policycaps(state); 2138 security_load_policycaps(state);
2133 state->initialized = 1; 2139 state->initialized = 1;
2134 seqno = ++state->ss->latest_granting; 2140 seqno = ++state->ss->latest_granting;
@@ -2141,13 +2147,17 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2141 goto out; 2147 goto out;
2142 } 2148 }
2143 2149
2150 oldsidtab = state->ss->sidtab;
2151
2144#if 0 2152#if 0
2145 sidtab_hash_eval(sidtab, "sids"); 2153 sidtab_hash_eval(oldsidtab, "sids");
2146#endif 2154#endif
2147 2155
2148 rc = policydb_read(newpolicydb, fp); 2156 rc = policydb_read(newpolicydb, fp);
2149 if (rc) 2157 if (rc) {
2158 kfree(newsidtab);
2150 goto out; 2159 goto out;
2160 }
2151 2161
2152 newpolicydb->len = len; 2162 newpolicydb->len = len;
2153 /* If switching between different policy types, log MLS status */ 2163 /* If switching between different policy types, log MLS status */
@@ -2156,10 +2166,11 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2156 else if (!policydb->mls_enabled && newpolicydb->mls_enabled) 2166 else if (!policydb->mls_enabled && newpolicydb->mls_enabled)
2157 pr_info("SELinux: Enabling MLS support...\n"); 2167 pr_info("SELinux: Enabling MLS support...\n");
2158 2168
2159 rc = policydb_load_isids(newpolicydb, &newsidtab); 2169 rc = policydb_load_isids(newpolicydb, newsidtab);
2160 if (rc) { 2170 if (rc) {
2161 pr_err("SELinux: unable to load the initial SIDs\n"); 2171 pr_err("SELinux: unable to load the initial SIDs\n");
2162 policydb_destroy(newpolicydb); 2172 policydb_destroy(newpolicydb);
2173 kfree(newsidtab);
2163 goto out; 2174 goto out;
2164 } 2175 }
2165 2176
@@ -2180,7 +2191,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2180 args.state = state; 2191 args.state = state;
2181 args.oldp = policydb; 2192 args.oldp = policydb;
2182 args.newp = newpolicydb; 2193 args.newp = newpolicydb;
2183 rc = sidtab_convert(sidtab, &newsidtab, convert_context, &args); 2194 rc = sidtab_convert(oldsidtab, newsidtab, convert_context, &args);
2184 if (rc) { 2195 if (rc) {
2185 pr_err("SELinux: unable to convert the internal" 2196 pr_err("SELinux: unable to convert the internal"
2186 " representation of contexts in the new SID" 2197 " representation of contexts in the new SID"
@@ -2190,12 +2201,11 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2190 2201
2191 /* Save the old policydb and SID table to free later. */ 2202 /* Save the old policydb and SID table to free later. */
2192 memcpy(oldpolicydb, policydb, sizeof(*policydb)); 2203 memcpy(oldpolicydb, policydb, sizeof(*policydb));
2193 sidtab_set(&oldsidtab, sidtab);
2194 2204
2195 /* Install the new policydb and SID table. */ 2205 /* Install the new policydb and SID table. */
2196 write_lock_irq(&state->ss->policy_rwlock); 2206 write_lock_irq(&state->ss->policy_rwlock);
2197 memcpy(policydb, newpolicydb, sizeof(*policydb)); 2207 memcpy(policydb, newpolicydb, sizeof(*policydb));
2198 sidtab_set(sidtab, &newsidtab); 2208 state->ss->sidtab = newsidtab;
2199 security_load_policycaps(state); 2209 security_load_policycaps(state);
2200 oldmapping = state->ss->map.mapping; 2210 oldmapping = state->ss->map.mapping;
2201 state->ss->map.mapping = newmap.mapping; 2211 state->ss->map.mapping = newmap.mapping;
@@ -2205,7 +2215,8 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2205 2215
2206 /* Free the old policydb and SID table. */ 2216 /* Free the old policydb and SID table. */
2207 policydb_destroy(oldpolicydb); 2217 policydb_destroy(oldpolicydb);
2208 sidtab_destroy(&oldsidtab); 2218 sidtab_destroy(oldsidtab);
2219 kfree(oldsidtab);
2209 kfree(oldmapping); 2220 kfree(oldmapping);
2210 2221
2211 avc_ss_reset(state->avc, seqno); 2222 avc_ss_reset(state->avc, seqno);
@@ -2219,7 +2230,8 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
2219 2230
2220err: 2231err:
2221 kfree(newmap.mapping); 2232 kfree(newmap.mapping);
2222 sidtab_destroy(&newsidtab); 2233 sidtab_destroy(newsidtab);
2234 kfree(newsidtab);
2223 policydb_destroy(newpolicydb); 2235 policydb_destroy(newpolicydb);
2224 2236
2225out: 2237out:
@@ -2256,7 +2268,7 @@ int security_port_sid(struct selinux_state *state,
2256 read_lock(&state->ss->policy_rwlock); 2268 read_lock(&state->ss->policy_rwlock);
2257 2269
2258 policydb = &state->ss->policydb; 2270 policydb = &state->ss->policydb;
2259 sidtab = &state->ss->sidtab; 2271 sidtab = state->ss->sidtab;
2260 2272
2261 c = policydb->ocontexts[OCON_PORT]; 2273 c = policydb->ocontexts[OCON_PORT];
2262 while (c) { 2274 while (c) {
@@ -2302,7 +2314,7 @@ int security_ib_pkey_sid(struct selinux_state *state,
2302 read_lock(&state->ss->policy_rwlock); 2314 read_lock(&state->ss->policy_rwlock);
2303 2315
2304 policydb = &state->ss->policydb; 2316 policydb = &state->ss->policydb;
2305 sidtab = &state->ss->sidtab; 2317 sidtab = state->ss->sidtab;
2306 2318
2307 c = policydb->ocontexts[OCON_IBPKEY]; 2319 c = policydb->ocontexts[OCON_IBPKEY];
2308 while (c) { 2320 while (c) {
@@ -2348,7 +2360,7 @@ int security_ib_endport_sid(struct selinux_state *state,
2348 read_lock(&state->ss->policy_rwlock); 2360 read_lock(&state->ss->policy_rwlock);
2349 2361
2350 policydb = &state->ss->policydb; 2362 policydb = &state->ss->policydb;
2351 sidtab = &state->ss->sidtab; 2363 sidtab = state->ss->sidtab;
2352 2364
2353 c = policydb->ocontexts[OCON_IBENDPORT]; 2365 c = policydb->ocontexts[OCON_IBENDPORT];
2354 while (c) { 2366 while (c) {
@@ -2394,7 +2406,7 @@ int security_netif_sid(struct selinux_state *state,
2394 read_lock(&state->ss->policy_rwlock); 2406 read_lock(&state->ss->policy_rwlock);
2395 2407
2396 policydb = &state->ss->policydb; 2408 policydb = &state->ss->policydb;
2397 sidtab = &state->ss->sidtab; 2409 sidtab = state->ss->sidtab;
2398 2410
2399 c = policydb->ocontexts[OCON_NETIF]; 2411 c = policydb->ocontexts[OCON_NETIF];
2400 while (c) { 2412 while (c) {
@@ -2459,7 +2471,7 @@ int security_node_sid(struct selinux_state *state,
2459 read_lock(&state->ss->policy_rwlock); 2471 read_lock(&state->ss->policy_rwlock);
2460 2472
2461 policydb = &state->ss->policydb; 2473 policydb = &state->ss->policydb;
2462 sidtab = &state->ss->sidtab; 2474 sidtab = state->ss->sidtab;
2463 2475
2464 switch (domain) { 2476 switch (domain) {
2465 case AF_INET: { 2477 case AF_INET: {
@@ -2559,7 +2571,7 @@ int security_get_user_sids(struct selinux_state *state,
2559 read_lock(&state->ss->policy_rwlock); 2571 read_lock(&state->ss->policy_rwlock);
2560 2572
2561 policydb = &state->ss->policydb; 2573 policydb = &state->ss->policydb;
2562 sidtab = &state->ss->sidtab; 2574 sidtab = state->ss->sidtab;
2563 2575
2564 context_init(&usercon); 2576 context_init(&usercon);
2565 2577
@@ -2661,7 +2673,7 @@ static inline int __security_genfs_sid(struct selinux_state *state,
2661 u32 *sid) 2673 u32 *sid)
2662{ 2674{
2663 struct policydb *policydb = &state->ss->policydb; 2675 struct policydb *policydb = &state->ss->policydb;
2664 struct sidtab *sidtab = &state->ss->sidtab; 2676 struct sidtab *sidtab = state->ss->sidtab;
2665 int len; 2677 int len;
2666 u16 sclass; 2678 u16 sclass;
2667 struct genfs *genfs; 2679 struct genfs *genfs;
@@ -2747,7 +2759,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
2747 read_lock(&state->ss->policy_rwlock); 2759 read_lock(&state->ss->policy_rwlock);
2748 2760
2749 policydb = &state->ss->policydb; 2761 policydb = &state->ss->policydb;
2750 sidtab = &state->ss->sidtab; 2762 sidtab = state->ss->sidtab;
2751 2763
2752 c = policydb->ocontexts[OCON_FSUSE]; 2764 c = policydb->ocontexts[OCON_FSUSE];
2753 while (c) { 2765 while (c) {
@@ -2953,7 +2965,7 @@ int security_sid_mls_copy(struct selinux_state *state,
2953 u32 sid, u32 mls_sid, u32 *new_sid) 2965 u32 sid, u32 mls_sid, u32 *new_sid)
2954{ 2966{
2955 struct policydb *policydb = &state->ss->policydb; 2967 struct policydb *policydb = &state->ss->policydb;
2956 struct sidtab *sidtab = &state->ss->sidtab; 2968 struct sidtab *sidtab = state->ss->sidtab;
2957 struct context *context1; 2969 struct context *context1;
2958 struct context *context2; 2970 struct context *context2;
2959 struct context newcon; 2971 struct context newcon;
@@ -3044,7 +3056,7 @@ int security_net_peersid_resolve(struct selinux_state *state,
3044 u32 *peer_sid) 3056 u32 *peer_sid)
3045{ 3057{
3046 struct policydb *policydb = &state->ss->policydb; 3058 struct policydb *policydb = &state->ss->policydb;
3047 struct sidtab *sidtab = &state->ss->sidtab; 3059 struct sidtab *sidtab = state->ss->sidtab;
3048 int rc; 3060 int rc;
3049 struct context *nlbl_ctx; 3061 struct context *nlbl_ctx;
3050 struct context *xfrm_ctx; 3062 struct context *xfrm_ctx;
@@ -3405,7 +3417,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
3405 goto out; 3417 goto out;
3406 } 3418 }
3407 3419
3408 ctxt = sidtab_search(&state->ss->sidtab, sid); 3420 ctxt = sidtab_search(state->ss->sidtab, sid);
3409 if (unlikely(!ctxt)) { 3421 if (unlikely(!ctxt)) {
3410 WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", 3422 WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
3411 sid); 3423 sid);
@@ -3568,7 +3580,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
3568 u32 *sid) 3580 u32 *sid)
3569{ 3581{
3570 struct policydb *policydb = &state->ss->policydb; 3582 struct policydb *policydb = &state->ss->policydb;
3571 struct sidtab *sidtab = &state->ss->sidtab; 3583 struct sidtab *sidtab = state->ss->sidtab;
3572 int rc; 3584 int rc;
3573 struct context *ctx; 3585 struct context *ctx;
3574 struct context ctx_new; 3586 struct context ctx_new;
@@ -3646,7 +3658,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state,
3646 read_lock(&state->ss->policy_rwlock); 3658 read_lock(&state->ss->policy_rwlock);
3647 3659
3648 rc = -ENOENT; 3660 rc = -ENOENT;
3649 ctx = sidtab_search(&state->ss->sidtab, sid); 3661 ctx = sidtab_search(state->ss->sidtab, sid);
3650 if (ctx == NULL) 3662 if (ctx == NULL)
3651 goto out; 3663 goto out;
3652 3664
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 ccc0ea230df4..e44e7cec630c 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -22,16 +22,24 @@ int sidtab_init(struct sidtab *s)
22 s->htable = kmalloc_array(SIDTAB_SIZE, sizeof(*s->htable), GFP_ATOMIC); 22 s->htable = kmalloc_array(SIDTAB_SIZE, sizeof(*s->htable), GFP_ATOMIC);
23 if (!s->htable) 23 if (!s->htable)
24 return -ENOMEM; 24 return -ENOMEM;
25
26 for (i = 0; i < SECINITSID_NUM; i++)
27 s->isids[i].set = 0;
28
25 for (i = 0; i < SIDTAB_SIZE; i++) 29 for (i = 0; i < SIDTAB_SIZE; i++)
26 s->htable[i] = NULL; 30 s->htable[i] = NULL;
31
32 for (i = 0; i < SIDTAB_CACHE_LEN; i++)
33 s->cache[i] = NULL;
34
27 s->nel = 0; 35 s->nel = 0;
28 s->next_sid = 1; 36 s->next_sid = 0;
29 s->shutdown = 0; 37 s->shutdown = 0;
30 spin_lock_init(&s->lock); 38 spin_lock_init(&s->lock);
31 return 0; 39 return 0;
32} 40}
33 41
34int sidtab_insert(struct sidtab *s, u32 sid, struct context *context) 42static int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
35{ 43{
36 int hvalue; 44 int hvalue;
37 struct sidtab_node *prev, *cur, *newnode; 45 struct sidtab_node *prev, *cur, *newnode;
@@ -76,34 +84,62 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
76 return 0; 84 return 0;
77} 85}
78 86
79static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force) 87int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context)
88{
89 struct sidtab_isid_entry *entry;
90 int rc;
91
92 if (sid == 0 || sid > SECINITSID_NUM)
93 return -EINVAL;
94
95 entry = &s->isids[sid - 1];
96
97 rc = context_cpy(&entry->context, context);
98 if (rc)
99 return rc;
100
101 entry->set = 1;
102 return 0;
103}
104
105static struct context *sidtab_lookup(struct sidtab *s, u32 sid)
80{ 106{
81 int hvalue; 107 int hvalue;
82 struct sidtab_node *cur; 108 struct sidtab_node *cur;
83 109
84 if (!s)
85 return NULL;
86
87 hvalue = SIDTAB_HASH(sid); 110 hvalue = SIDTAB_HASH(sid);
88 cur = s->htable[hvalue]; 111 cur = s->htable[hvalue];
89 while (cur && sid > cur->sid) 112 while (cur && sid > cur->sid)
90 cur = cur->next; 113 cur = cur->next;
91 114
92 if (force && cur && sid == cur->sid && cur->context.len) 115 if (!cur || sid != cur->sid)
93 return &cur->context; 116 return NULL;
94 117
95 if (!cur || sid != cur->sid || cur->context.len) { 118 return &cur->context;
96 /* Remap invalid SIDs to the unlabeled SID. */ 119}
97 sid = SECINITSID_UNLABELED; 120
98 hvalue = SIDTAB_HASH(sid); 121static struct context *sidtab_lookup_initial(struct sidtab *s, u32 sid)
99 cur = s->htable[hvalue]; 122{
100 while (cur && sid > cur->sid) 123 return s->isids[sid - 1].set ? &s->isids[sid - 1].context : NULL;
101 cur = cur->next; 124}
102 if (!cur || sid != cur->sid) 125
103 return NULL; 126static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
127{
128 struct context *context;
129
130 if (!s)
131 return NULL;
132
133 if (sid != 0) {
134 if (sid > SECINITSID_NUM)
135 context = sidtab_lookup(s, sid - (SECINITSID_NUM + 1));
136 else
137 context = sidtab_lookup_initial(s, sid);
138 if (context && (!context->len || force))
139 return context;
104 } 140 }
105 141
106 return &cur->context; 142 return sidtab_lookup_initial(s, SECINITSID_UNLABELED);
107} 143}
108 144
109struct context *sidtab_search(struct sidtab *s, u32 sid) 145struct context *sidtab_search(struct sidtab *s, u32 sid)
@@ -145,11 +181,7 @@ out:
145static int clone_sid(u32 sid, struct context *context, void *arg) 181static int clone_sid(u32 sid, struct context *context, void *arg)
146{ 182{
147 struct sidtab *s = arg; 183 struct sidtab *s = arg;
148 184 return sidtab_insert(s, sid, context);
149 if (sid > SECINITSID_NUM)
150 return sidtab_insert(s, sid, context);
151 else
152 return 0;
153} 185}
154 186
155int sidtab_convert(struct sidtab *s, struct sidtab *news, 187int sidtab_convert(struct sidtab *s, struct sidtab *news,
@@ -183,8 +215,8 @@ static void sidtab_update_cache(struct sidtab *s, struct sidtab_node *n, int loc
183 s->cache[0] = n; 215 s->cache[0] = n;
184} 216}
185 217
186static inline u32 sidtab_search_context(struct sidtab *s, 218static inline int sidtab_search_context(struct sidtab *s,
187 struct context *context) 219 struct context *context, u32 *sid)
188{ 220{
189 int i; 221 int i;
190 struct sidtab_node *cur; 222 struct sidtab_node *cur;
@@ -194,15 +226,17 @@ static inline u32 sidtab_search_context(struct sidtab *s,
194 while (cur) { 226 while (cur) {
195 if (context_cmp(&cur->context, context)) { 227 if (context_cmp(&cur->context, context)) {
196 sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1); 228 sidtab_update_cache(s, cur, SIDTAB_CACHE_LEN - 1);
197 return cur->sid; 229 *sid = cur->sid;
230 return 0;
198 } 231 }
199 cur = cur->next; 232 cur = cur->next;
200 } 233 }
201 } 234 }
202 return 0; 235 return -ENOENT;
203} 236}
204 237
205static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context) 238static inline int sidtab_search_cache(struct sidtab *s, struct context *context,
239 u32 *sid)
206{ 240{
207 int i; 241 int i;
208 struct sidtab_node *node; 242 struct sidtab_node *node;
@@ -210,54 +244,69 @@ static inline u32 sidtab_search_cache(struct sidtab *s, struct context *context)
210 for (i = 0; i < SIDTAB_CACHE_LEN; i++) { 244 for (i = 0; i < SIDTAB_CACHE_LEN; i++) {
211 node = s->cache[i]; 245 node = s->cache[i];
212 if (unlikely(!node)) 246 if (unlikely(!node))
213 return 0; 247 return -ENOENT;
214 if (context_cmp(&node->context, context)) { 248 if (context_cmp(&node->context, context)) {
215 sidtab_update_cache(s, node, i); 249 sidtab_update_cache(s, node, i);
216 return node->sid; 250 *sid = node->sid;
251 return 0;
217 } 252 }
218 } 253 }
219 return 0; 254 return -ENOENT;
220} 255}
221 256
222int sidtab_context_to_sid(struct sidtab *s, 257static int sidtab_reverse_lookup(struct sidtab *s, struct context *context,
223 struct context *context, 258 u32 *sid)
224 u32 *out_sid)
225{ 259{
226 u32 sid; 260 int ret;
227 int ret = 0;
228 unsigned long flags; 261 unsigned long flags;
229 262
230 *out_sid = SECSID_NULL; 263 ret = sidtab_search_cache(s, context, sid);
231 264 if (ret)
232 sid = sidtab_search_cache(s, context); 265 ret = sidtab_search_context(s, context, sid);
233 if (!sid) 266 if (ret) {
234 sid = sidtab_search_context(s, context);
235 if (!sid) {
236 spin_lock_irqsave(&s->lock, flags); 267 spin_lock_irqsave(&s->lock, flags);
237 /* Rescan now that we hold the lock. */ 268 /* Rescan now that we hold the lock. */
238 sid = sidtab_search_context(s, context); 269 ret = sidtab_search_context(s, context, sid);
239 if (sid) 270 if (!ret)
240 goto unlock_out; 271 goto unlock_out;
241 /* No SID exists for the context. Allocate a new one. */ 272 /* No SID exists for the context. Allocate a new one. */
242 if (s->next_sid == UINT_MAX || s->shutdown) { 273 if (s->next_sid == (UINT_MAX - SECINITSID_NUM - 1) ||
274 s->shutdown) {
243 ret = -ENOMEM; 275 ret = -ENOMEM;
244 goto unlock_out; 276 goto unlock_out;
245 } 277 }
246 sid = s->next_sid++; 278 *sid = s->next_sid++;
247 if (context->len) 279 if (context->len)
248 pr_info("SELinux: Context %s is not valid (left unmapped).\n", 280 pr_info("SELinux: Context %s is not valid (left unmapped).\n",
249 context->str); 281 context->str);
250 ret = sidtab_insert(s, sid, context); 282 ret = sidtab_insert(s, *sid, context);
251 if (ret) 283 if (ret)
252 s->next_sid--; 284 s->next_sid--;
253unlock_out: 285unlock_out:
254 spin_unlock_irqrestore(&s->lock, flags); 286 spin_unlock_irqrestore(&s->lock, flags);
255 } 287 }
256 288
257 if (ret) 289 return ret;
258 return ret; 290}
291
292int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
293{
294 int rc;
295 u32 i;
259 296
260 *out_sid = sid; 297 for (i = 0; i < SECINITSID_NUM; i++) {
298 struct sidtab_isid_entry *entry = &s->isids[i];
299
300 if (entry->set && context_cmp(context, &entry->context)) {
301 *sid = i + 1;
302 return 0;
303 }
304 }
305
306 rc = sidtab_reverse_lookup(s, context, sid);
307 if (rc)
308 return rc;
309 *sid += SECINITSID_NUM + 1;
261 return 0; 310 return 0;
262} 311}
263 312
@@ -296,6 +345,10 @@ void sidtab_destroy(struct sidtab *s)
296 if (!s) 345 if (!s)
297 return; 346 return;
298 347
348 for (i = 0; i < SECINITSID_NUM; i++)
349 if (s->isids[i].set)
350 context_destroy(&s->isids[i].context);
351
299 for (i = 0; i < SIDTAB_SIZE; i++) { 352 for (i = 0; i < SIDTAB_SIZE; i++) {
300 cur = s->htable[i]; 353 cur = s->htable[i];
301 while (cur) { 354 while (cur) {
@@ -311,18 +364,3 @@ void sidtab_destroy(struct sidtab *s)
311 s->nel = 0; 364 s->nel = 0;
312 s->next_sid = 1; 365 s->next_sid = 1;
313} 366}
314
315void sidtab_set(struct sidtab *dst, struct sidtab *src)
316{
317 unsigned long flags;
318 int i;
319
320 spin_lock_irqsave(&src->lock, flags);
321 dst->htable = src->htable;
322 dst->nel = src->nel;
323 dst->next_sid = src->next_sid;
324 dst->shutdown = 0;
325 for (i = 0; i < SIDTAB_CACHE_LEN; i++)
326 dst->cache[i] = NULL;
327 spin_unlock_irqrestore(&src->lock, flags);
328}
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index e1d1f0beb17c..e657ae6bf996 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -22,6 +22,11 @@ struct sidtab_node {
22 22
23#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS 23#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
24 24
25struct sidtab_isid_entry {
26 int set;
27 struct context context;
28};
29
25struct sidtab { 30struct sidtab {
26 struct sidtab_node **htable; 31 struct sidtab_node **htable;
27 unsigned int nel; /* number of elements */ 32 unsigned int nel; /* number of elements */
@@ -30,10 +35,13 @@ struct sidtab {
30#define SIDTAB_CACHE_LEN 3 35#define SIDTAB_CACHE_LEN 3
31 struct sidtab_node *cache[SIDTAB_CACHE_LEN]; 36 struct sidtab_node *cache[SIDTAB_CACHE_LEN];
32 spinlock_t lock; 37 spinlock_t lock;
38
39 /* index == SID - 1 (no entry for SECSID_NULL) */
40 struct sidtab_isid_entry isids[SECINITSID_NUM];
33}; 41};
34 42
35int sidtab_init(struct sidtab *s); 43int sidtab_init(struct sidtab *s);
36int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); 44int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context);
37struct context *sidtab_search(struct sidtab *s, u32 sid); 45struct context *sidtab_search(struct sidtab *s, u32 sid);
38struct context *sidtab_search_force(struct sidtab *s, u32 sid); 46struct context *sidtab_search_force(struct sidtab *s, u32 sid);
39 47
@@ -43,13 +51,10 @@ int sidtab_convert(struct sidtab *s, struct sidtab *news,
43 void *args), 51 void *args),
44 void *args); 52 void *args);
45 53
46int sidtab_context_to_sid(struct sidtab *s, 54int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
47 struct context *context,
48 u32 *sid);
49 55
50void sidtab_hash_eval(struct sidtab *h, char *tag); 56void sidtab_hash_eval(struct sidtab *h, char *tag);
51void sidtab_destroy(struct sidtab *s); 57void sidtab_destroy(struct sidtab *s);
52void sidtab_set(struct sidtab *dst, struct sidtab *src);
53 58
54#endif /* _SS_SIDTAB_H_ */ 59#endif /* _SS_SIDTAB_H_ */
55 60