aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux')
-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
9 files changed, 625 insertions, 396 deletions
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