Re: [PATCH v4] selinux: remove unused initial SIDs and improve handling
Stephen Smalley <[email protected]> Thu, 30 Oct 2025 12:37:03 -0400
| Newsgroups | org.kernel.vger.selinux-refpolicy,org.kernel.vger.selinux |
|---|---|
| Message-ID | <CAEjxPJ7eTNMMPxK93wE53Xq_YxSiSttaJO3jMY3Y9TuVi2aq4g@mail.gmail.com> |
On Mon, Feb 24, 2020 at 8:55 PM Paul Moore <[email protected]> wrote: > > FWD'ing this to the mailing list while Stephen is having problems posting. > > ---------- Forwarded message --------- > From: Stephen Smalley <[email protected]> > Date: Mon, Feb 24, 2020 at 11:09 AM > Subject: [PATCH v4] selinux: remove unused initial SIDs and improve handling > To: <[email protected]> > Cc: <[email protected]>, <[email protected]>, <[email protected]>, > Stephen Smalley <[email protected]> > > > Remove initial SIDs that have never been used or are no longer used by > the kernel from its string table, which is also used to generate the > SECINITSID_* symbols referenced in code. Update the code to > gracefully handle the fact that these can now be NULL. Stop treating > it as an error if a policy defines additional initial SIDs unknown to > the kernel. Do not load unused initial SID contexts into the sidtab. > Fix the incorrect usage of the name from the ocontext in error > messages when loading initial SIDs since these are not presently > written to the kernel policy and are therefore always NULL. > > After this change, it is possible to safely reclaim and reuse some of > the unused initial SIDs without compatibility issues. Specifically, > unused initial SIDs that were being assigned the same context as the > unlabeled initial SID in policies can be reclaimed and reused for > another purpose, with existing policies still treating them as having > the unlabeled context and future policies having the option of mapping > them to a more specific context. For example, this could have been > used when the infiniband labeling support was introduced to define > initial SIDs for the default pkey and endport SIDs similar to the > handling of port/netif/node SIDs rather than always using > SECINITSID_UNLABELED as the default. > > The set of safely reclaimable unused initial SIDs across all known > policies is igmp_packet (13), icmp_socket (14), tcp_socket (15), kmod > (24), policy (25), and scmp_packet (26); these initial SIDs were > assigned the same context as unlabeled in all known policies including > mls. If only considering non-mls policies (i.e. assuming that mls > users always upgrade policy with their kernels), the set of safely > reclaimable unused initial SIDs further includes file_labels (6), init > (7), sysctl_modprobe (16), and sysctl_fs (18) through sysctl_dev (23). > > Adding new initial SIDs beyond SECINITSID_NUM to policy unfortunately > became a fatal error in commit 24ed7fdae669 ("selinux: use separate > table for initial SID lookup") and even before that it could cause > problems on a policy reload (collision between the new initial SID and > one allocated at runtime) ever since commit 42596eafdd75 ("selinux: > load the initial SIDs upon every policy load") so we cannot safely > start adding new initial SIDs to policies beyond SECINITSID_NUM (27) > until such a time as all such kernels do not need to be supported and > only those that include this commit are relevant. That is not a big > deal since we haven't added a new initial SID since 2004 (v2.6.7) and > we have plenty of unused ones we can reclaim if we truly need one. > > If we want to avoid the wasted storage in initial_sid_to_string[] > and/or sidtab->isids[] for the unused initial SIDs, we could introduce > an indirection between the kernel initial SID values and the policy > initial SID values and just map the policy SID values in the ocontexts > to the kernel values during policy_load_isids(). Originally I thought > we'd do this by preserving the initial SID names in the kernel policy > and creating a mapping at load time like we do for the security > classes and permissions but that would require a new kernel policy > format version and associated changes to libsepol/checkpolicy and I'm > not sure it is justified. Simpler approach is just to create a fixed > mapping table in the kernel from the existing fixed policy values to > the kernel values. Less flexible but probably sufficient. > > A separate selinux userspace change was applied in > https://github.com/SELinuxProject/selinux/commit/8677ce5e8f592950ae6f14cea1b68a20ddc1ac25 > to enable removal of most of the unused initial SID contexts from > policies, but there is no dependency between that change and this one. > That change permits removing all of the unused initial SID contexts > from policy except for the fs and sysctl SID contexts. The initial > SID declarations themselves would remain in policy to preserve the > values of subsequent ones but the contexts can be dropped. If/when > the kernel decides to reuse one of them, future policies can change > the name and start assigning a context again without breaking > compatibility. > > Here is how I would envision staging changes to the initial SIDs in a > compatible manner after this commit is applied: > > 1. At any time after this commit is applied, the kernel could choose > to reclaim one of the safely reclaimable unused initial SIDs listed > above for a new purpose (i.e. replace its NULL entry in the > initial_sid_to_string[] table with a new name and start using the > newly generated SECINITSID_name symbol in code), and refpolicy could > at that time rename its declaration of that initial SID to reflect its > new purpose and start assigning it a context going > forward. Existing/old policies would map the reclaimed initial SID to > the unlabeled context, so that would be the initial default behavior > until policies are updated. This doesn't depend on the selinux > userspace change; it will work with existing policies and userspace. > > 2. In 6 months or so we'll have another SELinux userspace release that > will include the libsepol/checkpolicy support for omitting unused > initial SID contexts. > > 3. At any time after that release, refpolicy can make that release its > minimum build requirement and drop the sid context statements (but not > the sid declarations) for all of the unused initial SIDs except for > fs and sysctl, which must remain for compatibility on policy > reload with old kernels and for compatibility with kernels that were > still using SECINITSID_SYSCTL (< 2.6.39). This doesn't depend on this > kernel commit; it will work with previous kernels as well. This never happened AFAICT and I'm not sure if it was even tried. Might need/want to retain the sid context statement for the init SID too since it was re-activated by a later patch by Ondrej. > 4. After N years for some value of N, refpolicy decides that it no > longer cares about policy reload compatibility for kernels that > predate this kernel commit, and refpolicy drops the fs and sysctl > SID contexts from policy too (but retains the declarations). Checking to see if N == 5 here ;) > 5. After M years for some value of M, the kernel decides that it no > longer cares about compatibility with refpolicies that predate step 4 > (dropping the fs and sysctl SIDs), and those two SIDs also become > safely reclaimable. This step is optional and need not ever occur unless > we decide that the need to reclaim those two SIDs outweighs the > compatibility cost. > > 6. After O years for some value of O, refpolicy decides that it no > longer cares about policy load (not just reload) compatibility for > kernels that predate this kernel commit, and both kernel and refpolicy > can then start adding and using new initial SIDs beyond 27. This does > not depend on the previous change (step 5) and can occur independent > of it. > > Fixes: https://github.com/SELinuxProject/selinux-kernel/issues/12 > Signed-off-by: Stephen Smalley <[email protected]> > --- > v4 fixes the commit hashes that I cut-and-pasted from the GH issue > comments to be the proper length and added the one-line descriptions. > Oddly checkpatch.pl didn't catch that originally. > > scripts/selinux/genheaders/genheaders.c | 11 +++- > .../selinux/include/initial_sid_to_string.h | 57 +++++++++---------- > security/selinux/selinuxfs.c | 6 +- > security/selinux/ss/policydb.c | 25 ++++---- > security/selinux/ss/services.c | 26 ++++----- > 5 files changed, 66 insertions(+), 59 deletions(-) > > diff --git a/scripts/selinux/genheaders/genheaders.c > b/scripts/selinux/genheaders/genheaders.c > index 544ca126a8a8..f355b3e0e968 100644 > --- a/scripts/selinux/genheaders/genheaders.c > +++ b/scripts/selinux/genheaders/genheaders.c > @@ -67,8 +67,12 @@ int main(int argc, char *argv[]) > } > > isids_len = sizeof(initial_sid_to_string) / sizeof (char *); > - for (i = 1; i < isids_len; i++) > - initial_sid_to_string[i] = stoupperx(initial_sid_to_string[i]); > + for (i = 1; i < isids_len; i++) { > + const char *s = initial_sid_to_string[i]; > + > + if (s) > + initial_sid_to_string[i] = stoupperx(s); > + } > > fprintf(fout, "/* This file is automatically generated. Do > not edit. */\n"); > fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define > _SELINUX_FLASK_H_\n\n"); > @@ -82,7 +86,8 @@ int main(int argc, char *argv[]) > > for (i = 1; i < isids_len; i++) { > const char *s = initial_sid_to_string[i]; > - fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i); > + if (s) > + fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i); > } > fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1); > fprintf(fout, "\nstatic inline bool > security_is_socket_class(u16 kern_tclass)\n"); > diff --git a/security/selinux/include/initial_sid_to_string.h > b/security/selinux/include/initial_sid_to_string.h > index 4f93f697f71c..5d332aeb8b6c 100644 > --- a/security/selinux/include/initial_sid_to_string.h > +++ b/security/selinux/include/initial_sid_to_string.h > @@ -1,34 +1,33 @@ > /* SPDX-License-Identifier: GPL-2.0 */ > -/* This file is automatically generated. Do not edit. */ > static const char *initial_sid_to_string[] = > { > - "null", > - "kernel", > - "security", > - "unlabeled", > - "fs", > - "file", > - "file_labels", > - "init", > - "any_socket", > - "port", > - "netif", > - "netmsg", > - "node", > - "igmp_packet", > - "icmp_socket", > - "tcp_socket", > - "sysctl_modprobe", > - "sysctl", > - "sysctl_fs", > - "sysctl_kernel", > - "sysctl_net", > - "sysctl_net_unix", > - "sysctl_vm", > - "sysctl_dev", > - "kmod", > - "policy", > - "scmp_packet", > - "devnull", > + NULL, > + "kernel", > + "security", > + "unlabeled", > + NULL, > + "file", > + NULL, > + NULL, > + "any_socket", > + "port", > + "netif", > + "netmsg", > + "node", > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + "devnull", > }; > > diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c > index 533ab170ad52..4781314c2510 100644 > --- a/security/selinux/selinuxfs.c > +++ b/security/selinux/selinuxfs.c > @@ -1701,7 +1701,11 @@ static int sel_make_initcon_files(struct dentry *dir) > for (i = 1; i <= SECINITSID_NUM; i++) { > struct inode *inode; > struct dentry *dentry; > - dentry = d_alloc_name(dir, security_get_initial_sid_context(i)); > + const char *s = security_get_initial_sid_context(i); > + > + if (!s) > + continue; > + dentry = d_alloc_name(dir, s); > if (!dentry) > return -ENOMEM; > > diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c > index 32b3a8acf96f..406fb02d80ae 100644 > --- a/security/selinux/ss/policydb.c > +++ b/security/selinux/ss/policydb.c > @@ -867,29 +867,28 @@ int policydb_load_isids(struct policydb *p, > struct sidtab *s) > > head = p->ocontexts[OCON_ISID]; > for (c = head; c; c = c->next) { > - rc = -EINVAL; > - if (!c->context[0].user) { > - pr_err("SELinux: SID %s was never defined.\n", > - c->u.name); > - sidtab_destroy(s); > - goto out; > - } > - if (c->sid[0] == SECSID_NULL || c->sid[0] > SECINITSID_NUM) { > - pr_err("SELinux: Initial SID %s out of range.\n", > - c->u.name); > + u32 sid = c->sid[0]; > + const char *name = security_get_initial_sid_context(sid); > + > + if (sid == SECSID_NULL) { > + pr_err("SELinux: SID 0 was assigned a context.\n"); > sidtab_destroy(s); > goto out; > } > + > + /* Ignore initial SIDs unused by this kernel. */ > + if (!name) > + continue; > + > rc = context_add_hash(p, &c->context[0]); > if (rc) { > sidtab_destroy(s); > goto out; > } > - > - rc = sidtab_set_initial(s, c->sid[0], &c->context[0]); > + rc = sidtab_set_initial(s, sid, &c->context[0]); > if (rc) { > pr_err("SELinux: unable to load initial SID %s.\n", > - c->u.name); > + name); > sidtab_destroy(s); > goto out; > } > diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c > index f90e6550eec8..8ad34fd031d1 100644 > --- a/security/selinux/ss/services.c > +++ b/security/selinux/ss/services.c > @@ -1322,23 +1322,22 @@ static int security_sid_to_context_core(struct > selinux_state *state, > if (!selinux_initialized(state)) { > if (sid <= SECINITSID_NUM) { > char *scontextp; > + const char *s = initial_sid_to_string[sid]; > > - *scontext_len = strlen(initial_sid_to_string[sid]) + 1; > + if (!s) > + return -EINVAL; > + *scontext_len = strlen(s) + 1; > if (!scontext) > - goto out; > - scontextp = kmemdup(initial_sid_to_string[sid], > - *scontext_len, GFP_ATOMIC); > - if (!scontextp) { > - rc = -ENOMEM; > - goto out; > - } > + return 0; > + scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC); > + if (!scontextp) > + return -ENOMEM; > *scontext = scontextp; > - goto out; > + return 0; > } > pr_err("SELinux: %s: called before initial " > "load_policy on unknown SID %d\n", __func__, sid); > - rc = -EINVAL; > - goto out; > + return -EINVAL; > } > read_lock(&state->ss->policy_rwlock); > policydb = &state->ss->policydb; > @@ -1362,7 +1361,6 @@ static int security_sid_to_context_core(struct > selinux_state *state, > > out_unlock: > read_unlock(&state->ss->policy_rwlock); > -out: > return rc; > > } > @@ -1552,7 +1550,9 @@ static int security_context_to_sid_core(struct > selinux_state *state, > int i; > > for (i = 1; i < SECINITSID_NUM; i++) { > - if (!strcmp(initial_sid_to_string[i], scontext2)) { > + const char *s = initial_sid_to_string[i]; > + > + if (s && !strcmp(s, scontext2)) { > *sid = i; > goto out; > } > -- > 2.24.1 > > > > -- > paul moore > www.paul-moore.com