2019-05-31 15:09:32 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* Implementation of the security services.
|
|
|
|
*
|
2017-08-18 00:32:36 +07:00
|
|
|
* Authors : Stephen Smalley, <sds@tycho.nsa.gov>
|
2008-04-19 04:38:33 +07:00
|
|
|
* James Morris <jmorris@redhat.com>
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
|
|
|
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
|
|
|
|
*
|
|
|
|
* Support for enhanced MLS infrastructure.
|
2006-02-25 04:44:05 +07:00
|
|
|
* Support for context based audit filters.
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
|
|
|
* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
|
|
|
|
*
|
2008-04-19 04:38:33 +07:00
|
|
|
* Added conditional policy language extensions
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
2011-08-01 18:10:33 +07:00
|
|
|
* Updated: Hewlett-Packard <paul@paul-moore.com>
|
2006-08-05 13:17:57 +07:00
|
|
|
*
|
|
|
|
* Added support for NetLabel
|
2008-01-29 20:38:19 +07:00
|
|
|
* Added support for the policy capability bitmap
|
2006-08-05 13:17:57 +07:00
|
|
|
*
|
2006-11-07 00:38:18 +07:00
|
|
|
* Updated: Chad Sellers <csellers@tresys.com>
|
|
|
|
*
|
|
|
|
* Added validation of kernel classes and permissions
|
|
|
|
*
|
2009-06-18 15:26:13 +07:00
|
|
|
* Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
|
|
|
|
*
|
|
|
|
* Added support for bounds domain and audit messaged on masked permissions
|
|
|
|
*
|
2010-02-03 22:40:20 +07:00
|
|
|
* Updated: Guido Trentalancia <guido@trentalancia.com>
|
|
|
|
*
|
|
|
|
* Added support for runtime switching of the policy type
|
|
|
|
*
|
2009-06-18 15:26:13 +07:00
|
|
|
* Copyright (C) 2008, 2009 NEC Corporation
|
2008-01-29 20:38:19 +07:00
|
|
|
* Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
|
2006-02-25 04:44:05 +07:00
|
|
|
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
|
2006-11-07 00:38:18 +07:00
|
|
|
* Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
|
2005-04-17 05:20:36 +07:00
|
|
|
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
|
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/spinlock.h>
|
2006-11-18 05:38:53 +07:00
|
|
|
#include <linux/rcupdate.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/in.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/audit.h>
|
2010-10-20 12:08:00 +07:00
|
|
|
#include <linux/vmalloc.h>
|
2006-08-05 13:17:57 +07:00
|
|
|
#include <net/netlabel.h>
|
2006-03-22 15:09:14 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#include "flask.h"
|
|
|
|
#include "avc.h"
|
|
|
|
#include "avc_ss.h"
|
|
|
|
#include "security.h"
|
|
|
|
#include "context.h"
|
|
|
|
#include "policydb.h"
|
|
|
|
#include "sidtab.h"
|
|
|
|
#include "services.h"
|
|
|
|
#include "conditional.h"
|
|
|
|
#include "mls.h"
|
2006-08-05 13:17:57 +07:00
|
|
|
#include "objsec.h"
|
2007-03-01 03:14:23 +07:00
|
|
|
#include "netlabel.h"
|
2006-11-18 05:38:54 +07:00
|
|
|
#include "xfrm.h"
|
2006-11-30 01:18:18 +07:00
|
|
|
#include "ebitmap.h"
|
2008-03-02 03:03:14 +07:00
|
|
|
#include "audit.h"
|
2020-08-07 01:34:18 +07:00
|
|
|
#include "policycap_names.h"
|
2017-05-19 03:58:31 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Forward declaration. */
|
2018-03-02 06:48:02 +07:00
|
|
|
static int context_struct_to_string(struct policydb *policydb,
|
|
|
|
struct context *context,
|
|
|
|
char **scontext,
|
2005-04-17 05:20:36 +07:00
|
|
|
u32 *scontext_len);
|
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
static int sidtab_entry_to_string(struct policydb *policydb,
|
|
|
|
struct sidtab *sidtab,
|
|
|
|
struct sidtab_entry *entry,
|
|
|
|
char **scontext,
|
|
|
|
u32 *scontext_len);
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static void context_struct_compute_av(struct policydb *policydb,
|
|
|
|
struct context *scontext,
|
|
|
|
struct context *tcontext,
|
|
|
|
u16 tclass,
|
|
|
|
struct av_decision *avd,
|
|
|
|
struct extended_perms *xperms);
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
|
|
|
|
static int selinux_set_mapping(struct policydb *pol,
|
|
|
|
struct security_class_mapping *map,
|
2018-03-02 06:48:02 +07:00
|
|
|
struct selinux_map *out_map)
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
{
|
|
|
|
u16 i, j;
|
|
|
|
unsigned k;
|
|
|
|
bool print_unknown_handle = false;
|
|
|
|
|
|
|
|
/* Find number of classes in the input mapping */
|
|
|
|
if (!map)
|
|
|
|
return -EINVAL;
|
|
|
|
i = 0;
|
|
|
|
while (map[i].name)
|
|
|
|
i++;
|
|
|
|
|
|
|
|
/* Allocate space for the class records, plus one for class zero */
|
2018-03-02 06:48:02 +07:00
|
|
|
out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
|
|
|
|
if (!out_map->mapping)
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* Store the raw class and permission values */
|
|
|
|
j = 0;
|
|
|
|
while (map[j].name) {
|
|
|
|
struct security_class_mapping *p_in = map + (j++);
|
2018-03-02 06:48:02 +07:00
|
|
|
struct selinux_mapping *p_out = out_map->mapping + j;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
|
|
|
|
/* An empty class string skips ahead */
|
|
|
|
if (!strcmp(p_in->name, "")) {
|
|
|
|
p_out->num_perms = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_out->value = string_to_security_class(pol, p_in->name);
|
|
|
|
if (!p_out->value) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_info("SELinux: Class %s not defined in policy.\n",
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
p_in->name);
|
|
|
|
if (pol->reject_unknown)
|
|
|
|
goto err;
|
|
|
|
p_out->num_perms = 0;
|
|
|
|
print_unknown_handle = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
k = 0;
|
2017-03-17 05:26:52 +07:00
|
|
|
while (p_in->perms[k]) {
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
/* An empty permission string skips ahead */
|
|
|
|
if (!*p_in->perms[k]) {
|
|
|
|
k++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
p_out->perms[k] = string_to_av_perm(pol, p_out->value,
|
|
|
|
p_in->perms[k]);
|
|
|
|
if (!p_out->perms[k]) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_info("SELinux: Permission %s in class %s not defined in policy.\n",
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
p_in->perms[k], p_in->name);
|
|
|
|
if (pol->reject_unknown)
|
|
|
|
goto err;
|
|
|
|
print_unknown_handle = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
p_out->num_perms = k;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (print_unknown_handle)
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_info("SELinux: the above unknown classes and permissions will be %s\n",
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
pol->allow_unknown ? "allowed" : "denied");
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
out_map->size = i;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
return 0;
|
|
|
|
err:
|
2018-03-02 06:48:02 +07:00
|
|
|
kfree(out_map->mapping);
|
|
|
|
out_map->mapping = NULL;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get real, policy values from mapped values
|
|
|
|
*/
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static u16 unmap_class(struct selinux_map *map, u16 tclass)
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
if (tclass < map->size)
|
|
|
|
return map->mapping[tclass].value;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
|
|
|
|
return tclass;
|
|
|
|
}
|
|
|
|
|
2011-03-02 12:32:33 +07:00
|
|
|
/*
|
|
|
|
* Get kernel value for class from its policy value
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
static u16 map_class(struct selinux_map *map, u16 pol_value)
|
2011-03-02 12:32:33 +07:00
|
|
|
{
|
|
|
|
u16 i;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
for (i = 1; i < map->size; i++) {
|
|
|
|
if (map->mapping[i].value == pol_value)
|
2011-03-02 12:32:33 +07:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2011-03-25 21:13:43 +07:00
|
|
|
return SECCLASS_NULL;
|
2011-03-02 12:32:33 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static void map_decision(struct selinux_map *map,
|
|
|
|
u16 tclass, struct av_decision *avd,
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
int allow_unknown)
|
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
if (tclass < map->size) {
|
|
|
|
struct selinux_mapping *mapping = &map->mapping[tclass];
|
|
|
|
unsigned int i, n = mapping->num_perms;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
u32 result;
|
|
|
|
|
|
|
|
for (i = 0, result = 0; i < n; i++) {
|
2018-03-02 06:48:02 +07:00
|
|
|
if (avd->allowed & mapping->perms[i])
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
result |= 1<<i;
|
2018-03-02 06:48:02 +07:00
|
|
|
if (allow_unknown && !mapping->perms[i])
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
result |= 1<<i;
|
|
|
|
}
|
|
|
|
avd->allowed = result;
|
|
|
|
|
|
|
|
for (i = 0, result = 0; i < n; i++)
|
2018-03-02 06:48:02 +07:00
|
|
|
if (avd->auditallow & mapping->perms[i])
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
result |= 1<<i;
|
|
|
|
avd->auditallow = result;
|
|
|
|
|
|
|
|
for (i = 0, result = 0; i < n; i++) {
|
2018-03-02 06:48:02 +07:00
|
|
|
if (avd->auditdeny & mapping->perms[i])
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
result |= 1<<i;
|
2018-03-02 06:48:02 +07:00
|
|
|
if (!allow_unknown && !mapping->perms[i])
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
result |= 1<<i;
|
|
|
|
}
|
2009-11-24 04:47:23 +07:00
|
|
|
/*
|
|
|
|
* In case the kernel has a bug and requests a permission
|
|
|
|
* between num_perms and the maximum permission number, we
|
|
|
|
* should audit that denial
|
|
|
|
*/
|
|
|
|
for (; i < (sizeof(u32)*8); i++)
|
|
|
|
result |= 1<<i;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
avd->auditdeny = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_mls_enabled(struct selinux_state *state)
|
2010-02-03 22:40:20 +07:00
|
|
|
{
|
2020-08-07 20:29:33 +07:00
|
|
|
int mls_enabled;
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
|
2020-08-07 20:29:33 +07:00
|
|
|
if (!selinux_initialized(state))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
mls_enabled = policy->policydb.mls_enabled;
|
|
|
|
rcu_read_unlock();
|
2020-08-07 20:29:33 +07:00
|
|
|
return mls_enabled;
|
2010-02-03 22:40:20 +07:00
|
|
|
}
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* Return the boolean value of a constraint expression
|
|
|
|
* when it is applied to the specified source and target
|
|
|
|
* security contexts.
|
|
|
|
*
|
|
|
|
* xcontext is a special beast... It is used by the validatetrans rules
|
|
|
|
* only. For these rules, scontext is the context before the transition,
|
|
|
|
* tcontext is the context after the transition, and xcontext is the context
|
|
|
|
* of the process performing the transition. All other callers of
|
|
|
|
* constraint_expr_eval should pass in NULL for xcontext.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
static int constraint_expr_eval(struct policydb *policydb,
|
|
|
|
struct context *scontext,
|
2005-04-17 05:20:36 +07:00
|
|
|
struct context *tcontext,
|
|
|
|
struct context *xcontext,
|
|
|
|
struct constraint_expr *cexpr)
|
|
|
|
{
|
|
|
|
u32 val1, val2;
|
|
|
|
struct context *c;
|
|
|
|
struct role_datum *r1, *r2;
|
|
|
|
struct mls_level *l1, *l2;
|
|
|
|
struct constraint_expr *e;
|
|
|
|
int s[CEXPR_MAXDEPTH];
|
|
|
|
int sp = -1;
|
|
|
|
|
|
|
|
for (e = cexpr; e; e = e->next) {
|
|
|
|
switch (e->expr_type) {
|
|
|
|
case CEXPR_NOT:
|
|
|
|
BUG_ON(sp < 0);
|
|
|
|
s[sp] = !s[sp];
|
|
|
|
break;
|
|
|
|
case CEXPR_AND:
|
|
|
|
BUG_ON(sp < 1);
|
|
|
|
sp--;
|
2010-04-09 18:30:29 +07:00
|
|
|
s[sp] &= s[sp + 1];
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
case CEXPR_OR:
|
|
|
|
BUG_ON(sp < 1);
|
|
|
|
sp--;
|
2010-04-09 18:30:29 +07:00
|
|
|
s[sp] |= s[sp + 1];
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
case CEXPR_ATTR:
|
2010-04-09 18:30:29 +07:00
|
|
|
if (sp == (CEXPR_MAXDEPTH - 1))
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
|
|
|
switch (e->attr) {
|
|
|
|
case CEXPR_USER:
|
|
|
|
val1 = scontext->user;
|
|
|
|
val2 = tcontext->user;
|
|
|
|
break;
|
|
|
|
case CEXPR_TYPE:
|
|
|
|
val1 = scontext->type;
|
|
|
|
val2 = tcontext->type;
|
|
|
|
break;
|
|
|
|
case CEXPR_ROLE:
|
|
|
|
val1 = scontext->role;
|
|
|
|
val2 = tcontext->role;
|
2018-03-02 06:48:02 +07:00
|
|
|
r1 = policydb->role_val_to_struct[val1 - 1];
|
|
|
|
r2 = policydb->role_val_to_struct[val2 - 1];
|
2005-04-17 05:20:36 +07:00
|
|
|
switch (e->op) {
|
|
|
|
case CEXPR_DOM:
|
|
|
|
s[++sp] = ebitmap_get_bit(&r1->dominates,
|
|
|
|
val2 - 1);
|
|
|
|
continue;
|
|
|
|
case CEXPR_DOMBY:
|
|
|
|
s[++sp] = ebitmap_get_bit(&r2->dominates,
|
|
|
|
val1 - 1);
|
|
|
|
continue;
|
|
|
|
case CEXPR_INCOMP:
|
2008-04-19 04:38:33 +07:00
|
|
|
s[++sp] = (!ebitmap_get_bit(&r1->dominates,
|
|
|
|
val2 - 1) &&
|
|
|
|
!ebitmap_get_bit(&r2->dominates,
|
|
|
|
val1 - 1));
|
2005-04-17 05:20:36 +07:00
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CEXPR_L1L2:
|
|
|
|
l1 = &(scontext->range.level[0]);
|
|
|
|
l2 = &(tcontext->range.level[0]);
|
|
|
|
goto mls_ops;
|
|
|
|
case CEXPR_L1H2:
|
|
|
|
l1 = &(scontext->range.level[0]);
|
|
|
|
l2 = &(tcontext->range.level[1]);
|
|
|
|
goto mls_ops;
|
|
|
|
case CEXPR_H1L2:
|
|
|
|
l1 = &(scontext->range.level[1]);
|
|
|
|
l2 = &(tcontext->range.level[0]);
|
|
|
|
goto mls_ops;
|
|
|
|
case CEXPR_H1H2:
|
|
|
|
l1 = &(scontext->range.level[1]);
|
|
|
|
l2 = &(tcontext->range.level[1]);
|
|
|
|
goto mls_ops;
|
|
|
|
case CEXPR_L1H1:
|
|
|
|
l1 = &(scontext->range.level[0]);
|
|
|
|
l2 = &(scontext->range.level[1]);
|
|
|
|
goto mls_ops;
|
|
|
|
case CEXPR_L2H2:
|
|
|
|
l1 = &(tcontext->range.level[0]);
|
|
|
|
l2 = &(tcontext->range.level[1]);
|
|
|
|
goto mls_ops;
|
|
|
|
mls_ops:
|
|
|
|
switch (e->op) {
|
|
|
|
case CEXPR_EQ:
|
|
|
|
s[++sp] = mls_level_eq(l1, l2);
|
|
|
|
continue;
|
|
|
|
case CEXPR_NEQ:
|
|
|
|
s[++sp] = !mls_level_eq(l1, l2);
|
|
|
|
continue;
|
|
|
|
case CEXPR_DOM:
|
|
|
|
s[++sp] = mls_level_dom(l1, l2);
|
|
|
|
continue;
|
|
|
|
case CEXPR_DOMBY:
|
|
|
|
s[++sp] = mls_level_dom(l2, l1);
|
|
|
|
continue;
|
|
|
|
case CEXPR_INCOMP:
|
|
|
|
s[++sp] = mls_level_incomp(l2, l1);
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (e->op) {
|
|
|
|
case CEXPR_EQ:
|
|
|
|
s[++sp] = (val1 == val2);
|
|
|
|
break;
|
|
|
|
case CEXPR_NEQ:
|
|
|
|
s[++sp] = (val1 != val2);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CEXPR_NAMES:
|
|
|
|
if (sp == (CEXPR_MAXDEPTH-1))
|
|
|
|
return 0;
|
|
|
|
c = scontext;
|
|
|
|
if (e->attr & CEXPR_TARGET)
|
|
|
|
c = tcontext;
|
|
|
|
else if (e->attr & CEXPR_XTARGET) {
|
|
|
|
c = xcontext;
|
|
|
|
if (!c) {
|
|
|
|
BUG();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (e->attr & CEXPR_USER)
|
|
|
|
val1 = c->user;
|
|
|
|
else if (e->attr & CEXPR_ROLE)
|
|
|
|
val1 = c->role;
|
|
|
|
else if (e->attr & CEXPR_TYPE)
|
|
|
|
val1 = c->type;
|
|
|
|
else {
|
|
|
|
BUG();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (e->op) {
|
|
|
|
case CEXPR_EQ:
|
|
|
|
s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
|
|
|
|
break;
|
|
|
|
case CEXPR_NEQ:
|
|
|
|
s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BUG_ON(sp != 0);
|
|
|
|
return s[0];
|
|
|
|
}
|
|
|
|
|
2009-06-18 15:26:13 +07:00
|
|
|
/*
|
|
|
|
* security_dump_masked_av - dumps masked permissions during
|
|
|
|
* security_compute_av due to RBAC, MLS/Constraint and Type bounds.
|
|
|
|
*/
|
|
|
|
static int dump_masked_av_helper(void *k, void *d, void *args)
|
|
|
|
{
|
|
|
|
struct perm_datum *pdatum = d;
|
|
|
|
char **permission_names = args;
|
|
|
|
|
|
|
|
BUG_ON(pdatum->value < 1 || pdatum->value > 32);
|
|
|
|
|
|
|
|
permission_names[pdatum->value - 1] = (char *)k;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static void security_dump_masked_av(struct policydb *policydb,
|
|
|
|
struct context *scontext,
|
2009-06-18 15:26:13 +07:00
|
|
|
struct context *tcontext,
|
|
|
|
u16 tclass,
|
|
|
|
u32 permissions,
|
|
|
|
const char *reason)
|
|
|
|
{
|
|
|
|
struct common_datum *common_dat;
|
|
|
|
struct class_datum *tclass_dat;
|
|
|
|
struct audit_buffer *ab;
|
|
|
|
char *tclass_name;
|
|
|
|
char *scontext_name = NULL;
|
|
|
|
char *tcontext_name = NULL;
|
|
|
|
char *permission_names[32];
|
2010-02-16 13:29:06 +07:00
|
|
|
int index;
|
|
|
|
u32 length;
|
2009-06-18 15:26:13 +07:00
|
|
|
bool need_comma = false;
|
|
|
|
|
|
|
|
if (!permissions)
|
|
|
|
return;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
|
|
|
|
tclass_dat = policydb->class_val_to_struct[tclass - 1];
|
2009-06-18 15:26:13 +07:00
|
|
|
common_dat = tclass_dat->comdatum;
|
|
|
|
|
|
|
|
/* init permission_names */
|
|
|
|
if (common_dat &&
|
2020-04-28 19:55:12 +07:00
|
|
|
hashtab_map(&common_dat->permissions.table,
|
2009-06-18 15:26:13 +07:00
|
|
|
dump_masked_av_helper, permission_names) < 0)
|
|
|
|
goto out;
|
|
|
|
|
2020-04-28 19:55:12 +07:00
|
|
|
if (hashtab_map(&tclass_dat->permissions.table,
|
2009-06-18 15:26:13 +07:00
|
|
|
dump_masked_av_helper, permission_names) < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* get scontext/tcontext in text form */
|
2018-03-02 06:48:02 +07:00
|
|
|
if (context_struct_to_string(policydb, scontext,
|
2009-06-18 15:26:13 +07:00
|
|
|
&scontext_name, &length) < 0)
|
|
|
|
goto out;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
if (context_struct_to_string(policydb, tcontext,
|
2009-06-18 15:26:13 +07:00
|
|
|
&tcontext_name, &length) < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* audit a message */
|
2018-05-13 08:58:20 +07:00
|
|
|
ab = audit_log_start(audit_context(),
|
2009-06-18 15:26:13 +07:00
|
|
|
GFP_ATOMIC, AUDIT_SELINUX_ERR);
|
|
|
|
if (!ab)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
audit_log_format(ab, "op=security_compute_av reason=%s "
|
|
|
|
"scontext=%s tcontext=%s tclass=%s perms=",
|
|
|
|
reason, scontext_name, tcontext_name, tclass_name);
|
|
|
|
|
|
|
|
for (index = 0; index < 32; index++) {
|
|
|
|
u32 mask = (1 << index);
|
|
|
|
|
|
|
|
if ((mask & permissions) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
audit_log_format(ab, "%s%s",
|
|
|
|
need_comma ? "," : "",
|
|
|
|
permission_names[index]
|
|
|
|
? permission_names[index] : "????");
|
|
|
|
need_comma = true;
|
|
|
|
}
|
|
|
|
audit_log_end(ab);
|
|
|
|
out:
|
|
|
|
/* release scontext/tcontext */
|
|
|
|
kfree(tcontext_name);
|
|
|
|
kfree(scontext_name);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-08-28 14:35:57 +07:00
|
|
|
/*
|
|
|
|
* security_boundary_permission - drops violated permissions
|
|
|
|
* on boundary constraint.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
static void type_attribute_bounds_av(struct policydb *policydb,
|
|
|
|
struct context *scontext,
|
2008-08-28 14:35:57 +07:00
|
|
|
struct context *tcontext,
|
|
|
|
u16 tclass,
|
|
|
|
struct av_decision *avd)
|
|
|
|
{
|
2010-02-17 06:49:41 +07:00
|
|
|
struct context lo_scontext;
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
struct context lo_tcontext, *tcontextp = tcontext;
|
2010-02-17 06:49:41 +07:00
|
|
|
struct av_decision lo_avd;
|
2010-11-30 03:47:09 +07:00
|
|
|
struct type_datum *source;
|
|
|
|
struct type_datum *target;
|
2010-02-17 06:49:41 +07:00
|
|
|
u32 masked = 0;
|
2008-08-28 14:35:57 +07:00
|
|
|
|
2019-07-29 15:41:17 +07:00
|
|
|
source = policydb->type_val_to_struct[scontext->type - 1];
|
2010-11-30 03:47:09 +07:00
|
|
|
BUG_ON(!source);
|
|
|
|
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
if (!source->bounds)
|
|
|
|
return;
|
|
|
|
|
2019-07-29 15:41:17 +07:00
|
|
|
target = policydb->type_val_to_struct[tcontext->type - 1];
|
2010-11-30 03:47:09 +07:00
|
|
|
BUG_ON(!target);
|
|
|
|
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
memset(&lo_avd, 0, sizeof(lo_avd));
|
2008-08-28 14:35:57 +07:00
|
|
|
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
|
|
|
|
lo_scontext.type = source->bounds;
|
2010-02-17 06:49:41 +07:00
|
|
|
|
|
|
|
if (target->bounds) {
|
|
|
|
memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
|
|
|
|
lo_tcontext.type = target->bounds;
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
tcontextp = &lo_tcontext;
|
2010-02-17 06:49:41 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
context_struct_compute_av(policydb, &lo_scontext,
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
tcontextp,
|
|
|
|
tclass,
|
|
|
|
&lo_avd,
|
|
|
|
NULL);
|
2010-02-17 06:49:41 +07:00
|
|
|
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
masked = ~lo_avd.allowed & avd->allowed;
|
2008-08-28 14:35:57 +07:00
|
|
|
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
if (likely(!masked))
|
|
|
|
return; /* no masked permission */
|
2008-08-28 14:35:57 +07:00
|
|
|
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
/* mask violated permissions */
|
|
|
|
avd->allowed &= ~masked;
|
|
|
|
|
|
|
|
/* audit masked permissions */
|
2018-03-02 06:48:02 +07:00
|
|
|
security_dump_masked_av(policydb, scontext, tcontext,
|
selinux: Only apply bounds checking to source types
The current bounds checking of both source and target types
requires allowing any domain that has access to the child
domain to also have the same permissions to the parent, which
is undesirable. Drop the target bounds checking.
KaiGai Kohei originally removed all use of target bounds in
commit 7d52a155e38d ("selinux: remove dead code in
type_attribute_bounds_av()") but this was reverted in
commit 2ae3ba39389b ("selinux: libsepol: remove dead code in
check_avtab_hierarchy_callback()") because it would have
required explicitly allowing the parent any permissions
to the child that the child is allowed to itself.
This change in contrast retains the logic for the case where both
source and target types are bounded, thereby allowing access
if the parent of the source is allowed the corresponding
permissions to the parent of the target. Further, this change
reworks the logic such that we only perform a single computation
for each case and there is no ambiguity as to how to resolve
a bounds violation.
Under the new logic, if the source type and target types are both
bounded, then the parent of the source type must be allowed the same
permissions to the parent of the target type. If only the source
type is bounded, then the parent of the source type must be allowed
the same permissions to the target type.
Examples of the new logic and comparisons with the old logic:
1. If we have:
typebounds A B;
then:
allow B self:process <permissions>;
will satisfy the bounds constraint iff:
allow A self:process <permissions>;
is also allowed in policy.
Under the old logic, the allow rule on B satisfies the
bounds constraint if any of the following three are allowed:
allow A B:process <permissions>; or
allow B A:process <permissions>; or
allow A self:process <permissions>;
However, either of the first two ultimately require the third to
satisfy the bounds constraint under the old logic, and therefore
this degenerates to the same result (but is more efficient - we only
need to perform one compute_av call).
2. If we have:
typebounds A B;
typebounds A_exec B_exec;
then:
allow B B_exec:file <permissions>;
will satisfy the bounds constraint iff:
allow A A_exec:file <permissions>;
is also allowed in policy.
This is essentially the same as #1; it is merely included as
an example of dealing with object types related to a bounded domain
in a manner that satisfies the bounds relationship. Note that
this approach is preferable to leaving B_exec unbounded and having:
allow A B_exec:file <permissions>;
in policy because that would allow B's entrypoints to be used to
enter A. Similarly for _tmp or other related types.
3. If we have:
typebounds A B;
and an unbounded type T, then:
allow B T:file <permissions>;
will satisfy the bounds constraint iff:
allow A T:file <permissions>;
is allowed in policy.
The old logic would have been identical for this example.
4. If we have:
typebounds A B;
and an unbounded domain D, then:
allow D B:unix_stream_socket <permissions>;
is not subject to any bounds constraints under the new logic
because D is not bounded. This is desirable so that we can
allow a domain to e.g. connectto a child domain without having
to allow it to do the same to its parent.
The old logic would have required:
allow D A:unix_stream_socket <permissions>;
to also be allowed in policy.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: re-wrapped description to appease checkpatch.pl]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2016-05-23 21:54:11 +07:00
|
|
|
tclass, masked, "bounds");
|
2008-08-28 14:35:57 +07:00
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
2015-07-11 04:19:56 +07:00
|
|
|
* flag which drivers have permissions
|
|
|
|
* only looking for ioctl based extended permssions
|
|
|
|
*/
|
|
|
|
void services_compute_xperms_drivers(
|
|
|
|
struct extended_perms *xperms,
|
|
|
|
struct avtab_node *node)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
|
|
|
|
/* if one or more driver has all permissions allowed */
|
|
|
|
for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
|
|
|
|
xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
|
|
|
|
} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
|
|
|
|
/* if allowing permissions within a driver */
|
|
|
|
security_xperm_set(xperms->drivers.p,
|
|
|
|
node->datum.u.xperms->driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If no ioctl commands are allowed, ignore auditallow and auditdeny */
|
|
|
|
if (node->key.specified & AVTAB_XPERMS_ALLOWED)
|
|
|
|
xperms->len = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute access vectors and extended permissions based on a context
|
|
|
|
* structure pair for the permissions in a particular class.
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
static void context_struct_compute_av(struct policydb *policydb,
|
|
|
|
struct context *scontext,
|
|
|
|
struct context *tcontext,
|
|
|
|
u16 tclass,
|
|
|
|
struct av_decision *avd,
|
|
|
|
struct extended_perms *xperms)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct constraint_node *constraint;
|
|
|
|
struct role_allow *ra;
|
|
|
|
struct avtab_key avkey;
|
2005-09-04 05:55:16 +07:00
|
|
|
struct avtab_node *node;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct class_datum *tclass_datum;
|
2005-09-04 05:55:16 +07:00
|
|
|
struct ebitmap *sattr, *tattr;
|
|
|
|
struct ebitmap_node *snode, *tnode;
|
|
|
|
unsigned int i, j;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
avd->allowed = 0;
|
|
|
|
avd->auditallow = 0;
|
|
|
|
avd->auditdeny = 0xffffffff;
|
2015-07-11 04:19:56 +07:00
|
|
|
if (xperms) {
|
|
|
|
memset(&xperms->drivers, 0, sizeof(xperms->drivers));
|
|
|
|
xperms->len = 0;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
if (printk_ratelimit())
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_warn("SELinux: Invalid class %hu\n", tclass);
|
2010-01-15 05:28:10 +07:00
|
|
|
return;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
}
|
2007-09-22 01:37:10 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
tclass_datum = policydb->class_val_to_struct[tclass - 1];
|
2007-09-22 01:37:10 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* If a specific type enforcement rule was defined for
|
|
|
|
* this permission check, then use it.
|
|
|
|
*/
|
|
|
|
avkey.target_class = tclass;
|
2015-07-11 04:19:56 +07:00
|
|
|
avkey.specified = AVTAB_AV | AVTAB_XPERMS;
|
2019-03-12 13:31:10 +07:00
|
|
|
sattr = &policydb->type_attr_map_array[scontext->type - 1];
|
|
|
|
tattr = &policydb->type_attr_map_array[tcontext->type - 1];
|
SELinux: improve performance when AVC misses.
* We add ebitmap_for_each_positive_bit() which enables to walk on
any positive bit on the given ebitmap, to improve its performance
using common bit-operations defined in linux/bitops.h.
In the previous version, this logic was implemented using a combination
of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
in performance aspect.
This logic is most frequestly used to compute a new AVC entry,
so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get
suitable for using find_next_bit() which is fasted than iteration of
shift and logical operation, and to maximize memory usage allocated
from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation
in ss/service.c and ss/mls.c. Some of related implementation are
changed, however, there is no incompatibility with the previous
version.
* The width of any new line are less or equal than 80-chars.
The following benchmark shows the effect of this patch, when we
access many files which have different security context one after
another. The number is more than /selinux/avc/cache_threshold, so
any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s]
STD: 0.265 0.019
------------------------------------------
1st: 22.558 [s] 8.786 [s]
2nd: 22.458 [s] 8.750 [s]
3rd: 22.478 [s] 8.754 [s]
4th: 22.724 [s] 8.745 [s]
5th: 22.918 [s] 8.748 [s]
6th: 22.905 [s] 8.764 [s]
7th: 23.238 [s] 8.726 [s]
8th: 22.822 [s] 8.729 [s]
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2007-09-29 00:20:55 +07:00
|
|
|
ebitmap_for_each_positive_bit(sattr, snode, i) {
|
|
|
|
ebitmap_for_each_positive_bit(tattr, tnode, j) {
|
2005-09-04 05:55:16 +07:00
|
|
|
avkey.source_type = i + 1;
|
|
|
|
avkey.target_type = j + 1;
|
2018-03-02 06:48:02 +07:00
|
|
|
for (node = avtab_search_node(&policydb->te_avtab,
|
|
|
|
&avkey);
|
2008-08-07 07:18:20 +07:00
|
|
|
node;
|
2005-09-04 05:55:16 +07:00
|
|
|
node = avtab_search_node_next(node, avkey.specified)) {
|
|
|
|
if (node->key.specified == AVTAB_ALLOWED)
|
2015-07-11 04:19:56 +07:00
|
|
|
avd->allowed |= node->datum.u.data;
|
2005-09-04 05:55:16 +07:00
|
|
|
else if (node->key.specified == AVTAB_AUDITALLOW)
|
2015-07-11 04:19:56 +07:00
|
|
|
avd->auditallow |= node->datum.u.data;
|
2005-09-04 05:55:16 +07:00
|
|
|
else if (node->key.specified == AVTAB_AUDITDENY)
|
2015-07-11 04:19:56 +07:00
|
|
|
avd->auditdeny &= node->datum.u.data;
|
|
|
|
else if (xperms && (node->key.specified & AVTAB_XPERMS))
|
|
|
|
services_compute_xperms_drivers(xperms, node);
|
2005-09-04 05:55:16 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2005-09-04 05:55:16 +07:00
|
|
|
/* Check conditional av table for additional permissions */
|
2018-03-02 06:48:02 +07:00
|
|
|
cond_compute_av(&policydb->te_cond_avtab, &avkey,
|
2015-07-11 04:19:56 +07:00
|
|
|
avd, xperms);
|
2005-09-04 05:55:16 +07:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove any permissions prohibited by a constraint (this includes
|
|
|
|
* the MLS policy).
|
|
|
|
*/
|
|
|
|
constraint = tclass_datum->constraints;
|
|
|
|
while (constraint) {
|
|
|
|
if ((constraint->permissions & (avd->allowed)) &&
|
2018-03-02 06:48:02 +07:00
|
|
|
!constraint_expr_eval(policydb, scontext, tcontext, NULL,
|
2005-04-17 05:20:36 +07:00
|
|
|
constraint->expr)) {
|
2009-06-18 15:30:07 +07:00
|
|
|
avd->allowed &= ~(constraint->permissions);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
constraint = constraint->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If checking process transition permission and the
|
|
|
|
* role is changing, then check the (current_role, new_role)
|
|
|
|
* pair.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
if (tclass == policydb->process_class &&
|
|
|
|
(avd->allowed & policydb->process_trans_perms) &&
|
2005-04-17 05:20:36 +07:00
|
|
|
scontext->role != tcontext->role) {
|
2018-03-02 06:48:02 +07:00
|
|
|
for (ra = policydb->role_allow; ra; ra = ra->next) {
|
2005-04-17 05:20:36 +07:00
|
|
|
if (scontext->role == ra->role &&
|
|
|
|
tcontext->role == ra->new_role)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!ra)
|
2018-03-02 06:48:02 +07:00
|
|
|
avd->allowed &= ~policydb->process_trans_perms;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2008-08-28 14:35:57 +07:00
|
|
|
/*
|
|
|
|
* If the given source and target types have boundary
|
|
|
|
* constraint, lazy checks have to mask any violated
|
|
|
|
* permission and notice it to userspace via audit.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
type_attribute_bounds_av(policydb, scontext, tcontext,
|
2010-01-15 05:28:10 +07:00
|
|
|
tclass, avd);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static int security_validtrans_handle_fail(struct selinux_state *state,
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy,
|
|
|
|
struct sidtab_entry *oentry,
|
|
|
|
struct sidtab_entry *nentry,
|
|
|
|
struct sidtab_entry *tentry,
|
|
|
|
u16 tclass)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct policydb *p = &policy->policydb;
|
|
|
|
struct sidtab *sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
char *o = NULL, *n = NULL, *t = NULL;
|
|
|
|
u32 olen, nlen, tlen;
|
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
if (sidtab_entry_to_string(p, sidtab, oentry, &o, &olen))
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
2019-11-26 20:57:00 +07:00
|
|
|
if (sidtab_entry_to_string(p, sidtab, nentry, &n, &nlen))
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
2019-11-26 20:57:00 +07:00
|
|
|
if (sidtab_entry_to_string(p, sidtab, tentry, &t, &tlen))
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
2018-05-13 08:58:20 +07:00
|
|
|
audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
2014-09-19 07:47:48 +07:00
|
|
|
"op=security_validate_transition seresult=denied"
|
2008-04-19 04:38:33 +07:00
|
|
|
" oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
|
2018-03-02 06:48:02 +07:00
|
|
|
o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
|
2005-04-17 05:20:36 +07:00
|
|
|
out:
|
|
|
|
kfree(o);
|
|
|
|
kfree(n);
|
|
|
|
kfree(t);
|
|
|
|
|
2018-03-02 05:38:30 +07:00
|
|
|
if (!enforcing_enabled(state))
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static int security_compute_validatetrans(struct selinux_state *state,
|
|
|
|
u32 oldsid, u32 newsid, u32 tasksid,
|
2015-12-24 23:09:41 +07:00
|
|
|
u16 orig_tclass, bool user)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2019-11-26 20:57:00 +07:00
|
|
|
struct sidtab_entry *oentry;
|
|
|
|
struct sidtab_entry *nentry;
|
|
|
|
struct sidtab_entry *tentry;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct class_datum *tclass_datum;
|
|
|
|
struct constraint_node *constraint;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
u16 tclass;
|
2005-04-17 05:20:36 +07:00
|
|
|
int rc = 0;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state))
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
2018-03-02 06:48:02 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2015-12-24 23:09:41 +07:00
|
|
|
if (!user)
|
2020-08-20 02:45:16 +07:00
|
|
|
tclass = unmap_class(&policy->map, orig_tclass);
|
2015-12-24 23:09:41 +07:00
|
|
|
else
|
|
|
|
tclass = orig_tclass;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
if (!tclass || tclass > policydb->p_classes.nprim) {
|
2005-04-17 05:20:36 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
2018-03-02 06:48:02 +07:00
|
|
|
tclass_datum = policydb->class_val_to_struct[tclass - 1];
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
oentry = sidtab_search_entry(sidtab, oldsid);
|
|
|
|
if (!oentry) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, oldsid);
|
2005-04-17 05:20:36 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
nentry = sidtab_search_entry(sidtab, newsid);
|
|
|
|
if (!nentry) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, newsid);
|
2005-04-17 05:20:36 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
tentry = sidtab_search_entry(sidtab, tasksid);
|
|
|
|
if (!tentry) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, tasksid);
|
2005-04-17 05:20:36 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
constraint = tclass_datum->validatetrans;
|
|
|
|
while (constraint) {
|
2019-11-26 20:57:00 +07:00
|
|
|
if (!constraint_expr_eval(policydb, &oentry->context,
|
|
|
|
&nentry->context, &tentry->context,
|
|
|
|
constraint->expr)) {
|
2015-12-24 23:09:41 +07:00
|
|
|
if (user)
|
|
|
|
rc = -EPERM;
|
|
|
|
else
|
2018-03-02 06:48:02 +07:00
|
|
|
rc = security_validtrans_handle_fail(state,
|
2020-08-20 02:45:16 +07:00
|
|
|
policy,
|
|
|
|
oentry,
|
|
|
|
nentry,
|
|
|
|
tentry,
|
|
|
|
tclass);
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
constraint = constraint->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2005-04-17 05:20:36 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_validate_transition_user(struct selinux_state *state,
|
|
|
|
u32 oldsid, u32 newsid, u32 tasksid,
|
|
|
|
u16 tclass)
|
2015-12-24 23:09:41 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_compute_validatetrans(state, oldsid, newsid, tasksid,
|
|
|
|
tclass, true);
|
2015-12-24 23:09:41 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_validate_transition(struct selinux_state *state,
|
|
|
|
u32 oldsid, u32 newsid, u32 tasksid,
|
2015-12-24 23:09:41 +07:00
|
|
|
u16 orig_tclass)
|
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_compute_validatetrans(state, oldsid, newsid, tasksid,
|
|
|
|
orig_tclass, false);
|
2015-12-24 23:09:41 +07:00
|
|
|
}
|
|
|
|
|
2008-08-28 14:35:57 +07:00
|
|
|
/*
|
|
|
|
* security_bounded_transition - check whether the given
|
|
|
|
* transition is directed to bounded, or not.
|
|
|
|
* It returns 0, if @newsid is bounded by @oldsid.
|
|
|
|
* Otherwise, it returns error code.
|
|
|
|
*
|
|
|
|
* @oldsid : current security identifier
|
|
|
|
* @newsid : destinated security identifier
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_bounded_transition(struct selinux_state *state,
|
|
|
|
u32 old_sid, u32 new_sid)
|
2008-08-28 14:35:57 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2019-11-26 20:57:00 +07:00
|
|
|
struct sidtab_entry *old_entry, *new_entry;
|
2008-08-28 14:35:57 +07:00
|
|
|
struct type_datum *type;
|
|
|
|
int index;
|
2010-11-23 23:40:08 +07:00
|
|
|
int rc;
|
2008-08-28 14:35:57 +07:00
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state))
|
2017-12-06 05:17:43 +07:00
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2008-08-28 14:35:57 +07:00
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2019-11-26 20:57:00 +07:00
|
|
|
old_entry = sidtab_search_entry(sidtab, old_sid);
|
|
|
|
if (!old_entry) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %u\n",
|
2008-08-28 14:35:57 +07:00
|
|
|
__func__, old_sid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2019-11-26 20:57:00 +07:00
|
|
|
new_entry = sidtab_search_entry(sidtab, new_sid);
|
|
|
|
if (!new_entry) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %u\n",
|
2008-08-28 14:35:57 +07:00
|
|
|
__func__, new_sid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 22:09:05 +07:00
|
|
|
/* type/domain unchanged */
|
2019-11-26 20:57:00 +07:00
|
|
|
if (old_entry->context.type == new_entry->context.type)
|
2008-08-28 14:35:57 +07:00
|
|
|
goto out;
|
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
index = new_entry->context.type;
|
2008-08-28 14:35:57 +07:00
|
|
|
while (true) {
|
2019-07-29 15:41:17 +07:00
|
|
|
type = policydb->type_val_to_struct[index - 1];
|
2008-08-28 14:35:57 +07:00
|
|
|
BUG_ON(!type);
|
|
|
|
|
|
|
|
/* not bounded anymore */
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EPERM;
|
|
|
|
if (!type->bounds)
|
2008-08-28 14:35:57 +07:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* @newsid is bounded by @oldsid */
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
2019-11-26 20:57:00 +07:00
|
|
|
if (type->bounds == old_entry->context.type)
|
2008-08-28 14:35:57 +07:00
|
|
|
break;
|
2010-11-23 23:40:08 +07:00
|
|
|
|
2008-08-28 14:35:57 +07:00
|
|
|
index = type->bounds;
|
|
|
|
}
|
2009-06-18 15:26:13 +07:00
|
|
|
|
|
|
|
if (rc) {
|
|
|
|
char *old_name = NULL;
|
|
|
|
char *new_name = NULL;
|
2010-02-16 13:29:06 +07:00
|
|
|
u32 length;
|
2009-06-18 15:26:13 +07:00
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
if (!sidtab_entry_to_string(policydb, sidtab, old_entry,
|
|
|
|
&old_name, &length) &&
|
|
|
|
!sidtab_entry_to_string(policydb, sidtab, new_entry,
|
|
|
|
&new_name, &length)) {
|
2018-05-13 08:58:20 +07:00
|
|
|
audit_log(audit_context(),
|
2009-06-18 15:26:13 +07:00
|
|
|
GFP_ATOMIC, AUDIT_SELINUX_ERR,
|
|
|
|
"op=security_bounded_transition "
|
2014-09-19 07:47:48 +07:00
|
|
|
"seresult=denied "
|
2009-06-18 15:26:13 +07:00
|
|
|
"oldcontext=%s newcontext=%s",
|
|
|
|
old_name, new_name);
|
|
|
|
}
|
|
|
|
kfree(new_name);
|
|
|
|
kfree(old_name);
|
|
|
|
}
|
2008-08-28 14:35:57 +07:00
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2008-08-28 14:35:57 +07:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
static void avd_init(struct selinux_policy *policy, struct av_decision *avd)
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
{
|
2010-01-15 05:28:10 +07:00
|
|
|
avd->allowed = 0;
|
|
|
|
avd->auditallow = 0;
|
|
|
|
avd->auditdeny = 0xffffffff;
|
2020-08-20 02:45:16 +07:00
|
|
|
if (policy)
|
|
|
|
avd->seqno = policy->latest_granting;
|
|
|
|
else
|
|
|
|
avd->seqno = 0;
|
2010-01-15 05:28:10 +07:00
|
|
|
avd->flags = 0;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
}
|
|
|
|
|
2015-07-11 04:19:56 +07:00
|
|
|
void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
|
|
|
|
struct avtab_node *node)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
|
|
|
|
if (xpermd->driver != node->datum.u.xperms->driver)
|
|
|
|
return;
|
|
|
|
} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
|
|
|
|
if (!security_xperm_test(node->datum.u.xperms->perms.p,
|
|
|
|
xpermd->driver))
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
|
|
|
|
xpermd->used |= XPERMS_ALLOWED;
|
|
|
|
if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
|
|
|
|
memset(xpermd->allowed->p, 0xff,
|
|
|
|
sizeof(xpermd->allowed->p));
|
|
|
|
}
|
|
|
|
if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
|
|
|
|
for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
|
|
|
|
xpermd->allowed->p[i] |=
|
|
|
|
node->datum.u.xperms->perms.p[i];
|
|
|
|
}
|
|
|
|
} else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
|
|
|
|
xpermd->used |= XPERMS_AUDITALLOW;
|
|
|
|
if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
|
|
|
|
memset(xpermd->auditallow->p, 0xff,
|
|
|
|
sizeof(xpermd->auditallow->p));
|
|
|
|
}
|
|
|
|
if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
|
|
|
|
for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
|
|
|
|
xpermd->auditallow->p[i] |=
|
|
|
|
node->datum.u.xperms->perms.p[i];
|
|
|
|
}
|
|
|
|
} else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
|
|
|
|
xpermd->used |= XPERMS_DONTAUDIT;
|
|
|
|
if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
|
|
|
|
memset(xpermd->dontaudit->p, 0xff,
|
|
|
|
sizeof(xpermd->dontaudit->p));
|
|
|
|
}
|
|
|
|
if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
|
|
|
|
for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
|
|
|
|
xpermd->dontaudit->p[i] |=
|
|
|
|
node->datum.u.xperms->perms.p[i];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
void security_compute_xperms_decision(struct selinux_state *state,
|
|
|
|
u32 ssid,
|
|
|
|
u32 tsid,
|
|
|
|
u16 orig_tclass,
|
|
|
|
u8 driver,
|
|
|
|
struct extended_perms_decision *xpermd)
|
2015-07-11 04:19:56 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2015-07-11 04:19:56 +07:00
|
|
|
u16 tclass;
|
|
|
|
struct context *scontext, *tcontext;
|
|
|
|
struct avtab_key avkey;
|
|
|
|
struct avtab_node *node;
|
|
|
|
struct ebitmap *sattr, *tattr;
|
|
|
|
struct ebitmap_node *snode, *tnode;
|
|
|
|
unsigned int i, j;
|
|
|
|
|
|
|
|
xpermd->driver = driver;
|
|
|
|
xpermd->used = 0;
|
|
|
|
memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
|
|
|
|
memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
|
|
|
|
memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state))
|
2015-07-11 04:19:56 +07:00
|
|
|
goto allow;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2018-03-02 06:48:02 +07:00
|
|
|
|
|
|
|
scontext = sidtab_search(sidtab, ssid);
|
2015-07-11 04:19:56 +07:00
|
|
|
if (!scontext) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2015-07-11 04:19:56 +07:00
|
|
|
__func__, ssid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
tcontext = sidtab_search(sidtab, tsid);
|
2015-07-11 04:19:56 +07:00
|
|
|
if (!tcontext) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2015-07-11 04:19:56 +07:00
|
|
|
__func__, tsid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
tclass = unmap_class(&policy->map, orig_tclass);
|
2015-07-11 04:19:56 +07:00
|
|
|
if (unlikely(orig_tclass && !tclass)) {
|
2018-03-02 06:48:02 +07:00
|
|
|
if (policydb->allow_unknown)
|
2015-07-11 04:19:56 +07:00
|
|
|
goto allow;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
|
2015-07-11 04:19:56 +07:00
|
|
|
pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
avkey.target_class = tclass;
|
|
|
|
avkey.specified = AVTAB_XPERMS;
|
2019-03-12 13:31:10 +07:00
|
|
|
sattr = &policydb->type_attr_map_array[scontext->type - 1];
|
|
|
|
tattr = &policydb->type_attr_map_array[tcontext->type - 1];
|
2015-07-11 04:19:56 +07:00
|
|
|
ebitmap_for_each_positive_bit(sattr, snode, i) {
|
|
|
|
ebitmap_for_each_positive_bit(tattr, tnode, j) {
|
|
|
|
avkey.source_type = i + 1;
|
|
|
|
avkey.target_type = j + 1;
|
2018-03-02 06:48:02 +07:00
|
|
|
for (node = avtab_search_node(&policydb->te_avtab,
|
|
|
|
&avkey);
|
2015-07-11 04:19:56 +07:00
|
|
|
node;
|
|
|
|
node = avtab_search_node_next(node, avkey.specified))
|
|
|
|
services_compute_xperms_decision(xpermd, node);
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
cond_compute_xperms(&policydb->te_cond_avtab,
|
2015-07-11 04:19:56 +07:00
|
|
|
&avkey, xpermd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2015-07-11 04:19:56 +07:00
|
|
|
return;
|
|
|
|
allow:
|
|
|
|
memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
|
|
|
|
goto out;
|
|
|
|
}
|
2010-01-15 05:28:10 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/**
|
|
|
|
* security_compute_av - Compute access vector decisions.
|
|
|
|
* @ssid: source security identifier
|
|
|
|
* @tsid: target security identifier
|
|
|
|
* @tclass: target security class
|
|
|
|
* @avd: access vector decisions
|
2015-07-11 04:19:56 +07:00
|
|
|
* @xperms: extended permissions
|
2005-04-17 05:20:36 +07:00
|
|
|
*
|
|
|
|
* Compute a set of access vector decisions based on the
|
|
|
|
* SID pair (@ssid, @tsid) for the permissions in @tclass.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
void security_compute_av(struct selinux_state *state,
|
|
|
|
u32 ssid,
|
2010-01-15 05:28:10 +07:00
|
|
|
u32 tsid,
|
|
|
|
u16 orig_tclass,
|
2015-07-11 04:19:56 +07:00
|
|
|
struct av_decision *avd,
|
|
|
|
struct extended_perms *xperms)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
u16 tclass;
|
2010-01-15 05:28:10 +07:00
|
|
|
struct context *scontext = NULL, *tcontext = NULL;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
avd_init(policy, avd);
|
2015-07-11 04:19:56 +07:00
|
|
|
xperms->len = 0;
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state))
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
goto allow;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2018-03-02 06:48:02 +07:00
|
|
|
|
|
|
|
scontext = sidtab_search(sidtab, ssid);
|
2010-01-15 05:28:10 +07:00
|
|
|
if (!scontext) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2010-01-15 05:28:10 +07:00
|
|
|
__func__, ssid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* permissive domain? */
|
2018-03-02 06:48:02 +07:00
|
|
|
if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
|
2010-01-15 05:28:10 +07:00
|
|
|
avd->flags |= AVD_FLAGS_PERMISSIVE;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
tcontext = sidtab_search(sidtab, tsid);
|
2010-01-15 05:28:10 +07:00
|
|
|
if (!tcontext) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2010-01-15 05:28:10 +07:00
|
|
|
__func__, tsid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
tclass = unmap_class(&policy->map, orig_tclass);
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
if (unlikely(orig_tclass && !tclass)) {
|
2018-03-02 06:48:02 +07:00
|
|
|
if (policydb->allow_unknown)
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
goto allow;
|
2009-10-19 21:08:50 +07:00
|
|
|
goto out;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
}
|
2018-03-02 06:48:02 +07:00
|
|
|
context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
|
|
|
|
xperms);
|
2020-08-20 02:45:16 +07:00
|
|
|
map_decision(&policy->map, orig_tclass, avd,
|
2018-03-02 06:48:02 +07:00
|
|
|
policydb->allow_unknown);
|
2009-10-19 21:08:50 +07:00
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2010-01-15 05:28:10 +07:00
|
|
|
return;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
allow:
|
|
|
|
avd->allowed = 0xffffffff;
|
2009-10-19 21:08:50 +07:00
|
|
|
goto out;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
void security_compute_av_user(struct selinux_state *state,
|
|
|
|
u32 ssid,
|
2010-01-15 05:28:10 +07:00
|
|
|
u32 tsid,
|
|
|
|
u16 tclass,
|
|
|
|
struct av_decision *avd)
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2010-01-15 05:28:10 +07:00
|
|
|
struct context *scontext = NULL, *tcontext = NULL;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
avd_init(policy, avd);
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state))
|
2010-01-15 05:28:10 +07:00
|
|
|
goto allow;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2018-03-02 06:48:02 +07:00
|
|
|
|
|
|
|
scontext = sidtab_search(sidtab, ssid);
|
2010-01-15 05:28:10 +07:00
|
|
|
if (!scontext) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2010-01-15 05:28:10 +07:00
|
|
|
__func__, ssid);
|
|
|
|
goto out;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2010-01-15 05:28:10 +07:00
|
|
|
/* permissive domain? */
|
2018-03-02 06:48:02 +07:00
|
|
|
if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
|
2010-01-15 05:28:10 +07:00
|
|
|
avd->flags |= AVD_FLAGS_PERMISSIVE;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
tcontext = sidtab_search(sidtab, tsid);
|
2010-01-15 05:28:10 +07:00
|
|
|
if (!tcontext) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2010-01-15 05:28:10 +07:00
|
|
|
__func__, tsid);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlikely(!tclass)) {
|
2018-03-02 06:48:02 +07:00
|
|
|
if (policydb->allow_unknown)
|
2010-01-15 05:28:10 +07:00
|
|
|
goto allow;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
|
|
|
|
NULL);
|
2010-01-15 05:28:10 +07:00
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2010-01-15 05:28:10 +07:00
|
|
|
return;
|
|
|
|
allow:
|
|
|
|
avd->allowed = 0xffffffff;
|
|
|
|
goto out;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write the security context string representation of
|
|
|
|
* the context structure `context' into a dynamically
|
|
|
|
* allocated string of the correct size. Set `*scontext'
|
|
|
|
* to point to this string and set `*scontext_len' to
|
|
|
|
* the length of the string.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
static int context_struct_to_string(struct policydb *p,
|
|
|
|
struct context *context,
|
|
|
|
char **scontext, u32 *scontext_len)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
char *scontextp;
|
|
|
|
|
2010-10-14 03:24:48 +07:00
|
|
|
if (scontext)
|
|
|
|
*scontext = NULL;
|
2005-04-17 05:20:36 +07:00
|
|
|
*scontext_len = 0;
|
|
|
|
|
2008-05-08 00:03:20 +07:00
|
|
|
if (context->len) {
|
|
|
|
*scontext_len = context->len;
|
2012-04-05 00:46:36 +07:00
|
|
|
if (scontext) {
|
|
|
|
*scontext = kstrdup(context->str, GFP_ATOMIC);
|
|
|
|
if (!(*scontext))
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2008-05-08 00:03:20 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Compute the size of the context. */
|
2018-03-02 06:48:02 +07:00
|
|
|
*scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
|
|
|
|
*scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
|
|
|
|
*scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
|
|
|
|
*scontext_len += mls_compute_context_len(p, context);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2010-10-14 03:24:48 +07:00
|
|
|
if (!scontext)
|
|
|
|
return 0;
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Allocate space for the context; caller must free this space. */
|
|
|
|
scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
|
2008-04-19 04:38:33 +07:00
|
|
|
if (!scontextp)
|
2005-04-17 05:20:36 +07:00
|
|
|
return -ENOMEM;
|
|
|
|
*scontext = scontextp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the user name, role name and type name into the context.
|
|
|
|
*/
|
2015-10-22 04:44:27 +07:00
|
|
|
scontextp += sprintf(scontextp, "%s:%s:%s",
|
2018-03-02 06:48:02 +07:00
|
|
|
sym_name(p, SYM_USERS, context->user - 1),
|
|
|
|
sym_name(p, SYM_ROLES, context->role - 1),
|
|
|
|
sym_name(p, SYM_TYPES, context->type - 1));
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
mls_sid_to_context(p, context, &scontextp);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
*scontextp = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
static int sidtab_entry_to_string(struct policydb *p,
|
|
|
|
struct sidtab *sidtab,
|
|
|
|
struct sidtab_entry *entry,
|
|
|
|
char **scontext, u32 *scontext_len)
|
|
|
|
{
|
|
|
|
int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len);
|
|
|
|
|
|
|
|
if (rc != -ENOENT)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = context_struct_to_string(p, &entry->context, scontext,
|
|
|
|
scontext_len);
|
|
|
|
if (!rc && scontext)
|
|
|
|
sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#include "initial_sid_to_string.h"
|
|
|
|
|
2019-11-22 16:33:06 +07:00
|
|
|
int security_sidtab_hash_stats(struct selinux_state *state, char *page)
|
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2019-11-22 16:33:06 +07:00
|
|
|
int rc;
|
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
2019-12-24 04:38:36 +07:00
|
|
|
pr_err("SELinux: %s: called before initial load_policy\n",
|
|
|
|
__func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
rc = sidtab_hash_stats(policy->sidtab, page);
|
|
|
|
rcu_read_unlock();
|
2019-11-22 16:33:06 +07:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-04-04 21:11:29 +07:00
|
|
|
const char *security_get_initial_sid_context(u32 sid)
|
|
|
|
{
|
|
|
|
if (unlikely(sid > SECINITSID_NUM))
|
|
|
|
return NULL;
|
|
|
|
return initial_sid_to_string[sid];
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static int security_sid_to_context_core(struct selinux_state *state,
|
|
|
|
u32 sid, char **scontext,
|
2019-01-25 17:06:51 +07:00
|
|
|
u32 *scontext_len, int force,
|
|
|
|
int only_invalid)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2019-11-26 20:57:00 +07:00
|
|
|
struct sidtab_entry *entry;
|
2005-04-17 05:20:36 +07:00
|
|
|
int rc = 0;
|
|
|
|
|
2010-10-14 03:24:48 +07:00
|
|
|
if (scontext)
|
|
|
|
*scontext = NULL;
|
2007-02-27 00:02:34 +07:00
|
|
|
*scontext_len = 0;
|
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
2005-04-17 05:20:36 +07:00
|
|
|
if (sid <= SECINITSID_NUM) {
|
|
|
|
char *scontextp;
|
selinux: remove unused initial SIDs and improve handling
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.
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).
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 <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
2020-02-24 23:10:23 +07:00
|
|
|
const char *s = initial_sid_to_string[sid];
|
2005-04-17 05:20:36 +07:00
|
|
|
|
selinux: remove unused initial SIDs and improve handling
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.
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).
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 <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
2020-02-24 23:10:23 +07:00
|
|
|
if (!s)
|
|
|
|
return -EINVAL;
|
|
|
|
*scontext_len = strlen(s) + 1;
|
2010-10-14 03:24:48 +07:00
|
|
|
if (!scontext)
|
selinux: remove unused initial SIDs and improve handling
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.
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).
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 <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
2020-02-24 23:10:23 +07:00
|
|
|
return 0;
|
|
|
|
scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
|
|
|
|
if (!scontextp)
|
|
|
|
return -ENOMEM;
|
2005-04-17 05:20:36 +07:00
|
|
|
*scontext = scontextp;
|
selinux: remove unused initial SIDs and improve handling
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.
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).
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 <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
2020-02-24 23:10:23 +07:00
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: called before initial "
|
2008-04-17 22:52:44 +07:00
|
|
|
"load_policy on unknown SID %d\n", __func__, sid);
|
selinux: remove unused initial SIDs and improve handling
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.
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).
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 <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
2020-02-24 23:10:23 +07:00
|
|
|
return -EINVAL;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2019-11-26 20:57:00 +07:00
|
|
|
|
2008-05-08 00:03:20 +07:00
|
|
|
if (force)
|
2019-11-26 20:57:00 +07:00
|
|
|
entry = sidtab_search_entry_force(sidtab, sid);
|
2008-05-08 00:03:20 +07:00
|
|
|
else
|
2019-11-26 20:57:00 +07:00
|
|
|
entry = sidtab_search_entry(sidtab, sid);
|
|
|
|
if (!entry) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, sid);
|
2005-04-17 05:20:36 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
2019-11-26 20:57:00 +07:00
|
|
|
if (only_invalid && !entry->context.len)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext,
|
|
|
|
scontext_len);
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
out_unlock:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2005-04-17 05:20:36 +07:00
|
|
|
return rc;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-05-08 00:03:20 +07:00
|
|
|
/**
|
|
|
|
* security_sid_to_context - Obtain a context for a given SID.
|
|
|
|
* @sid: security identifier, SID
|
|
|
|
* @scontext: security context
|
|
|
|
* @scontext_len: length in bytes
|
|
|
|
*
|
|
|
|
* Write the string representation of the context associated with @sid
|
|
|
|
* into a dynamically allocated string of the correct size. Set @scontext
|
|
|
|
* to point to this string and set @scontext_len to the length of the string.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_sid_to_context(struct selinux_state *state,
|
|
|
|
u32 sid, char **scontext, u32 *scontext_len)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_sid_to_context_core(state, sid, scontext,
|
2019-01-25 17:06:51 +07:00
|
|
|
scontext_len, 0, 0);
|
2008-05-08 00:03:20 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_sid_to_context_force(struct selinux_state *state, u32 sid,
|
|
|
|
char **scontext, u32 *scontext_len)
|
2008-05-08 00:03:20 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_sid_to_context_core(state, sid, scontext,
|
2019-01-25 17:06:51 +07:00
|
|
|
scontext_len, 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* security_sid_to_context_inval - Obtain a context for a given SID if it
|
|
|
|
* is invalid.
|
|
|
|
* @sid: security identifier, SID
|
|
|
|
* @scontext: security context
|
|
|
|
* @scontext_len: length in bytes
|
|
|
|
*
|
|
|
|
* Write the string representation of the context associated with @sid
|
|
|
|
* into a dynamically allocated string of the correct size, but only if the
|
|
|
|
* context is invalid in the current policy. Set @scontext to point to
|
|
|
|
* this string (or NULL if the context is valid) and set @scontext_len to
|
|
|
|
* the length of the string (or 0 if the context is valid).
|
|
|
|
*/
|
|
|
|
int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
|
|
|
|
char **scontext, u32 *scontext_len)
|
|
|
|
{
|
|
|
|
return security_sid_to_context_core(state, sid, scontext,
|
|
|
|
scontext_len, 1, 1);
|
2008-05-08 00:03:20 +07:00
|
|
|
}
|
|
|
|
|
2008-05-14 21:33:55 +07:00
|
|
|
/*
|
|
|
|
* Caveat: Mutates scontext.
|
|
|
|
*/
|
2008-05-08 00:03:20 +07:00
|
|
|
static int string_to_context_struct(struct policydb *pol,
|
|
|
|
struct sidtab *sidtabp,
|
2008-05-14 21:33:55 +07:00
|
|
|
char *scontext,
|
2008-05-08 00:03:20 +07:00
|
|
|
struct context *ctx,
|
2008-05-14 21:33:55 +07:00
|
|
|
u32 def_sid)
|
2008-05-08 00:03:20 +07:00
|
|
|
{
|
2005-04-17 05:20:36 +07:00
|
|
|
struct role_datum *role;
|
|
|
|
struct type_datum *typdatum;
|
|
|
|
struct user_datum *usrdatum;
|
|
|
|
char *scontextp, *p, oldc;
|
|
|
|
int rc = 0;
|
|
|
|
|
2008-05-08 00:03:20 +07:00
|
|
|
context_init(ctx);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Parse the security context. */
|
|
|
|
|
|
|
|
rc = -EINVAL;
|
2008-05-14 21:33:55 +07:00
|
|
|
scontextp = (char *) scontext;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Extract the user. */
|
|
|
|
p = scontextp;
|
|
|
|
while (*p && *p != ':')
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (*p == 0)
|
2008-05-08 00:03:20 +07:00
|
|
|
goto out;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
2020-07-08 18:24:45 +07:00
|
|
|
usrdatum = symtab_search(&pol->p_users, scontextp);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (!usrdatum)
|
2008-05-08 00:03:20 +07:00
|
|
|
goto out;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-05-08 00:03:20 +07:00
|
|
|
ctx->user = usrdatum->value;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Extract role. */
|
|
|
|
scontextp = p;
|
|
|
|
while (*p && *p != ':')
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (*p == 0)
|
2008-05-08 00:03:20 +07:00
|
|
|
goto out;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
2020-07-08 18:24:45 +07:00
|
|
|
role = symtab_search(&pol->p_roles, scontextp);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (!role)
|
2008-05-08 00:03:20 +07:00
|
|
|
goto out;
|
|
|
|
ctx->role = role->value;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Extract type. */
|
|
|
|
scontextp = p;
|
|
|
|
while (*p && *p != ':')
|
|
|
|
p++;
|
|
|
|
oldc = *p;
|
|
|
|
*p++ = 0;
|
|
|
|
|
2020-07-08 18:24:45 +07:00
|
|
|
typdatum = symtab_search(&pol->p_types, scontextp);
|
2008-08-28 14:35:57 +07:00
|
|
|
if (!typdatum || typdatum->attribute)
|
2008-05-08 00:03:20 +07:00
|
|
|
goto out;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-05-08 00:03:20 +07:00
|
|
|
ctx->type = typdatum->value;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2018-08-07 04:19:32 +07:00
|
|
|
rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (rc)
|
2008-05-08 00:03:20 +07:00
|
|
|
goto out;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Check the validity of the new context. */
|
2018-08-07 04:19:32 +07:00
|
|
|
rc = -EINVAL;
|
2010-11-23 23:40:08 +07:00
|
|
|
if (!policydb_context_isvalid(pol, ctx))
|
2008-05-08 00:03:20 +07:00
|
|
|
goto out;
|
|
|
|
rc = 0;
|
|
|
|
out:
|
2008-09-03 22:49:47 +07:00
|
|
|
if (rc)
|
|
|
|
context_destroy(ctx);
|
2008-05-08 00:03:20 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static int security_context_to_sid_core(struct selinux_state *state,
|
|
|
|
const char *scontext, u32 scontext_len,
|
2008-05-08 00:03:20 +07:00
|
|
|
u32 *sid, u32 def_sid, gfp_t gfp_flags,
|
|
|
|
int force)
|
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2008-05-14 21:33:55 +07:00
|
|
|
char *scontext2, *str = NULL;
|
2008-05-08 00:03:20 +07:00
|
|
|
struct context context;
|
|
|
|
int rc = 0;
|
|
|
|
|
2014-01-30 23:26:59 +07:00
|
|
|
/* An empty security context is never valid. */
|
|
|
|
if (!scontext_len)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-11-29 06:51:12 +07:00
|
|
|
/* Copy the string to allow changes and ensure a NUL terminator */
|
|
|
|
scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
|
|
|
|
if (!scontext2)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
2008-05-08 00:03:20 +07:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 1; i < SECINITSID_NUM; i++) {
|
selinux: remove unused initial SIDs and improve handling
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.
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).
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 <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
2020-02-24 23:10:23 +07:00
|
|
|
const char *s = initial_sid_to_string[i];
|
|
|
|
|
|
|
|
if (s && !strcmp(s, scontext2)) {
|
2008-05-08 00:03:20 +07:00
|
|
|
*sid = i;
|
2017-11-29 06:51:12 +07:00
|
|
|
goto out;
|
2008-05-08 00:03:20 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*sid = SECINITSID_KERNEL;
|
2017-11-29 06:51:12 +07:00
|
|
|
goto out;
|
2008-05-08 00:03:20 +07:00
|
|
|
}
|
|
|
|
*sid = SECSID_NULL;
|
|
|
|
|
2008-05-14 21:33:55 +07:00
|
|
|
if (force) {
|
|
|
|
/* Save another copy for storing in uninterpreted form */
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOMEM;
|
2008-05-14 21:33:55 +07:00
|
|
|
str = kstrdup(scontext2, gfp_flags);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (!str)
|
|
|
|
goto out;
|
2008-05-14 21:33:55 +07:00
|
|
|
}
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2018-03-02 06:48:02 +07:00
|
|
|
rc = string_to_context_struct(policydb, sidtab, scontext2,
|
2018-08-07 04:19:32 +07:00
|
|
|
&context, def_sid);
|
2008-05-08 00:03:20 +07:00
|
|
|
if (rc == -EINVAL && force) {
|
2008-05-14 21:33:55 +07:00
|
|
|
context.str = str;
|
2018-05-25 15:31:39 +07:00
|
|
|
context.len = strlen(str) + 1;
|
2008-05-14 21:33:55 +07:00
|
|
|
str = NULL;
|
2008-05-08 00:03:20 +07:00
|
|
|
} else if (rc)
|
2010-11-23 23:40:08 +07:00
|
|
|
goto out_unlock;
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &context, sid);
|
2008-09-03 22:49:47 +07:00
|
|
|
context_destroy(&context);
|
2010-11-23 23:40:08 +07:00
|
|
|
out_unlock:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2010-11-23 23:40:08 +07:00
|
|
|
out:
|
2008-05-14 21:33:55 +07:00
|
|
|
kfree(scontext2);
|
|
|
|
kfree(str);
|
2005-04-17 05:20:36 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-07-28 15:07:37 +07:00
|
|
|
/**
|
|
|
|
* security_context_to_sid - Obtain a SID for a given security context.
|
|
|
|
* @scontext: security context
|
|
|
|
* @scontext_len: length in bytes
|
|
|
|
* @sid: security identifier, SID
|
2014-03-07 18:44:19 +07:00
|
|
|
* @gfp: context for the allocation
|
2005-07-28 15:07:37 +07:00
|
|
|
*
|
|
|
|
* Obtains a SID associated with the security context that
|
|
|
|
* has the string representation specified by @scontext.
|
|
|
|
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
|
|
|
|
* memory is available, or 0 on success.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_context_to_sid(struct selinux_state *state,
|
|
|
|
const char *scontext, u32 scontext_len, u32 *sid,
|
2014-03-07 18:44:19 +07:00
|
|
|
gfp_t gfp)
|
2005-07-28 15:07:37 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_context_to_sid_core(state, scontext, scontext_len,
|
2014-03-07 18:44:19 +07:00
|
|
|
sid, SECSID_NULL, gfp, 0);
|
2015-10-22 04:44:25 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_context_str_to_sid(struct selinux_state *state,
|
|
|
|
const char *scontext, u32 *sid, gfp_t gfp)
|
2015-10-22 04:44:25 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_context_to_sid(state, scontext, strlen(scontext),
|
|
|
|
sid, gfp);
|
2005-07-28 15:07:37 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* security_context_to_sid_default - Obtain a SID for a given security context,
|
|
|
|
* falling back to specified default if needed.
|
|
|
|
*
|
|
|
|
* @scontext: security context
|
|
|
|
* @scontext_len: length in bytes
|
|
|
|
* @sid: security identifier, SID
|
2007-07-31 14:39:19 +07:00
|
|
|
* @def_sid: default SID to assign on error
|
2005-07-28 15:07:37 +07:00
|
|
|
*
|
|
|
|
* Obtains a SID associated with the security context that
|
|
|
|
* has the string representation specified by @scontext.
|
|
|
|
* The default SID is passed to the MLS layer to be used to allow
|
|
|
|
* kernel labeling of the MLS field if the MLS field is not present
|
|
|
|
* (for upgrading to MLS without full relabel).
|
2008-05-08 00:03:20 +07:00
|
|
|
* Implicitly forces adding of the context even if it cannot be mapped yet.
|
2005-07-28 15:07:37 +07:00
|
|
|
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
|
|
|
|
* memory is available, or 0 on success.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_context_to_sid_default(struct selinux_state *state,
|
|
|
|
const char *scontext, u32 scontext_len,
|
2008-04-30 02:52:51 +07:00
|
|
|
u32 *sid, u32 def_sid, gfp_t gfp_flags)
|
2005-07-28 15:07:37 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_context_to_sid_core(state, scontext, scontext_len,
|
2008-05-08 00:03:20 +07:00
|
|
|
sid, def_sid, gfp_flags, 1);
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_context_to_sid_force(struct selinux_state *state,
|
|
|
|
const char *scontext, u32 scontext_len,
|
2008-05-08 00:03:20 +07:00
|
|
|
u32 *sid)
|
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_context_to_sid_core(state, scontext, scontext_len,
|
2008-05-08 00:03:20 +07:00
|
|
|
sid, SECSID_NULL, GFP_KERNEL, 1);
|
2005-07-28 15:07:37 +07:00
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
static int compute_sid_handle_invalid_context(
|
2018-03-02 06:48:02 +07:00
|
|
|
struct selinux_state *state,
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy,
|
2019-11-26 20:57:00 +07:00
|
|
|
struct sidtab_entry *sentry,
|
|
|
|
struct sidtab_entry *tentry,
|
2005-04-17 05:20:36 +07:00
|
|
|
u16 tclass,
|
|
|
|
struct context *newcontext)
|
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct policydb *policydb = &policy->policydb;
|
|
|
|
struct sidtab *sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
char *s = NULL, *t = NULL, *n = NULL;
|
|
|
|
u32 slen, tlen, nlen;
|
2019-06-27 23:48:01 +07:00
|
|
|
struct audit_buffer *ab;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen))
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
2019-11-26 20:57:00 +07:00
|
|
|
if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen))
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
2018-03-02 06:48:02 +07:00
|
|
|
if (context_struct_to_string(policydb, newcontext, &n, &nlen))
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
2019-06-27 23:48:01 +07:00
|
|
|
ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
|
|
|
|
audit_log_format(ab,
|
|
|
|
"op=security_compute_sid invalid_context=");
|
|
|
|
/* no need to record the NUL with untrusted strings */
|
|
|
|
audit_log_n_untrustedstring(ab, n, nlen - 1);
|
|
|
|
audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
|
|
|
|
s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
|
|
|
|
audit_log_end(ab);
|
2005-04-17 05:20:36 +07:00
|
|
|
out:
|
|
|
|
kfree(s);
|
|
|
|
kfree(t);
|
|
|
|
kfree(n);
|
2018-03-02 05:38:30 +07:00
|
|
|
if (!enforcing_enabled(state))
|
2005-04-17 05:20:36 +07:00
|
|
|
return 0;
|
|
|
|
return -EACCES;
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static void filename_compute_type(struct policydb *policydb,
|
|
|
|
struct context *newcontext,
|
2011-04-29 02:11:20 +07:00
|
|
|
u32 stype, u32 ttype, u16 tclass,
|
2011-04-01 21:39:26 +07:00
|
|
|
const char *objname)
|
SELinux: Use dentry name in new object labeling
Currently SELinux has rules which label new objects according to 3 criteria.
The label of the process creating the object, the label of the parent
directory, and the type of object (reg, dir, char, block, etc.) This patch
adds a 4th criteria, the dentry name, thus we can distinguish between
creating a file in an etc_t directory called shadow and one called motd.
There is no file globbing, regex parsing, or anything mystical. Either the
policy exactly (strcmp) matches the dentry name of the object or it doesn't.
This patch has no changes from today if policy does not implement the new
rules.
Signed-off-by: Eric Paris <eparis@redhat.com>
2011-02-01 23:05:40 +07:00
|
|
|
{
|
selinux: optimize storage of filename transitions
In these rules, each rule with the same (target type, target class,
filename) values is (in practice) always mapped to the same result type.
Therefore, it is much more efficient to group the rules by (ttype,
tclass, filename).
Thus, this patch drops the stype field from the key and changes the
datum to be a linked list of one or more structures that contain a
result type and an ebitmap of source types that map the given target to
the given result type under the given filename. The size of the hash
table is also incremented to 2048 to be more optimal for Fedora policy
(which currently has ~2500 unique (ttype, tclass, filename) tuples,
regardless of whether the 'unconfined' module is enabled).
Not only does this dramtically reduce memory usage when the policy
contains a lot of unconfined domains (ergo a lot of filename based
transitions), but it also slightly reduces memory usage of strongly
confined policies (modeled on Fedora policy with 'unconfined' module
disabled) and significantly reduces lookup times of these rules on
Fedora (roughly matches the performance of the rhashtable conversion
patch [1] posted recently to selinux@vger.kernel.org).
An obvious next step is to change binary policy format to match this
layout, so that disk space is also saved. However, since that requires
more work (including matching userspace changes) and this patch is
already beneficial on its own, I'm posting it separately.
Performance/memory usage comparison:
Kernel | Policy load | Policy load | Mem usage | Mem usage | openbench
| | (-unconfined) | | (-unconfined) | (createfiles)
-----------------|-------------|---------------|-----------|---------------|--------------
reference | 1,30s | 0,91s | 90MB | 77MB | 55 us/file
rhashtable patch | 0.98s | 0,85s | 85MB | 75MB | 38 us/file
this patch | 0,95s | 0,87s | 75MB | 75MB | 40 us/file
(Memory usage is measured after boot. With SELinux disabled the memory
usage was ~60MB on the same system.)
[1] https://lore.kernel.org/selinux/20200116213937.77795-1-dev@lynxeye.de/T/
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
2020-02-18 18:27:34 +07:00
|
|
|
struct filename_trans_key ft;
|
|
|
|
struct filename_trans_datum *datum;
|
2011-04-29 02:11:21 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Most filename trans rules are going to live in specific directories
|
|
|
|
* like /dev or /var/run. This bitmap will quickly skip rule searches
|
|
|
|
* if the ttype does not contain any rules.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
|
2011-04-29 02:11:21 +07:00
|
|
|
return;
|
|
|
|
|
2011-04-29 02:11:21 +07:00
|
|
|
ft.ttype = ttype;
|
|
|
|
ft.tclass = tclass;
|
|
|
|
ft.name = objname;
|
|
|
|
|
2020-07-10 02:19:51 +07:00
|
|
|
datum = policydb_filenametr_search(policydb, &ft);
|
selinux: optimize storage of filename transitions
In these rules, each rule with the same (target type, target class,
filename) values is (in practice) always mapped to the same result type.
Therefore, it is much more efficient to group the rules by (ttype,
tclass, filename).
Thus, this patch drops the stype field from the key and changes the
datum to be a linked list of one or more structures that contain a
result type and an ebitmap of source types that map the given target to
the given result type under the given filename. The size of the hash
table is also incremented to 2048 to be more optimal for Fedora policy
(which currently has ~2500 unique (ttype, tclass, filename) tuples,
regardless of whether the 'unconfined' module is enabled).
Not only does this dramtically reduce memory usage when the policy
contains a lot of unconfined domains (ergo a lot of filename based
transitions), but it also slightly reduces memory usage of strongly
confined policies (modeled on Fedora policy with 'unconfined' module
disabled) and significantly reduces lookup times of these rules on
Fedora (roughly matches the performance of the rhashtable conversion
patch [1] posted recently to selinux@vger.kernel.org).
An obvious next step is to change binary policy format to match this
layout, so that disk space is also saved. However, since that requires
more work (including matching userspace changes) and this patch is
already beneficial on its own, I'm posting it separately.
Performance/memory usage comparison:
Kernel | Policy load | Policy load | Mem usage | Mem usage | openbench
| | (-unconfined) | | (-unconfined) | (createfiles)
-----------------|-------------|---------------|-----------|---------------|--------------
reference | 1,30s | 0,91s | 90MB | 77MB | 55 us/file
rhashtable patch | 0.98s | 0,85s | 85MB | 75MB | 38 us/file
this patch | 0,95s | 0,87s | 75MB | 75MB | 40 us/file
(Memory usage is measured after boot. With SELinux disabled the memory
usage was ~60MB on the same system.)
[1] https://lore.kernel.org/selinux/20200116213937.77795-1-dev@lynxeye.de/T/
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
2020-02-18 18:27:34 +07:00
|
|
|
while (datum) {
|
|
|
|
if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
|
|
|
|
newcontext->type = datum->otype;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
datum = datum->next;
|
|
|
|
}
|
SELinux: Use dentry name in new object labeling
Currently SELinux has rules which label new objects according to 3 criteria.
The label of the process creating the object, the label of the parent
directory, and the type of object (reg, dir, char, block, etc.) This patch
adds a 4th criteria, the dentry name, thus we can distinguish between
creating a file in an etc_t directory called shadow and one called motd.
There is no file globbing, regex parsing, or anything mystical. Either the
policy exactly (strcmp) matches the dentry name of the object or it doesn't.
This patch has no changes from today if policy does not implement the new
rules.
Signed-off-by: Eric Paris <eparis@redhat.com>
2011-02-01 23:05:40 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static int security_compute_sid(struct selinux_state *state,
|
|
|
|
u32 ssid,
|
2005-04-17 05:20:36 +07:00
|
|
|
u32 tsid,
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
u16 orig_tclass,
|
2005-04-17 05:20:36 +07:00
|
|
|
u32 specified,
|
2011-04-01 21:39:26 +07:00
|
|
|
const char *objname,
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
u32 *out_sid,
|
|
|
|
bool kern)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2012-03-21 01:35:12 +07:00
|
|
|
struct class_datum *cladatum = NULL;
|
2019-11-26 20:57:00 +07:00
|
|
|
struct context *scontext, *tcontext, newcontext;
|
|
|
|
struct sidtab_entry *sentry, *tentry;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct avtab_key avkey;
|
|
|
|
struct avtab_datum *avdatum;
|
|
|
|
struct avtab_node *node;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
u16 tclass;
|
2005-04-17 05:20:36 +07:00
|
|
|
int rc = 0;
|
2011-03-02 12:32:33 +07:00
|
|
|
bool sock;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
switch (orig_tclass) {
|
|
|
|
case SECCLASS_PROCESS: /* kernel value */
|
2005-04-17 05:20:36 +07:00
|
|
|
*out_sid = ssid;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*out_sid = tsid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2006-07-30 17:03:18 +07:00
|
|
|
context_init(&newcontext);
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
policy = rcu_dereference(state->policy);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2011-03-02 12:32:33 +07:00
|
|
|
if (kern) {
|
2020-08-20 02:45:16 +07:00
|
|
|
tclass = unmap_class(&policy->map, orig_tclass);
|
2011-03-02 12:32:33 +07:00
|
|
|
sock = security_is_socket_class(orig_tclass);
|
|
|
|
} else {
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
tclass = orig_tclass;
|
2020-08-20 02:45:16 +07:00
|
|
|
sock = security_is_socket_class(map_class(&policy->map,
|
2018-03-02 06:48:02 +07:00
|
|
|
tclass));
|
2011-03-02 12:32:33 +07:00
|
|
|
}
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2018-03-02 06:48:02 +07:00
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
sentry = sidtab_search_entry(sidtab, ssid);
|
|
|
|
if (!sentry) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, ssid);
|
2005-04-17 05:20:36 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
2019-11-26 20:57:00 +07:00
|
|
|
tentry = sidtab_search_entry(sidtab, tsid);
|
|
|
|
if (!tentry) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, tsid);
|
2005-04-17 05:20:36 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
2019-11-26 20:57:00 +07:00
|
|
|
scontext = &sentry->context;
|
|
|
|
tcontext = &tentry->context;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
if (tclass && tclass <= policydb->p_classes.nprim)
|
|
|
|
cladatum = policydb->class_val_to_struct[tclass - 1];
|
2012-03-21 01:35:12 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Set the user identity. */
|
|
|
|
switch (specified) {
|
|
|
|
case AVTAB_TRANSITION:
|
|
|
|
case AVTAB_CHANGE:
|
2012-03-21 01:35:12 +07:00
|
|
|
if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
|
|
|
|
newcontext.user = tcontext->user;
|
|
|
|
} else {
|
|
|
|
/* notice this gets both DEFAULT_SOURCE and unset */
|
|
|
|
/* Use the process user identity. */
|
|
|
|
newcontext.user = scontext->user;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
case AVTAB_MEMBER:
|
|
|
|
/* Use the related object owner. */
|
|
|
|
newcontext.user = tcontext->user;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-03-21 01:35:12 +07:00
|
|
|
/* Set the role to default values. */
|
|
|
|
if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
|
2005-04-17 05:20:36 +07:00
|
|
|
newcontext.role = scontext->role;
|
2012-03-21 01:35:12 +07:00
|
|
|
} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
|
|
|
|
newcontext.role = tcontext->role;
|
|
|
|
} else {
|
2020-04-14 15:18:07 +07:00
|
|
|
if ((tclass == policydb->process_class) || sock)
|
2012-03-21 01:35:12 +07:00
|
|
|
newcontext.role = scontext->role;
|
|
|
|
else
|
|
|
|
newcontext.role = OBJECT_R_VAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the type to default values. */
|
2012-03-21 01:35:12 +07:00
|
|
|
if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
|
2005-04-17 05:20:36 +07:00
|
|
|
newcontext.type = scontext->type;
|
2012-03-21 01:35:12 +07:00
|
|
|
} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
|
2005-04-17 05:20:36 +07:00
|
|
|
newcontext.type = tcontext->type;
|
2012-03-21 01:35:12 +07:00
|
|
|
} else {
|
2020-04-14 15:18:07 +07:00
|
|
|
if ((tclass == policydb->process_class) || sock) {
|
2012-03-21 01:35:12 +07:00
|
|
|
/* Use the type of process. */
|
|
|
|
newcontext.type = scontext->type;
|
|
|
|
} else {
|
|
|
|
/* Use the type of the related object. */
|
|
|
|
newcontext.type = tcontext->type;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Look for a type transition/member/change rule. */
|
|
|
|
avkey.source_type = scontext->type;
|
|
|
|
avkey.target_type = tcontext->type;
|
|
|
|
avkey.target_class = tclass;
|
2005-09-04 05:55:16 +07:00
|
|
|
avkey.specified = specified;
|
2018-03-02 06:48:02 +07:00
|
|
|
avdatum = avtab_search(&policydb->te_avtab, &avkey);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* If no permanent rule, also check for enabled conditional rules */
|
2008-04-19 04:38:33 +07:00
|
|
|
if (!avdatum) {
|
2018-03-02 06:48:02 +07:00
|
|
|
node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
|
2008-08-07 07:18:20 +07:00
|
|
|
for (; node; node = avtab_search_node_next(node, specified)) {
|
2005-09-04 05:55:16 +07:00
|
|
|
if (node->key.specified & AVTAB_ENABLED) {
|
2005-04-17 05:20:36 +07:00
|
|
|
avdatum = &node->datum;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-04 05:55:16 +07:00
|
|
|
if (avdatum) {
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Use the type from the type transition/member/change rule. */
|
2015-07-11 04:19:56 +07:00
|
|
|
newcontext.type = avdatum->u.data;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2011-04-29 02:11:20 +07:00
|
|
|
/* if we have a objname this is a file trans check so check those rules */
|
2011-04-01 21:39:26 +07:00
|
|
|
if (objname)
|
2018-03-02 06:48:02 +07:00
|
|
|
filename_compute_type(policydb, &newcontext, scontext->type,
|
2011-04-01 21:39:26 +07:00
|
|
|
tcontext->type, tclass, objname);
|
SELinux: Use dentry name in new object labeling
Currently SELinux has rules which label new objects according to 3 criteria.
The label of the process creating the object, the label of the parent
directory, and the type of object (reg, dir, char, block, etc.) This patch
adds a 4th criteria, the dentry name, thus we can distinguish between
creating a file in an etc_t directory called shadow and one called motd.
There is no file globbing, regex parsing, or anything mystical. Either the
policy exactly (strcmp) matches the dentry name of the object or it doesn't.
This patch has no changes from today if policy does not implement the new
rules.
Signed-off-by: Eric Paris <eparis@redhat.com>
2011-02-01 23:05:40 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Check for class-specific changes. */
|
2011-03-25 12:51:58 +07:00
|
|
|
if (specified & AVTAB_TRANSITION) {
|
|
|
|
/* Look for a role transition rule. */
|
2020-04-08 01:28:58 +07:00
|
|
|
struct role_trans_datum *rtd;
|
|
|
|
struct role_trans_key rtk = {
|
|
|
|
.role = scontext->role,
|
|
|
|
.type = tcontext->type,
|
|
|
|
.tclass = tclass,
|
|
|
|
};
|
|
|
|
|
2020-07-10 02:19:51 +07:00
|
|
|
rtd = policydb_roletr_search(policydb, &rtk);
|
2020-04-08 01:28:58 +07:00
|
|
|
if (rtd)
|
|
|
|
newcontext.role = rtd->new_role;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the MLS attributes.
|
|
|
|
This is done last because it may allocate memory. */
|
2018-03-02 06:48:02 +07:00
|
|
|
rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
|
2011-03-02 12:32:33 +07:00
|
|
|
&newcontext, sock);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (rc)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
/* Check the validity of the context. */
|
2018-03-02 06:48:02 +07:00
|
|
|
if (!policydb_context_isvalid(policydb, &newcontext)) {
|
2020-08-20 02:45:16 +07:00
|
|
|
rc = compute_sid_handle_invalid_context(state, policy, sentry,
|
|
|
|
tentry, tclass,
|
|
|
|
&newcontext);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (rc)
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
/* Obtain the sid for the context. */
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
|
2005-04-17 05:20:36 +07:00
|
|
|
out_unlock:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2005-04-17 05:20:36 +07:00
|
|
|
context_destroy(&newcontext);
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* security_transition_sid - Compute the SID for a new subject/object.
|
|
|
|
* @ssid: source security identifier
|
|
|
|
* @tsid: target security identifier
|
|
|
|
* @tclass: target security class
|
|
|
|
* @out_sid: security identifier for new subject/object
|
|
|
|
*
|
|
|
|
* Compute a SID to use for labeling a new subject or object in the
|
|
|
|
* class @tclass based on a SID pair (@ssid, @tsid).
|
|
|
|
* Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
|
|
|
|
* if insufficient memory is available, or %0 if the new SID was
|
|
|
|
* computed successfully.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_transition_sid(struct selinux_state *state,
|
|
|
|
u32 ssid, u32 tsid, u16 tclass,
|
SELinux: Use dentry name in new object labeling
Currently SELinux has rules which label new objects according to 3 criteria.
The label of the process creating the object, the label of the parent
directory, and the type of object (reg, dir, char, block, etc.) This patch
adds a 4th criteria, the dentry name, thus we can distinguish between
creating a file in an etc_t directory called shadow and one called motd.
There is no file globbing, regex parsing, or anything mystical. Either the
policy exactly (strcmp) matches the dentry name of the object or it doesn't.
This patch has no changes from today if policy does not implement the new
rules.
Signed-off-by: Eric Paris <eparis@redhat.com>
2011-02-01 23:05:40 +07:00
|
|
|
const struct qstr *qstr, u32 *out_sid)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_compute_sid(state, ssid, tsid, tclass,
|
|
|
|
AVTAB_TRANSITION,
|
2011-04-01 21:39:26 +07:00
|
|
|
qstr ? qstr->name : NULL, out_sid, true);
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_transition_sid_user(struct selinux_state *state,
|
|
|
|
u32 ssid, u32 tsid, u16 tclass,
|
2011-04-01 21:39:26 +07:00
|
|
|
const char *objname, u32 *out_sid)
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_compute_sid(state, ssid, tsid, tclass,
|
|
|
|
AVTAB_TRANSITION,
|
2011-04-01 21:39:26 +07:00
|
|
|
objname, out_sid, false);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* security_member_sid - Compute the SID for member selection.
|
|
|
|
* @ssid: source security identifier
|
|
|
|
* @tsid: target security identifier
|
|
|
|
* @tclass: target security class
|
|
|
|
* @out_sid: security identifier for selected member
|
|
|
|
*
|
|
|
|
* Compute a SID to use when selecting a member of a polyinstantiated
|
|
|
|
* object of class @tclass based on a SID pair (@ssid, @tsid).
|
|
|
|
* Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
|
|
|
|
* if insufficient memory is available, or %0 if the SID was
|
|
|
|
* computed successfully.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_member_sid(struct selinux_state *state,
|
|
|
|
u32 ssid,
|
2005-04-17 05:20:36 +07:00
|
|
|
u32 tsid,
|
|
|
|
u16 tclass,
|
|
|
|
u32 *out_sid)
|
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_compute_sid(state, ssid, tsid, tclass,
|
|
|
|
AVTAB_MEMBER, NULL,
|
SELinux: Use dentry name in new object labeling
Currently SELinux has rules which label new objects according to 3 criteria.
The label of the process creating the object, the label of the parent
directory, and the type of object (reg, dir, char, block, etc.) This patch
adds a 4th criteria, the dentry name, thus we can distinguish between
creating a file in an etc_t directory called shadow and one called motd.
There is no file globbing, regex parsing, or anything mystical. Either the
policy exactly (strcmp) matches the dentry name of the object or it doesn't.
This patch has no changes from today if policy does not implement the new
rules.
Signed-off-by: Eric Paris <eparis@redhat.com>
2011-02-01 23:05:40 +07:00
|
|
|
out_sid, false);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* security_change_sid - Compute the SID for object relabeling.
|
|
|
|
* @ssid: source security identifier
|
|
|
|
* @tsid: target security identifier
|
|
|
|
* @tclass: target security class
|
|
|
|
* @out_sid: security identifier for selected member
|
|
|
|
*
|
|
|
|
* Compute a SID to use for relabeling an object of class @tclass
|
|
|
|
* based on a SID pair (@ssid, @tsid).
|
|
|
|
* Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
|
|
|
|
* if insufficient memory is available, or %0 if the SID was
|
|
|
|
* computed successfully.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_change_sid(struct selinux_state *state,
|
|
|
|
u32 ssid,
|
2005-04-17 05:20:36 +07:00
|
|
|
u32 tsid,
|
|
|
|
u16 tclass,
|
|
|
|
u32 *out_sid)
|
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
return security_compute_sid(state,
|
|
|
|
ssid, tsid, tclass, AVTAB_CHANGE, NULL,
|
SELinux: Use dentry name in new object labeling
Currently SELinux has rules which label new objects according to 3 criteria.
The label of the process creating the object, the label of the parent
directory, and the type of object (reg, dir, char, block, etc.) This patch
adds a 4th criteria, the dentry name, thus we can distinguish between
creating a file in an etc_t directory called shadow and one called motd.
There is no file globbing, regex parsing, or anything mystical. Either the
policy exactly (strcmp) matches the dentry name of the object or it doesn't.
This patch has no changes from today if policy does not implement the new
rules.
Signed-off-by: Eric Paris <eparis@redhat.com>
2011-02-01 23:05:40 +07:00
|
|
|
out_sid, false);
|
2006-11-07 00:38:18 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
static inline int convert_context_handle_invalid_context(
|
|
|
|
struct selinux_state *state,
|
2020-08-20 02:45:16 +07:00
|
|
|
struct policydb *policydb,
|
2018-03-02 06:48:02 +07:00
|
|
|
struct context *context)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2010-11-23 23:40:08 +07:00
|
|
|
char *s;
|
|
|
|
u32 len;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2018-03-02 05:38:30 +07:00
|
|
|
if (enforcing_enabled(state))
|
2010-11-23 23:40:08 +07:00
|
|
|
return -EINVAL;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
if (!context_struct_to_string(policydb, context, &s, &len)) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_warn("SELinux: Context %s would be invalid if enforcing\n",
|
|
|
|
s);
|
2010-11-23 23:40:08 +07:00
|
|
|
kfree(s);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2010-11-23 23:40:08 +07:00
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
struct convert_context_args {
|
2018-03-02 06:48:02 +07:00
|
|
|
struct selinux_state *state;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct policydb *oldp;
|
|
|
|
struct policydb *newp;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert the values in the security context
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
* structure `oldc' from the values specified
|
2005-04-17 05:20:36 +07:00
|
|
|
* in the policy `p->oldp' to the values specified
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
* in the policy `p->newp', storing the new context
|
|
|
|
* in `newc'. Verify that the context is valid
|
|
|
|
* under the new policy.
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
static int convert_context(struct context *oldc, struct context *newc, void *p)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct convert_context_args *args;
|
2010-02-03 22:40:20 +07:00
|
|
|
struct ocontext *oc;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct role_datum *role;
|
|
|
|
struct type_datum *typdatum;
|
|
|
|
struct user_datum *usrdatum;
|
|
|
|
char *s;
|
|
|
|
u32 len;
|
2018-11-30 22:24:07 +07:00
|
|
|
int rc;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
args = p;
|
|
|
|
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
if (oldc->str) {
|
|
|
|
s = kstrdup(oldc->str, GFP_KERNEL);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (!s)
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
return -ENOMEM;
|
2010-11-23 23:40:08 +07:00
|
|
|
|
2008-05-14 21:33:55 +07:00
|
|
|
rc = string_to_context_struct(args->newp, NULL, s,
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
newc, SECSID_NULL);
|
|
|
|
if (rc == -EINVAL) {
|
2019-10-03 20:59:22 +07:00
|
|
|
/*
|
|
|
|
* Retain string representation for later mapping.
|
|
|
|
*
|
|
|
|
* IMPORTANT: We need to copy the contents of oldc->str
|
|
|
|
* back into s again because string_to_context_struct()
|
|
|
|
* may have garbled it.
|
|
|
|
*/
|
|
|
|
memcpy(s, oldc->str, oldc->len);
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
context_init(newc);
|
|
|
|
newc->str = s;
|
|
|
|
newc->len = oldc->len;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
kfree(s);
|
|
|
|
if (rc) {
|
2008-05-08 00:03:20 +07:00
|
|
|
/* Other error condition, e.g. ENOMEM. */
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: Unable to map context %s, rc = %d.\n",
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
oldc->str, -rc);
|
|
|
|
return rc;
|
2008-05-08 00:03:20 +07:00
|
|
|
}
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
pr_info("SELinux: Context %s became valid (mapped).\n",
|
|
|
|
oldc->str);
|
|
|
|
return 0;
|
2008-05-08 00:03:20 +07:00
|
|
|
}
|
|
|
|
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
context_init(newc);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Convert the user. */
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2020-07-08 18:24:45 +07:00
|
|
|
usrdatum = symtab_search(&args->newp->p_users,
|
|
|
|
sym_name(args->oldp,
|
|
|
|
SYM_USERS, oldc->user - 1));
|
2008-04-19 04:38:33 +07:00
|
|
|
if (!usrdatum)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto bad;
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
newc->user = usrdatum->value;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Convert the role. */
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2020-07-08 18:24:45 +07:00
|
|
|
role = symtab_search(&args->newp->p_roles,
|
|
|
|
sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
|
2008-04-19 04:38:33 +07:00
|
|
|
if (!role)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto bad;
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
newc->role = role->value;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Convert the type. */
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2020-07-08 18:24:45 +07:00
|
|
|
typdatum = symtab_search(&args->newp->p_types,
|
|
|
|
sym_name(args->oldp,
|
|
|
|
SYM_TYPES, oldc->type - 1));
|
2008-04-19 04:38:33 +07:00
|
|
|
if (!typdatum)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto bad;
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
newc->type = typdatum->value;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2010-02-03 22:40:20 +07:00
|
|
|
/* Convert the MLS fields if dealing with MLS policies */
|
|
|
|
if (args->oldp->mls_enabled && args->newp->mls_enabled) {
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
|
2010-02-03 22:40:20 +07:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
|
|
|
|
/*
|
|
|
|
* Switching between non-MLS and MLS policy:
|
|
|
|
* ensure that the MLS fields of the context for all
|
|
|
|
* existing entries in the sidtab are filled in with a
|
|
|
|
* suitable default value, likely taken from one of the
|
|
|
|
* initial SIDs.
|
|
|
|
*/
|
|
|
|
oc = args->newp->ocontexts[OCON_ISID];
|
|
|
|
while (oc && oc->sid[0] != SECINITSID_UNLABELED)
|
|
|
|
oc = oc->next;
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2010-02-03 22:40:20 +07:00
|
|
|
if (!oc) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: unable to look up"
|
2010-02-03 22:40:20 +07:00
|
|
|
" the initial SIDs list\n");
|
|
|
|
goto bad;
|
|
|
|
}
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
rc = mls_range_set(newc, &oc->context[0].range);
|
2010-02-03 22:40:20 +07:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Check the validity of the new context. */
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
if (!policydb_context_isvalid(args->newp, newc)) {
|
2020-08-20 02:45:16 +07:00
|
|
|
rc = convert_context_handle_invalid_context(args->state,
|
|
|
|
args->oldp,
|
|
|
|
oldc);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
bad:
|
2008-05-08 00:03:20 +07:00
|
|
|
/* Map old representation to string and save it. */
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
rc = context_struct_to_string(args->oldp, oldc, &s, &len);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
context_destroy(newc);
|
|
|
|
newc->str = s;
|
|
|
|
newc->len = len;
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_info("SELinux: Context %s became invalid (unmapped).\n",
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
newc->str);
|
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
static void security_load_policycaps(struct selinux_state *state,
|
|
|
|
struct selinux_policy *policy)
|
2008-01-29 20:38:19 +07:00
|
|
|
{
|
2020-08-07 20:29:33 +07:00
|
|
|
struct policydb *p;
|
2017-05-19 03:58:31 +07:00
|
|
|
unsigned int i;
|
|
|
|
struct ebitmap_node *node;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
p = &policy->policydb;
|
2020-08-07 20:29:33 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
|
2020-09-10 21:28:05 +07:00
|
|
|
WRITE_ONCE(state->policycap[i],
|
|
|
|
ebitmap_get_bit(&p->policycaps, i));
|
2017-05-19 03:58:31 +07:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
|
|
|
|
pr_info("SELinux: policy capability %s=%d\n",
|
|
|
|
selinux_policycap_names[i],
|
2018-03-02 06:48:02 +07:00
|
|
|
ebitmap_get_bit(&p->policycaps, i));
|
2017-05-19 03:58:31 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
|
2017-05-19 03:58:31 +07:00
|
|
|
if (i >= ARRAY_SIZE(selinux_policycap_names))
|
|
|
|
pr_info("SELinux: unknown policy capability %u\n",
|
|
|
|
i);
|
|
|
|
}
|
2008-01-29 20:38:19 +07:00
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
static int security_preserve_bools(struct selinux_policy *oldpolicy,
|
|
|
|
struct selinux_policy *newpolicy);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-07 20:29:33 +07:00
|
|
|
static void selinux_policy_free(struct selinux_policy *policy)
|
|
|
|
{
|
|
|
|
if (!policy)
|
|
|
|
return;
|
|
|
|
|
2020-08-12 02:01:56 +07:00
|
|
|
sidtab_destroy(policy->sidtab);
|
2020-08-07 20:29:33 +07:00
|
|
|
kfree(policy->map.mapping);
|
2020-08-26 21:14:19 +07:00
|
|
|
policydb_destroy(&policy->policydb);
|
|
|
|
kfree(policy->sidtab);
|
2020-08-07 20:29:33 +07:00
|
|
|
kfree(policy);
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
static void selinux_policy_cond_free(struct selinux_policy *policy)
|
|
|
|
{
|
|
|
|
cond_policydb_destroy_dup(&policy->policydb);
|
|
|
|
kfree(policy);
|
|
|
|
}
|
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
void selinux_policy_cancel(struct selinux_state *state,
|
|
|
|
struct selinux_policy *policy)
|
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *oldpolicy;
|
|
|
|
|
2020-08-27 00:28:53 +07:00
|
|
|
oldpolicy = rcu_dereference_protected(state->policy,
|
|
|
|
lockdep_is_held(&state->policy_mutex));
|
2020-08-20 02:45:16 +07:00
|
|
|
|
|
|
|
sidtab_cancel_convert(oldpolicy->sidtab);
|
2020-08-07 20:29:34 +07:00
|
|
|
selinux_policy_free(policy);
|
|
|
|
}
|
|
|
|
|
2020-08-12 02:01:56 +07:00
|
|
|
static void selinux_notify_policy_change(struct selinux_state *state,
|
|
|
|
u32 seqno)
|
|
|
|
{
|
|
|
|
/* Flush external caches and notify userspace of policy load */
|
|
|
|
avc_ss_reset(state->avc, seqno);
|
|
|
|
selnl_notify_policyload(seqno);
|
|
|
|
selinux_status_update_policyload(state, seqno);
|
|
|
|
selinux_netlbl_cache_invalidate();
|
|
|
|
selinux_xfrm_notify_policyload();
|
|
|
|
}
|
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
void selinux_policy_commit(struct selinux_state *state,
|
|
|
|
struct selinux_policy *newpolicy)
|
2020-08-07 20:29:33 +07:00
|
|
|
{
|
|
|
|
struct selinux_policy *oldpolicy;
|
|
|
|
u32 seqno;
|
|
|
|
|
2020-08-27 00:28:53 +07:00
|
|
|
oldpolicy = rcu_dereference_protected(state->policy,
|
|
|
|
lockdep_is_held(&state->policy_mutex));
|
2020-08-07 20:29:33 +07:00
|
|
|
|
|
|
|
/* If switching between different policy types, log MLS status */
|
|
|
|
if (oldpolicy) {
|
|
|
|
if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
|
|
|
|
pr_info("SELinux: Disabling MLS support...\n");
|
|
|
|
else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
|
|
|
|
pr_info("SELinux: Enabling MLS support...\n");
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
/* Set latest granting seqno for new policy. */
|
|
|
|
if (oldpolicy)
|
|
|
|
newpolicy->latest_granting = oldpolicy->latest_granting + 1;
|
|
|
|
else
|
|
|
|
newpolicy->latest_granting = 1;
|
|
|
|
seqno = newpolicy->latest_granting;
|
|
|
|
|
2020-08-07 20:29:33 +07:00
|
|
|
/* Install the new policy. */
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_assign_pointer(state->policy, newpolicy);
|
2020-08-07 20:29:33 +07:00
|
|
|
|
|
|
|
/* Load the policycaps from the new policy */
|
2020-08-20 02:45:16 +07:00
|
|
|
security_load_policycaps(state, newpolicy);
|
2020-08-07 20:29:33 +07:00
|
|
|
|
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
/*
|
|
|
|
* After first policy load, the security server is
|
|
|
|
* marked as initialized and ready to handle requests and
|
|
|
|
* any objects created prior to policy load are then labeled.
|
|
|
|
*/
|
|
|
|
selinux_mark_initialized(state);
|
|
|
|
selinux_complete_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free the old policy */
|
2020-08-20 02:45:16 +07:00
|
|
|
synchronize_rcu();
|
2020-08-07 20:29:33 +07:00
|
|
|
selinux_policy_free(oldpolicy);
|
|
|
|
|
2020-08-12 02:01:56 +07:00
|
|
|
/* Notify others of the policy change */
|
|
|
|
selinux_notify_policy_change(state, seqno);
|
2020-08-07 20:29:33 +07:00
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/**
|
|
|
|
* security_load_policy - Load a security policy configuration.
|
|
|
|
* @data: binary policy data
|
|
|
|
* @len: length of data in bytes
|
|
|
|
*
|
|
|
|
* Load a new set of security policy configuration data,
|
|
|
|
* validate it and convert the SID table as necessary.
|
|
|
|
* This function will flush the access vector cache after
|
|
|
|
* loading the new policy.
|
|
|
|
*/
|
2020-08-07 20:29:34 +07:00
|
|
|
int security_load_policy(struct selinux_state *state, void *data, size_t len,
|
|
|
|
struct selinux_policy **newpolicyp)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *newpolicy, *oldpolicy;
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
struct sidtab_convert_params convert_params;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct convert_context_args args;
|
|
|
|
int rc = 0;
|
|
|
|
struct policy_file file = { data, len }, *fp = &file;
|
|
|
|
|
2020-08-07 20:29:33 +07:00
|
|
|
newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
|
|
|
|
if (!newpolicy)
|
2020-01-16 19:04:34 +07:00
|
|
|
return -ENOMEM;
|
2018-03-02 06:48:02 +07:00
|
|
|
|
2020-08-12 02:01:56 +07:00
|
|
|
newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
|
2020-08-26 21:14:19 +07:00
|
|
|
if (!newpolicy->sidtab) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto err_policy;
|
|
|
|
}
|
2020-08-12 02:01:56 +07:00
|
|
|
|
2020-08-07 20:29:33 +07:00
|
|
|
rc = policydb_read(&newpolicy->policydb, fp);
|
|
|
|
if (rc)
|
2020-08-26 21:14:19 +07:00
|
|
|
goto err_sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-07 20:29:33 +07:00
|
|
|
newpolicy->policydb.len = len;
|
|
|
|
rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
|
|
|
|
&newpolicy->map);
|
|
|
|
if (rc)
|
2020-08-26 21:14:19 +07:00
|
|
|
goto err_policydb;
|
2020-01-16 19:04:34 +07:00
|
|
|
|
2020-08-12 02:01:56 +07:00
|
|
|
rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab);
|
2018-11-30 22:24:07 +07:00
|
|
|
if (rc) {
|
2020-08-07 20:29:33 +07:00
|
|
|
pr_err("SELinux: unable to load the initial SIDs\n");
|
2020-08-26 21:14:19 +07:00
|
|
|
goto err_mapping;
|
2018-11-30 22:24:07 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2010-02-03 22:40:20 +07:00
|
|
|
|
2020-08-07 20:29:33 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
/* First policy load, so no need to preserve state from old policy */
|
2020-08-07 20:29:34 +07:00
|
|
|
*newpolicyp = newpolicy;
|
2020-08-07 20:29:33 +07:00
|
|
|
return 0;
|
2008-05-08 00:03:20 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-27 00:28:53 +07:00
|
|
|
oldpolicy = rcu_dereference_protected(state->policy,
|
|
|
|
lockdep_is_held(&state->policy_mutex));
|
2020-08-20 02:45:16 +07:00
|
|
|
|
2020-08-07 20:29:33 +07:00
|
|
|
/* Preserve active boolean values from the old policy */
|
2020-08-20 02:45:16 +07:00
|
|
|
rc = security_preserve_bools(oldpolicy, newpolicy);
|
2007-04-20 01:16:19 +07:00
|
|
|
if (rc) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: unable to preserve booleans\n");
|
2020-08-26 21:14:19 +07:00
|
|
|
goto err_free_isids;
|
2007-04-20 01:16:19 +07:00
|
|
|
}
|
|
|
|
|
2008-05-08 00:03:20 +07:00
|
|
|
/*
|
|
|
|
* Convert the internal representations of contexts
|
|
|
|
* in the new SID table.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
args.state = state;
|
2020-08-20 02:45:16 +07:00
|
|
|
args.oldp = &oldpolicy->policydb;
|
2020-08-07 20:29:33 +07:00
|
|
|
args.newp = &newpolicy->policydb;
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
|
|
|
|
convert_params.func = convert_context;
|
|
|
|
convert_params.args = &args;
|
2020-08-12 02:01:56 +07:00
|
|
|
convert_params.target = newpolicy->sidtab;
|
selinux: overhaul sidtab to fix bug and improve performance
Before this patch, during a policy reload the sidtab would become frozen
and trying to map a new context to SID would be unable to add a new
entry to sidtab and fail with -ENOMEM.
Such failures are usually propagated into userspace, which has no way of
distignuishing them from actual allocation failures and thus doesn't
handle them gracefully. Such situation can be triggered e.g. by the
following reproducer:
while true; do load_policy; echo -n .; sleep 0.1; done &
for (( i = 0; i < 1024; i++ )); do
runcon -l s0:c$i echo -n x || break
# or:
# chcon -l s0:c$i <some_file> || break
done
This patch overhauls the sidtab so it doesn't need to be frozen during
policy reload, thus solving the above problem.
The new SID table leverages the fact that SIDs are allocated
sequentially and are never invalidated and stores them in linear buckets
indexed by a tree structure. This brings several advantages:
1. Fast SID -> context lookup - this lookup can now be done in
logarithmic time complexity (usually in less than 4 array lookups)
and can still be done safely without locking.
2. No need to re-search the whole table on reverse lookup miss - after
acquiring the spinlock only the newly added entries need to be
searched, which means that reverse lookups that end up inserting a
new entry are now about twice as fast.
3. No need to freeze sidtab during policy reload - it is now possible
to handle insertion of new entries even during sidtab conversion.
The tree structure of the new sidtab is able to grow automatically to up
to about 2^31 entries (at which point it should not have more than about
4 tree levels). The old sidtab had a theoretical capacity of almost 2^32
entries, but half of that is still more than enough since by that point
the reverse table lookups would become unusably slow anyway...
The number of entries per tree node is selected automatically so that
each node fits into a single page, which should be the easiest size for
kmalloc() to handle.
Note that the cache for reverse lookup is preserved with equivalent
logic. The only difference is that instead of storing pointers to the
hash table nodes it stores just the indices of the cached entries.
The new cache ensures that the indices are loaded/stored atomically, but
it still has the drawback that concurrent cache updates may mess up the
contents of the cache. Such situation however only reduces its
effectivity, not the correctness of lookups.
Tested by selinux-testsuite and thoroughly tortured by this simple
stress test:
```
function rand_cat() {
echo $(( $RANDOM % 1024 ))
}
function do_work() {
while true; do
echo -n "system_u:system_r:kernel_t:s0:c$(rand_cat),c$(rand_cat)" \
>/sys/fs/selinux/context 2>/dev/null || true
done
}
do_work >/dev/null &
do_work >/dev/null &
do_work >/dev/null &
while load_policy; do echo -n .; sleep 0.1; done
kill %1
kill %2
kill %3
```
Link: https://github.com/SELinuxProject/selinux-kernel/issues/38
Reported-by: Orion Poplawski <orion@nwra.com>
Reported-by: Li Kun <hw.likun@huawei.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
[PM: most of sidtab.c merged by hand due to conflicts]
[PM: checkpatch fixes in mls.c, services.c, sidtab.c]
Signed-off-by: Paul Moore <paul@paul-moore.com>
2018-11-30 22:24:08 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rc = sidtab_convert(oldpolicy->sidtab, &convert_params);
|
2010-02-03 22:40:20 +07:00
|
|
|
if (rc) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: unable to convert the internal"
|
2010-02-03 22:40:20 +07:00
|
|
|
" representation of contexts in the new SID"
|
|
|
|
" table\n");
|
2020-08-26 21:14:19 +07:00
|
|
|
goto err_free_isids;
|
2010-02-03 22:40:20 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
*newpolicyp = newpolicy;
|
2020-08-07 20:29:33 +07:00
|
|
|
return 0;
|
2020-08-26 21:14:19 +07:00
|
|
|
|
|
|
|
err_free_isids:
|
|
|
|
sidtab_destroy(newpolicy->sidtab);
|
|
|
|
err_mapping:
|
|
|
|
kfree(newpolicy->map.mapping);
|
|
|
|
err_policydb:
|
|
|
|
policydb_destroy(&newpolicy->policydb);
|
|
|
|
err_sidtab:
|
|
|
|
kfree(newpolicy->sidtab);
|
|
|
|
err_policy:
|
|
|
|
kfree(newpolicy);
|
|
|
|
|
2013-11-15 05:04:51 +07:00
|
|
|
return rc;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* security_port_sid - Obtain the SID for a port.
|
|
|
|
* @protocol: protocol number
|
|
|
|
* @port: port number
|
|
|
|
* @out_sid: security identifier
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_port_sid(struct selinux_state *state,
|
|
|
|
u8 protocol, u16 port, u32 *out_sid)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
2020-04-17 15:11:57 +07:00
|
|
|
struct sidtab *sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct ocontext *c;
|
|
|
|
int rc = 0;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
*out_sid = SECINITSID_PORT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
c = policydb->ocontexts[OCON_PORT];
|
2005-04-17 05:20:36 +07:00
|
|
|
while (c) {
|
|
|
|
if (c->u.port.protocol == protocol &&
|
|
|
|
c->u.port.low_port <= port &&
|
|
|
|
c->u.port.high_port >= port)
|
|
|
|
break;
|
|
|
|
c = c->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c) {
|
|
|
|
if (!c->sid[0]) {
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
2005-04-17 05:20:36 +07:00
|
|
|
&c->sid[0]);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
*out_sid = c->sid[0];
|
|
|
|
} else {
|
|
|
|
*out_sid = SECINITSID_PORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2005-04-17 05:20:36 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-05-19 19:48:57 +07:00
|
|
|
/**
|
|
|
|
* security_pkey_sid - Obtain the SID for a pkey.
|
|
|
|
* @subnet_prefix: Subnet Prefix
|
|
|
|
* @pkey_num: pkey number
|
|
|
|
* @out_sid: security identifier
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_ib_pkey_sid(struct selinux_state *state,
|
|
|
|
u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
|
2017-05-19 19:48:57 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
2020-04-17 15:11:57 +07:00
|
|
|
struct sidtab *sidtab;
|
2017-05-19 19:48:57 +07:00
|
|
|
struct ocontext *c;
|
|
|
|
int rc = 0;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
*out_sid = SECINITSID_UNLABELED;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2017-05-19 19:48:57 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
c = policydb->ocontexts[OCON_IBPKEY];
|
2017-05-19 19:48:57 +07:00
|
|
|
while (c) {
|
|
|
|
if (c->u.ibpkey.low_pkey <= pkey_num &&
|
|
|
|
c->u.ibpkey.high_pkey >= pkey_num &&
|
|
|
|
c->u.ibpkey.subnet_prefix == subnet_prefix)
|
|
|
|
break;
|
|
|
|
|
|
|
|
c = c->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c) {
|
|
|
|
if (!c->sid[0]) {
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab,
|
2017-05-19 19:48:57 +07:00
|
|
|
&c->context[0],
|
|
|
|
&c->sid[0]);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
*out_sid = c->sid[0];
|
|
|
|
} else
|
|
|
|
*out_sid = SECINITSID_UNLABELED;
|
|
|
|
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2017-05-19 19:48:57 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-05-19 19:48:58 +07:00
|
|
|
/**
|
|
|
|
* security_ib_endport_sid - Obtain the SID for a subnet management interface.
|
|
|
|
* @dev_name: device name
|
|
|
|
* @port: port number
|
|
|
|
* @out_sid: security identifier
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_ib_endport_sid(struct selinux_state *state,
|
|
|
|
const char *dev_name, u8 port_num, u32 *out_sid)
|
2017-05-19 19:48:58 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
2020-04-17 15:11:57 +07:00
|
|
|
struct sidtab *sidtab;
|
2017-05-19 19:48:58 +07:00
|
|
|
struct ocontext *c;
|
|
|
|
int rc = 0;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
*out_sid = SECINITSID_UNLABELED;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2018-03-02 06:48:02 +07:00
|
|
|
|
|
|
|
c = policydb->ocontexts[OCON_IBENDPORT];
|
2017-05-19 19:48:58 +07:00
|
|
|
while (c) {
|
|
|
|
if (c->u.ibendport.port == port_num &&
|
|
|
|
!strncmp(c->u.ibendport.dev_name,
|
|
|
|
dev_name,
|
|
|
|
IB_DEVICE_NAME_MAX))
|
|
|
|
break;
|
|
|
|
|
|
|
|
c = c->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c) {
|
|
|
|
if (!c->sid[0]) {
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
2017-05-19 19:48:58 +07:00
|
|
|
&c->sid[0]);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
*out_sid = c->sid[0];
|
|
|
|
} else
|
|
|
|
*out_sid = SECINITSID_UNLABELED;
|
|
|
|
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2017-05-19 19:48:58 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/**
|
|
|
|
* security_netif_sid - Obtain the SID for a network interface.
|
|
|
|
* @name: interface name
|
|
|
|
* @if_sid: interface SID
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_netif_sid(struct selinux_state *state,
|
|
|
|
char *name, u32 *if_sid)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
2020-04-17 15:11:57 +07:00
|
|
|
struct sidtab *sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
int rc = 0;
|
|
|
|
struct ocontext *c;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
*if_sid = SECINITSID_NETIF;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
c = policydb->ocontexts[OCON_NETIF];
|
2005-04-17 05:20:36 +07:00
|
|
|
while (c) {
|
|
|
|
if (strcmp(name, c->u.name) == 0)
|
|
|
|
break;
|
|
|
|
c = c->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c) {
|
|
|
|
if (!c->sid[0] || !c->sid[1]) {
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
2019-11-22 16:33:06 +07:00
|
|
|
&c->sid[0]);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &c->context[1],
|
2005-04-17 05:20:36 +07:00
|
|
|
&c->sid[1]);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
*if_sid = c->sid[0];
|
2008-01-29 20:38:08 +07:00
|
|
|
} else
|
2005-04-17 05:20:36 +07:00
|
|
|
*if_sid = SECINITSID_NETIF;
|
|
|
|
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2005-04-17 05:20:36 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
|
|
|
|
{
|
|
|
|
int i, fail = 0;
|
|
|
|
|
2008-04-19 04:38:33 +07:00
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
if (addr[i] != (input[i] & mask[i])) {
|
2005-04-17 05:20:36 +07:00
|
|
|
fail = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* security_node_sid - Obtain the SID for a node (host).
|
|
|
|
* @domain: communication domain aka address family
|
|
|
|
* @addrp: address
|
|
|
|
* @addrlen: address length in bytes
|
|
|
|
* @out_sid: security identifier
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_node_sid(struct selinux_state *state,
|
|
|
|
u16 domain,
|
2005-04-17 05:20:36 +07:00
|
|
|
void *addrp,
|
|
|
|
u32 addrlen,
|
|
|
|
u32 *out_sid)
|
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
2020-04-17 15:11:57 +07:00
|
|
|
struct sidtab *sidtab;
|
2010-11-23 23:40:08 +07:00
|
|
|
int rc;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct ocontext *c;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
*out_sid = SECINITSID_NODE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
switch (domain) {
|
|
|
|
case AF_INET: {
|
|
|
|
u32 addr;
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
if (addrlen != sizeof(u32))
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
addr = *((u32 *)addrp);
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
c = policydb->ocontexts[OCON_NODE];
|
2005-04-17 05:20:36 +07:00
|
|
|
while (c) {
|
|
|
|
if (c->u.node.addr == (addr & c->u.node.mask))
|
|
|
|
break;
|
|
|
|
c = c->next;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case AF_INET6:
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
|
|
|
if (addrlen != sizeof(u64) * 2)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
2018-03-02 06:48:02 +07:00
|
|
|
c = policydb->ocontexts[OCON_NODE6];
|
2005-04-17 05:20:36 +07:00
|
|
|
while (c) {
|
|
|
|
if (match_ipv6_addrmask(addrp, c->u.node6.addr,
|
|
|
|
c->u.node6.mask))
|
|
|
|
break;
|
|
|
|
c = c->next;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
*out_sid = SECINITSID_NODE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c) {
|
|
|
|
if (!c->sid[0]) {
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab,
|
2005-04-17 05:20:36 +07:00
|
|
|
&c->context[0],
|
|
|
|
&c->sid[0]);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
*out_sid = c->sid[0];
|
|
|
|
} else {
|
|
|
|
*out_sid = SECINITSID_NODE;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2005-04-17 05:20:36 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SIDS_NEL 25
|
|
|
|
|
|
|
|
/**
|
|
|
|
* security_get_user_sids - Obtain reachable SIDs for a user.
|
|
|
|
* @fromsid: starting SID
|
|
|
|
* @username: username
|
|
|
|
* @sids: array of reachable SIDs for user
|
|
|
|
* @nel: number of elements in @sids
|
|
|
|
*
|
|
|
|
* Generate the set of SIDs for legal security contexts
|
|
|
|
* for a given user that can be reached by @fromsid.
|
|
|
|
* Set *@sids to point to a dynamically allocated
|
|
|
|
* array containing the set of SIDs. Set *@nel to the
|
|
|
|
* number of elements in the array.
|
|
|
|
*/
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_get_user_sids(struct selinux_state *state,
|
|
|
|
u32 fromsid,
|
2008-04-19 04:38:33 +07:00
|
|
|
char *username,
|
2005-04-17 05:20:36 +07:00
|
|
|
u32 **sids,
|
|
|
|
u32 *nel)
|
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct context *fromcon, usercon;
|
2007-06-08 02:34:10 +07:00
|
|
|
u32 *mysids = NULL, *mysids2, sid;
|
2005-04-17 05:20:36 +07:00
|
|
|
u32 mynel = 0, maxnel = SIDS_NEL;
|
|
|
|
struct user_datum *user;
|
|
|
|
struct role_datum *role;
|
2005-09-04 05:55:16 +07:00
|
|
|
struct ebitmap_node *rnode, *tnode;
|
2005-04-17 05:20:36 +07:00
|
|
|
int rc = 0, i, j;
|
|
|
|
|
2007-06-08 02:34:10 +07:00
|
|
|
*sids = NULL;
|
|
|
|
*nel = 0;
|
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state))
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-05-08 00:03:20 +07:00
|
|
|
context_init(&usercon);
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2018-03-02 06:48:02 +07:00
|
|
|
fromcon = sidtab_search(sidtab, fromsid);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (!fromcon)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out_unlock;
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2020-07-08 18:24:45 +07:00
|
|
|
user = symtab_search(&policydb->p_users, username);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (!user)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out_unlock;
|
2010-11-23 23:40:08 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
usercon.user = user->value;
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOMEM;
|
2005-10-31 05:59:21 +07:00
|
|
|
mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (!mysids)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out_unlock;
|
|
|
|
|
SELinux: improve performance when AVC misses.
* We add ebitmap_for_each_positive_bit() which enables to walk on
any positive bit on the given ebitmap, to improve its performance
using common bit-operations defined in linux/bitops.h.
In the previous version, this logic was implemented using a combination
of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
in performance aspect.
This logic is most frequestly used to compute a new AVC entry,
so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get
suitable for using find_next_bit() which is fasted than iteration of
shift and logical operation, and to maximize memory usage allocated
from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation
in ss/service.c and ss/mls.c. Some of related implementation are
changed, however, there is no incompatibility with the previous
version.
* The width of any new line are less or equal than 80-chars.
The following benchmark shows the effect of this patch, when we
access many files which have different security context one after
another. The number is more than /selinux/avc/cache_threshold, so
any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s]
STD: 0.265 0.019
------------------------------------------
1st: 22.558 [s] 8.786 [s]
2nd: 22.458 [s] 8.750 [s]
3rd: 22.478 [s] 8.754 [s]
4th: 22.724 [s] 8.745 [s]
5th: 22.918 [s] 8.748 [s]
6th: 22.905 [s] 8.764 [s]
7th: 23.238 [s] 8.726 [s]
8th: 22.822 [s] 8.729 [s]
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2007-09-29 00:20:55 +07:00
|
|
|
ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
|
2018-03-02 06:48:02 +07:00
|
|
|
role = policydb->role_val_to_struct[i];
|
2010-04-09 18:30:29 +07:00
|
|
|
usercon.role = i + 1;
|
SELinux: improve performance when AVC misses.
* We add ebitmap_for_each_positive_bit() which enables to walk on
any positive bit on the given ebitmap, to improve its performance
using common bit-operations defined in linux/bitops.h.
In the previous version, this logic was implemented using a combination
of ebitmap_for_each_bit() and ebitmap_node_get_bit(), but is was worse
in performance aspect.
This logic is most frequestly used to compute a new AVC entry,
so this patch can improve SELinux performance when AVC misses are happen.
* struct ebitmap_node is redefined as an array of "unsigned long", to get
suitable for using find_next_bit() which is fasted than iteration of
shift and logical operation, and to maximize memory usage allocated
from general purpose slab.
* Any ebitmap_for_each_bit() are repleced by the new implementation
in ss/service.c and ss/mls.c. Some of related implementation are
changed, however, there is no incompatibility with the previous
version.
* The width of any new line are less or equal than 80-chars.
The following benchmark shows the effect of this patch, when we
access many files which have different security context one after
another. The number is more than /selinux/avc/cache_threshold, so
any access always causes AVC misses.
selinux-2.6 selinux-2.6-ebitmap
AVG: 22.763 [s] 8.750 [s]
STD: 0.265 0.019
------------------------------------------
1st: 22.558 [s] 8.786 [s]
2nd: 22.458 [s] 8.750 [s]
3rd: 22.478 [s] 8.754 [s]
4th: 22.724 [s] 8.745 [s]
5th: 22.918 [s] 8.748 [s]
6th: 22.905 [s] 8.764 [s]
7th: 23.238 [s] 8.726 [s]
8th: 22.822 [s] 8.729 [s]
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2007-09-29 00:20:55 +07:00
|
|
|
ebitmap_for_each_positive_bit(&role->types, tnode, j) {
|
2010-04-09 18:30:29 +07:00
|
|
|
usercon.type = j + 1;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
if (mls_setup_user_range(policydb, fromcon, user,
|
|
|
|
&usercon))
|
2005-04-17 05:20:36 +07:00
|
|
|
continue;
|
|
|
|
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
|
2007-06-08 02:34:10 +07:00
|
|
|
if (rc)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out_unlock;
|
|
|
|
if (mynel < maxnel) {
|
|
|
|
mysids[mynel++] = sid;
|
|
|
|
} else {
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOMEM;
|
2005-04-17 05:20:36 +07:00
|
|
|
maxnel += SIDS_NEL;
|
2005-10-31 05:59:21 +07:00
|
|
|
mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (!mysids2)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out_unlock;
|
|
|
|
memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
|
|
|
|
kfree(mysids);
|
|
|
|
mysids = mysids2;
|
|
|
|
mysids[mynel++] = sid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
out_unlock:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2007-06-08 02:34:10 +07:00
|
|
|
if (rc || !mynel) {
|
|
|
|
kfree(mysids);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOMEM;
|
2007-06-08 02:34:10 +07:00
|
|
|
mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
|
|
|
|
if (!mysids2) {
|
|
|
|
kfree(mysids);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
for (i = 0, j = 0; i < mynel; i++) {
|
2011-05-25 03:48:51 +07:00
|
|
|
struct av_decision dummy_avd;
|
2018-03-05 23:47:56 +07:00
|
|
|
rc = avc_has_perm_noaudit(state,
|
|
|
|
fromsid, mysids[i],
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
SECCLASS_PROCESS, /* kernel value */
|
2007-06-08 02:34:10 +07:00
|
|
|
PROCESS__TRANSITION, AVC_STRICT,
|
2011-05-25 03:48:51 +07:00
|
|
|
&dummy_avd);
|
2007-06-08 02:34:10 +07:00
|
|
|
if (!rc)
|
|
|
|
mysids2[j++] = mysids[i];
|
|
|
|
cond_resched();
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
kfree(mysids);
|
|
|
|
*sids = mysids2;
|
|
|
|
*nel = j;
|
2005-04-17 05:20:36 +07:00
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-06-23 22:28:51 +07:00
|
|
|
* __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
|
2005-04-17 05:20:36 +07:00
|
|
|
* @fstype: filesystem type
|
|
|
|
* @path: path from root of mount
|
|
|
|
* @sclass: file security class
|
|
|
|
* @sid: SID for path
|
|
|
|
*
|
|
|
|
* Obtain a SID to use for a file in a filesystem that
|
|
|
|
* cannot support xattr or use a fixed labeling behavior like
|
|
|
|
* transition SIDs or task SIDs.
|
|
|
|
*/
|
2020-08-07 20:29:34 +07:00
|
|
|
static inline int __security_genfs_sid(struct selinux_policy *policy,
|
2018-03-02 06:48:02 +07:00
|
|
|
const char *fstype,
|
2014-06-23 22:28:51 +07:00
|
|
|
char *path,
|
|
|
|
u16 orig_sclass,
|
|
|
|
u32 *sid)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-07 20:29:34 +07:00
|
|
|
struct policydb *policydb = &policy->policydb;
|
2020-08-12 02:01:56 +07:00
|
|
|
struct sidtab *sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
int len;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
u16 sclass;
|
2005-04-17 05:20:36 +07:00
|
|
|
struct genfs *genfs;
|
|
|
|
struct ocontext *c;
|
2010-11-23 23:40:08 +07:00
|
|
|
int rc, cmp = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2008-01-26 01:03:42 +07:00
|
|
|
while (path[0] == '/' && path[1] == '/')
|
|
|
|
path++;
|
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
sclass = unmap_class(&policy->map, orig_sclass);
|
2010-11-23 23:40:08 +07:00
|
|
|
*sid = SECINITSID_UNLABELED;
|
selinux: dynamic class/perm discovery
Modify SELinux to dynamically discover class and permission values
upon policy load, based on the dynamic object class/perm discovery
logic from libselinux. A mapping is created between kernel-private
class and permission indices used outside the security server and the
policy values used within the security server.
The mappings are only applied upon kernel-internal computations;
similar mappings for the private indices of userspace object managers
is handled on a per-object manager basis by the userspace AVC. The
interfaces for compute_av and transition_sid are split for kernel
vs. userspace; the userspace functions are distinguished by a _user
suffix.
The kernel-private class indices are no longer tied to the policy
values and thus do not need to skip indices for userspace classes;
thus the kernel class index values are compressed. The flask.h
definitions were regenerated by deleting the userspace classes from
refpolicy's definitions and then regenerating the headers. Going
forward, we can just maintain the flask.h, av_permissions.h, and
classmap.h definitions separately from policy as they are no longer
tied to the policy values. The next patch introduces a utility to
automate generation of flask.h and av_permissions.h from the
classmap.h definitions.
The older kernel class and permission string tables are removed and
replaced by a single security class mapping table that is walked at
policy load to generate the mapping. The old kernel class validation
logic is completely replaced by the mapping logic.
The handle unknown logic is reworked. reject_unknown=1 is handled
when the mappings are computed at policy load time, similar to the old
handling by the class validation logic. allow_unknown=1 is handled
when computing and mapping decisions - if the permission was not able
to be mapped (i.e. undefined, mapped to zero), then it is
automatically added to the allowed vector. If the class was not able
to be mapped (i.e. undefined, mapped to zero), then all permissions
are allowed for it if allow_unknown=1.
avc_audit leverages the new security class mapping table to lookup the
class and permission names from the kernel-private indices.
The mdp program is updated to use the new table when generating the
class definitions and allow rules for a minimal boot policy for the
kernel. It should be noted that this policy will not include any
userspace classes, nor will its policy index values for the kernel
classes correspond with the ones in refpolicy (they will instead match
the kernel-private indices).
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
2009-10-01 00:37:50 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
|
2005-04-17 05:20:36 +07:00
|
|
|
cmp = strcmp(fstype, genfs->fstype);
|
|
|
|
if (cmp <= 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOENT;
|
|
|
|
if (!genfs || cmp)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
for (c = genfs->head; c; c = c->next) {
|
|
|
|
len = strlen(c->u.name);
|
|
|
|
if ((!c->v.sclass || sclass == c->v.sclass) &&
|
|
|
|
(strncmp(c->u.name, path, len) == 0))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOENT;
|
|
|
|
if (!c)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (!c->sid[0]) {
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
*sid = c->sid[0];
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-06-23 22:28:51 +07:00
|
|
|
/**
|
|
|
|
* security_genfs_sid - Obtain a SID for a file in a filesystem
|
|
|
|
* @fstype: filesystem type
|
|
|
|
* @path: path from root of mount
|
|
|
|
* @sclass: file security class
|
|
|
|
* @sid: SID for path
|
|
|
|
*
|
|
|
|
* Acquire policy_rwlock before calling __security_genfs_sid() and release
|
|
|
|
* it afterward.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_genfs_sid(struct selinux_state *state,
|
|
|
|
const char *fstype,
|
2014-06-23 22:28:51 +07:00
|
|
|
char *path,
|
|
|
|
u16 orig_sclass,
|
|
|
|
u32 *sid)
|
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2014-06-23 22:28:51 +07:00
|
|
|
int retval;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
*sid = SECINITSID_UNLABELED;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
retval = __security_genfs_sid(policy,
|
2020-08-07 20:29:34 +07:00
|
|
|
fstype, path, orig_sclass, sid);
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2014-06-23 22:28:51 +07:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
int selinux_policy_genfs_sid(struct selinux_policy *policy,
|
|
|
|
const char *fstype,
|
|
|
|
char *path,
|
|
|
|
u16 orig_sclass,
|
|
|
|
u32 *sid)
|
|
|
|
{
|
|
|
|
/* no lock required, policy is not yet accessible by other threads */
|
|
|
|
return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/**
|
|
|
|
* security_fs_use - Determine how to handle labeling for a filesystem.
|
2012-08-25 02:59:07 +07:00
|
|
|
* @sb: superblock in question
|
2005-04-17 05:20:36 +07:00
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_fs_use(struct selinux_state *state, struct super_block *sb)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
2020-04-17 15:11:57 +07:00
|
|
|
struct sidtab *sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
int rc = 0;
|
|
|
|
struct ocontext *c;
|
2012-08-25 02:59:07 +07:00
|
|
|
struct superblock_security_struct *sbsec = sb->s_security;
|
|
|
|
const char *fstype = sb->s_type->name;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
|
|
|
sbsec->behavior = SECURITY_FS_USE_NONE;
|
|
|
|
sbsec->sid = SECINITSID_UNLABELED;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
c = policydb->ocontexts[OCON_FSUSE];
|
2013-12-14 02:49:53 +07:00
|
|
|
while (c) {
|
|
|
|
if (strcmp(fstype, c->u.name) == 0)
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
2013-12-14 02:49:53 +07:00
|
|
|
c = c->next;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (c) {
|
2012-08-25 02:59:07 +07:00
|
|
|
sbsec->behavior = c->v.behavior;
|
2005-04-17 05:20:36 +07:00
|
|
|
if (!c->sid[0]) {
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &c->context[0],
|
2005-04-17 05:20:36 +07:00
|
|
|
&c->sid[0]);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
2012-08-25 02:59:07 +07:00
|
|
|
sbsec->sid = c->sid[0];
|
2005-04-17 05:20:36 +07:00
|
|
|
} else {
|
2020-08-20 02:45:16 +07:00
|
|
|
rc = __security_genfs_sid(policy, fstype, "/",
|
2020-08-07 20:29:34 +07:00
|
|
|
SECCLASS_DIR, &sbsec->sid);
|
2008-07-15 15:32:49 +07:00
|
|
|
if (rc) {
|
2012-08-25 02:59:07 +07:00
|
|
|
sbsec->behavior = SECURITY_FS_USE_NONE;
|
2008-07-15 15:32:49 +07:00
|
|
|
rc = 0;
|
|
|
|
} else {
|
2012-08-25 02:59:07 +07:00
|
|
|
sbsec->behavior = SECURITY_FS_USE_GENFS;
|
2008-07-15 15:32:49 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2005-04-17 05:20:36 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
int security_get_bools(struct selinux_policy *policy,
|
2020-02-03 18:27:20 +07:00
|
|
|
u32 *len, char ***names, int **values)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
2020-02-03 18:27:20 +07:00
|
|
|
u32 i;
|
|
|
|
int rc;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
policydb = &policy->policydb;
|
2018-03-02 06:48:02 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
*names = NULL;
|
|
|
|
*values = NULL;
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
2018-03-02 06:48:02 +07:00
|
|
|
*len = policydb->p_bools.nprim;
|
2010-11-23 23:40:08 +07:00
|
|
|
if (!*len)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOMEM;
|
|
|
|
*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (!*names)
|
|
|
|
goto err;
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOMEM;
|
|
|
|
*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (!*values)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
for (i = 0; i < *len; i++) {
|
2018-03-02 06:48:02 +07:00
|
|
|
(*values)[i] = policydb->bool_val_to_struct[i]->state;
|
2010-11-23 23:40:08 +07:00
|
|
|
|
|
|
|
rc = -ENOMEM;
|
2018-03-02 06:48:02 +07:00
|
|
|
(*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
|
|
|
|
GFP_ATOMIC);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (!(*names)[i])
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
err:
|
|
|
|
if (*names) {
|
|
|
|
for (i = 0; i < *len; i++)
|
2005-06-26 04:58:51 +07:00
|
|
|
kfree((*names)[i]);
|
2020-06-11 04:57:13 +07:00
|
|
|
kfree(*names);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
2005-06-26 04:58:51 +07:00
|
|
|
kfree(*values);
|
2020-06-11 04:57:13 +07:00
|
|
|
*len = 0;
|
|
|
|
*names = NULL;
|
|
|
|
*values = NULL;
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-03 18:27:20 +07:00
|
|
|
int security_set_bools(struct selinux_state *state, u32 len, int *values)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-12 02:01:56 +07:00
|
|
|
struct selinux_policy *newpolicy, *oldpolicy;
|
2020-02-03 18:27:20 +07:00
|
|
|
int rc;
|
2020-08-12 02:01:56 +07:00
|
|
|
u32 i, seqno = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-08-27 00:28:53 +07:00
|
|
|
oldpolicy = rcu_dereference_protected(state->policy,
|
|
|
|
lockdep_is_held(&state->policy_mutex));
|
2020-08-20 02:45:16 +07:00
|
|
|
|
2020-08-12 02:01:56 +07:00
|
|
|
/* Consistency check on number of booleans, should never fail */
|
2020-08-20 02:45:16 +07:00
|
|
|
if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
|
2020-08-12 02:01:56 +07:00
|
|
|
return -EINVAL;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
|
2020-08-12 02:01:56 +07:00
|
|
|
if (!newpolicy)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deep copy only the parts of the policydb that might be
|
|
|
|
* modified as a result of changing booleans.
|
|
|
|
*/
|
|
|
|
rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb);
|
|
|
|
if (rc) {
|
|
|
|
kfree(newpolicy);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the boolean states in the copy */
|
2005-04-17 05:20:36 +07:00
|
|
|
for (i = 0; i < len; i++) {
|
2020-08-12 02:01:56 +07:00
|
|
|
int new_state = !!values[i];
|
|
|
|
int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
|
|
|
|
|
|
|
|
if (new_state != old_state) {
|
2018-05-13 08:58:20 +07:00
|
|
|
audit_log(audit_context(), GFP_ATOMIC,
|
2006-01-04 21:08:39 +07:00
|
|
|
AUDIT_MAC_CONFIG_CHANGE,
|
2008-01-08 22:06:53 +07:00
|
|
|
"bool=%s val=%d old_val=%d auid=%u ses=%u",
|
2020-08-12 02:01:56 +07:00
|
|
|
sym_name(&newpolicy->policydb, SYM_BOOLS, i),
|
|
|
|
new_state,
|
|
|
|
old_state,
|
2012-08-20 14:09:36 +07:00
|
|
|
from_kuid(&init_user_ns, audit_get_loginuid(current)),
|
2008-01-08 22:06:53 +07:00
|
|
|
audit_get_sessionid(current));
|
2020-08-12 02:01:56 +07:00
|
|
|
newpolicy->policydb.bool_val_to_struct[i]->state = new_state;
|
2006-01-04 21:08:39 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2020-08-12 02:01:56 +07:00
|
|
|
/* Re-evaluate the conditional rules in the copy */
|
|
|
|
evaluate_cond_nodes(&newpolicy->policydb);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
/* Set latest granting seqno for new policy */
|
|
|
|
newpolicy->latest_granting = oldpolicy->latest_granting + 1;
|
|
|
|
seqno = newpolicy->latest_granting;
|
|
|
|
|
2020-08-12 02:01:56 +07:00
|
|
|
/* Install the new policy */
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_assign_pointer(state->policy, newpolicy);
|
2020-08-12 02:01:56 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Free the conditional portions of the old policydb
|
2020-08-20 02:45:16 +07:00
|
|
|
* that were copied for the new policy, and the oldpolicy
|
|
|
|
* structure itself but not what it references.
|
2020-08-12 02:01:56 +07:00
|
|
|
*/
|
2020-08-20 02:45:16 +07:00
|
|
|
synchronize_rcu();
|
|
|
|
selinux_policy_cond_free(oldpolicy);
|
2020-08-12 02:01:56 +07:00
|
|
|
|
|
|
|
/* Notify others of the policy change */
|
|
|
|
selinux_notify_policy_change(state, seqno);
|
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_get_bool_value(struct selinux_state *state,
|
2020-02-03 18:27:20 +07:00
|
|
|
u32 index)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2018-03-02 06:48:02 +07:00
|
|
|
struct policydb *policydb;
|
2010-11-23 23:40:08 +07:00
|
|
|
int rc;
|
2020-02-03 18:27:20 +07:00
|
|
|
u32 len;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EFAULT;
|
2018-03-02 06:48:02 +07:00
|
|
|
len = policydb->p_bools.nprim;
|
2016-04-14 21:40:57 +07:00
|
|
|
if (index >= len)
|
2005-04-17 05:20:36 +07:00
|
|
|
goto out;
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
rc = policydb->bool_val_to_struct[index]->state;
|
2005-04-17 05:20:36 +07:00
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2005-04-17 05:20:36 +07:00
|
|
|
return rc;
|
|
|
|
}
|
2006-02-25 04:44:05 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
static int security_preserve_bools(struct selinux_policy *oldpolicy,
|
|
|
|
struct selinux_policy *newpolicy)
|
2007-04-20 01:16:19 +07:00
|
|
|
{
|
2020-02-03 18:27:20 +07:00
|
|
|
int rc, *bvalues = NULL;
|
2007-04-20 01:16:19 +07:00
|
|
|
char **bnames = NULL;
|
|
|
|
struct cond_bool_datum *booldatum;
|
2020-02-03 18:27:20 +07:00
|
|
|
u32 i, nbools = 0;
|
2007-04-20 01:16:19 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
|
2007-04-20 01:16:19 +07:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
for (i = 0; i < nbools; i++) {
|
2020-08-20 02:45:16 +07:00
|
|
|
booldatum = symtab_search(&newpolicy->policydb.p_bools,
|
|
|
|
bnames[i]);
|
2007-04-20 01:16:19 +07:00
|
|
|
if (booldatum)
|
|
|
|
booldatum->state = bvalues[i];
|
|
|
|
}
|
2020-08-20 02:45:16 +07:00
|
|
|
evaluate_cond_nodes(&newpolicy->policydb);
|
2007-04-20 01:16:19 +07:00
|
|
|
|
|
|
|
out:
|
|
|
|
if (bnames) {
|
|
|
|
for (i = 0; i < nbools; i++)
|
|
|
|
kfree(bnames[i]);
|
|
|
|
}
|
|
|
|
kfree(bnames);
|
|
|
|
kfree(bvalues);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2006-07-25 13:27:16 +07:00
|
|
|
/*
|
|
|
|
* security_sid_mls_copy() - computes a new sid based on the given
|
|
|
|
* sid and the mls portion of mls_sid.
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_sid_mls_copy(struct selinux_state *state,
|
|
|
|
u32 sid, u32 mls_sid, u32 *new_sid)
|
2006-07-25 13:27:16 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2020-08-07 20:29:33 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2006-07-25 13:27:16 +07:00
|
|
|
struct context *context1;
|
|
|
|
struct context *context2;
|
|
|
|
struct context newcon;
|
|
|
|
char *s;
|
|
|
|
u32 len;
|
2010-11-23 23:40:08 +07:00
|
|
|
int rc;
|
2006-07-25 13:27:16 +07:00
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
2020-08-07 20:29:33 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
2006-07-25 13:27:16 +07:00
|
|
|
*new_sid = sid;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
context_init(&newcon);
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2020-08-07 20:29:33 +07:00
|
|
|
|
|
|
|
if (!policydb->mls_enabled) {
|
|
|
|
*new_sid = sid;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2018-03-02 06:48:02 +07:00
|
|
|
context1 = sidtab_search(sidtab, sid);
|
2006-07-25 13:27:16 +07:00
|
|
|
if (!context1) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, sid);
|
2006-07-25 13:27:16 +07:00
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2018-03-02 06:48:02 +07:00
|
|
|
context2 = sidtab_search(sidtab, mls_sid);
|
2006-07-25 13:27:16 +07:00
|
|
|
if (!context2) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, mls_sid);
|
2006-07-25 13:27:16 +07:00
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
newcon.user = context1->user;
|
|
|
|
newcon.role = context1->role;
|
|
|
|
newcon.type = context1->type;
|
2006-12-13 02:02:41 +07:00
|
|
|
rc = mls_context_cpy(&newcon, context2);
|
2006-07-25 13:27:16 +07:00
|
|
|
if (rc)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
/* Check the validity of the new context. */
|
2018-03-02 06:48:02 +07:00
|
|
|
if (!policydb_context_isvalid(policydb, &newcon)) {
|
2020-08-20 02:45:16 +07:00
|
|
|
rc = convert_context_handle_invalid_context(state, policydb,
|
|
|
|
&newcon);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (rc) {
|
2018-03-02 06:48:02 +07:00
|
|
|
if (!context_struct_to_string(policydb, &newcon, &s,
|
|
|
|
&len)) {
|
2019-06-27 23:48:01 +07:00
|
|
|
struct audit_buffer *ab;
|
|
|
|
|
|
|
|
ab = audit_log_start(audit_context(),
|
|
|
|
GFP_ATOMIC,
|
|
|
|
AUDIT_SELINUX_ERR);
|
|
|
|
audit_log_format(ab,
|
|
|
|
"op=security_sid_mls_copy invalid_context=");
|
|
|
|
/* don't record NUL with untrusted strings */
|
|
|
|
audit_log_n_untrustedstring(ab, s, len - 1);
|
|
|
|
audit_log_end(ab);
|
2010-11-23 23:40:08 +07:00
|
|
|
kfree(s);
|
|
|
|
}
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
2006-07-25 13:27:16 +07:00
|
|
|
}
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
|
2006-07-25 13:27:16 +07:00
|
|
|
out_unlock:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2006-07-25 13:27:16 +07:00
|
|
|
context_destroy(&newcon);
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-01-29 20:38:23 +07:00
|
|
|
/**
|
|
|
|
* security_net_peersid_resolve - Compare and resolve two network peer SIDs
|
|
|
|
* @nlbl_sid: NetLabel SID
|
|
|
|
* @nlbl_type: NetLabel labeling protocol type
|
|
|
|
* @xfrm_sid: XFRM SID
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
|
|
|
|
* resolved into a single SID it is returned via @peer_sid and the function
|
|
|
|
* returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function
|
|
|
|
* returns a negative value. A table summarizing the behavior is below:
|
|
|
|
*
|
|
|
|
* | function return | @sid
|
|
|
|
* ------------------------------+-----------------+-----------------
|
|
|
|
* no peer labels | 0 | SECSID_NULL
|
|
|
|
* single peer label | 0 | <peer_label>
|
|
|
|
* multiple, consistent labels | 0 | <peer_label>
|
|
|
|
* multiple, inconsistent labels | -<errno> | SECSID_NULL
|
|
|
|
*
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_net_peersid_resolve(struct selinux_state *state,
|
|
|
|
u32 nlbl_sid, u32 nlbl_type,
|
2008-01-29 20:38:23 +07:00
|
|
|
u32 xfrm_sid,
|
|
|
|
u32 *peer_sid)
|
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2020-08-07 20:29:33 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2008-01-29 20:38:23 +07:00
|
|
|
int rc;
|
|
|
|
struct context *nlbl_ctx;
|
|
|
|
struct context *xfrm_ctx;
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
*peer_sid = SECSID_NULL;
|
|
|
|
|
2008-01-29 20:38:23 +07:00
|
|
|
/* handle the common (which also happens to be the set of easy) cases
|
|
|
|
* right away, these two if statements catch everything involving a
|
|
|
|
* single or absent peer SID/label */
|
|
|
|
if (xfrm_sid == SECSID_NULL) {
|
|
|
|
*peer_sid = nlbl_sid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
|
|
|
|
* and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
|
|
|
|
* is present */
|
|
|
|
if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
|
|
|
|
*peer_sid = xfrm_sid;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2020-08-07 20:29:33 +07:00
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
/*
|
|
|
|
* We don't need to check initialized here since the only way both
|
2008-01-29 20:38:23 +07:00
|
|
|
* nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
|
2018-03-02 06:48:02 +07:00
|
|
|
* security server was initialized and state->initialized was true.
|
|
|
|
*/
|
2020-08-07 20:29:33 +07:00
|
|
|
if (!policydb->mls_enabled) {
|
|
|
|
rc = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
2008-01-29 20:38:23 +07:00
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2018-03-02 06:48:02 +07:00
|
|
|
nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
|
2008-01-29 20:38:23 +07:00
|
|
|
if (!nlbl_ctx) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, nlbl_sid);
|
2010-11-23 23:40:08 +07:00
|
|
|
goto out;
|
2008-01-29 20:38:23 +07:00
|
|
|
}
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2018-03-02 06:48:02 +07:00
|
|
|
xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
|
2008-01-29 20:38:23 +07:00
|
|
|
if (!xfrm_ctx) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized SID %d\n",
|
2008-04-17 22:52:44 +07:00
|
|
|
__func__, xfrm_sid);
|
2010-11-23 23:40:08 +07:00
|
|
|
goto out;
|
2008-01-29 20:38:23 +07:00
|
|
|
}
|
|
|
|
rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
2008-01-29 20:38:23 +07:00
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
/* at present NetLabel SIDs/labels really only carry MLS
|
|
|
|
* information so if the MLS portion of the NetLabel SID
|
|
|
|
* matches the MLS portion of the labeled XFRM SID/label
|
|
|
|
* then pass along the XFRM SID as it is the most
|
|
|
|
* expressive */
|
|
|
|
*peer_sid = xfrm_sid;
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2008-01-29 20:38:23 +07:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-05-23 20:12:06 +07:00
|
|
|
static int get_classes_callback(void *k, void *d, void *args)
|
|
|
|
{
|
|
|
|
struct class_datum *datum = d;
|
|
|
|
char *name = k, **classes = args;
|
|
|
|
int value = datum->value - 1;
|
|
|
|
|
|
|
|
classes[value] = kstrdup(name, GFP_ATOMIC);
|
|
|
|
if (!classes[value])
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
int security_get_classes(struct selinux_policy *policy,
|
2018-03-02 06:48:02 +07:00
|
|
|
char ***classes, int *nclasses)
|
2007-05-23 20:12:06 +07:00
|
|
|
{
|
2020-08-07 20:29:33 +07:00
|
|
|
struct policydb *policydb;
|
2010-11-23 23:40:08 +07:00
|
|
|
int rc;
|
2007-05-23 20:12:06 +07:00
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
policydb = &policy->policydb;
|
2020-08-07 20:29:33 +07:00
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOMEM;
|
2018-03-02 06:48:02 +07:00
|
|
|
*nclasses = policydb->p_classes.nprim;
|
2009-12-06 16:16:51 +07:00
|
|
|
*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
|
2007-05-23 20:12:06 +07:00
|
|
|
if (!*classes)
|
|
|
|
goto out;
|
|
|
|
|
2020-04-28 19:55:12 +07:00
|
|
|
rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
|
|
|
|
*classes);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (rc) {
|
2007-05-23 20:12:06 +07:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < *nclasses; i++)
|
|
|
|
kfree((*classes)[i]);
|
|
|
|
kfree(*classes);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_permissions_callback(void *k, void *d, void *args)
|
|
|
|
{
|
|
|
|
struct perm_datum *datum = d;
|
|
|
|
char *name = k, **perms = args;
|
|
|
|
int value = datum->value - 1;
|
|
|
|
|
|
|
|
perms[value] = kstrdup(name, GFP_ATOMIC);
|
|
|
|
if (!perms[value])
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
int security_get_permissions(struct selinux_policy *policy,
|
2018-03-02 06:48:02 +07:00
|
|
|
char *class, char ***perms, int *nperms)
|
2007-05-23 20:12:06 +07:00
|
|
|
{
|
2020-08-07 20:29:33 +07:00
|
|
|
struct policydb *policydb;
|
2010-11-23 23:40:08 +07:00
|
|
|
int rc, i;
|
2007-05-23 20:12:06 +07:00
|
|
|
struct class_datum *match;
|
|
|
|
|
2020-08-07 20:29:34 +07:00
|
|
|
policydb = &policy->policydb;
|
2020-08-07 20:29:33 +07:00
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2020-07-08 18:24:45 +07:00
|
|
|
match = symtab_search(&policydb->p_classes, class);
|
2007-05-23 20:12:06 +07:00
|
|
|
if (!match) {
|
2018-06-12 15:09:05 +07:00
|
|
|
pr_err("SELinux: %s: unrecognized class %s\n",
|
2008-03-06 06:03:59 +07:00
|
|
|
__func__, class);
|
2007-05-23 20:12:06 +07:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOMEM;
|
2007-05-23 20:12:06 +07:00
|
|
|
*nperms = match->permissions.nprim;
|
2009-12-06 16:16:51 +07:00
|
|
|
*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
|
2007-05-23 20:12:06 +07:00
|
|
|
if (!*perms)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (match->comdatum) {
|
2020-04-28 19:55:12 +07:00
|
|
|
rc = hashtab_map(&match->comdatum->permissions.table,
|
|
|
|
get_permissions_callback, *perms);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (rc)
|
2007-05-23 20:12:06 +07:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2020-04-28 19:55:12 +07:00
|
|
|
rc = hashtab_map(&match->permissions.table, get_permissions_callback,
|
|
|
|
*perms);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (rc)
|
2007-05-23 20:12:06 +07:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
err:
|
|
|
|
for (i = 0; i < *nperms; i++)
|
|
|
|
kfree((*perms)[i]);
|
|
|
|
kfree(*perms);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_get_reject_unknown(struct selinux_state *state)
|
2007-09-22 01:37:10 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2020-08-07 20:29:33 +07:00
|
|
|
int value;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
value = policy->policydb.reject_unknown;
|
|
|
|
rcu_read_unlock();
|
2020-08-07 20:29:33 +07:00
|
|
|
return value;
|
2007-09-22 01:37:10 +07:00
|
|
|
}
|
|
|
|
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_get_allow_unknown(struct selinux_state *state)
|
2007-09-22 01:37:10 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2020-08-07 20:29:33 +07:00
|
|
|
int value;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
value = policy->policydb.allow_unknown;
|
|
|
|
rcu_read_unlock();
|
2020-08-07 20:29:33 +07:00
|
|
|
return value;
|
2007-09-22 01:37:10 +07:00
|
|
|
}
|
|
|
|
|
2008-01-29 20:38:19 +07:00
|
|
|
/**
|
|
|
|
* security_policycap_supported - Check for a specific policy capability
|
|
|
|
* @req_cap: capability
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* This function queries the currently loaded policy to see if it supports the
|
|
|
|
* capability specified by @req_cap. Returns true (1) if the capability is
|
|
|
|
* supported, false (0) if it isn't supported.
|
|
|
|
*
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_policycap_supported(struct selinux_state *state,
|
|
|
|
unsigned int req_cap)
|
2008-01-29 20:38:19 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2008-01-29 20:38:19 +07:00
|
|
|
int rc;
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
|
|
|
|
rcu_read_unlock();
|
2008-01-29 20:38:19 +07:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2006-02-25 04:44:05 +07:00
|
|
|
struct selinux_audit_rule {
|
|
|
|
u32 au_seqno;
|
|
|
|
struct context au_ctxt;
|
|
|
|
};
|
|
|
|
|
2008-03-02 03:03:14 +07:00
|
|
|
void selinux_audit_rule_free(void *vrule)
|
2006-02-25 04:44:05 +07:00
|
|
|
{
|
2008-03-02 03:03:14 +07:00
|
|
|
struct selinux_audit_rule *rule = vrule;
|
|
|
|
|
2006-02-25 04:44:05 +07:00
|
|
|
if (rule) {
|
|
|
|
context_destroy(&rule->au_ctxt);
|
|
|
|
kfree(rule);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-02 03:03:14 +07:00
|
|
|
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
|
2006-02-25 04:44:05 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
struct selinux_state *state = &selinux_state;
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2020-08-07 20:29:33 +07:00
|
|
|
struct policydb *policydb;
|
2006-02-25 04:44:05 +07:00
|
|
|
struct selinux_audit_rule *tmprule;
|
|
|
|
struct role_datum *roledatum;
|
|
|
|
struct type_datum *typedatum;
|
|
|
|
struct user_datum *userdatum;
|
2008-03-02 03:03:14 +07:00
|
|
|
struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
|
2006-02-25 04:44:05 +07:00
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
*rule = NULL;
|
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state))
|
2007-08-15 02:50:46 +07:00
|
|
|
return -EOPNOTSUPP;
|
2006-02-25 04:44:05 +07:00
|
|
|
|
|
|
|
switch (field) {
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_USER:
|
|
|
|
case AUDIT_SUBJ_ROLE:
|
|
|
|
case AUDIT_SUBJ_TYPE:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_USER:
|
|
|
|
case AUDIT_OBJ_ROLE:
|
|
|
|
case AUDIT_OBJ_TYPE:
|
2006-02-25 04:44:05 +07:00
|
|
|
/* only 'equals' and 'not equals' fit user, role, and type */
|
2008-12-16 17:59:26 +07:00
|
|
|
if (op != Audit_equal && op != Audit_not_equal)
|
2006-02-25 04:44:05 +07:00
|
|
|
return -EINVAL;
|
|
|
|
break;
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_SEN:
|
|
|
|
case AUDIT_SUBJ_CLR:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_LEV_LOW:
|
|
|
|
case AUDIT_OBJ_LEV_HIGH:
|
2011-03-31 08:57:33 +07:00
|
|
|
/* we do not allow a range, indicated by the presence of '-' */
|
2006-02-25 04:44:05 +07:00
|
|
|
if (strchr(rulestr, '-'))
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* only the above fields are valid */
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
|
|
|
|
if (!tmprule)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
context_init(&tmprule->au_ctxt);
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
2020-08-07 20:29:33 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
tmprule->au_seqno = policy->latest_granting;
|
2006-02-25 04:44:05 +07:00
|
|
|
|
|
|
|
switch (field) {
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_USER:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_USER:
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2020-07-08 18:24:45 +07:00
|
|
|
userdatum = symtab_search(&policydb->p_users, rulestr);
|
2006-02-25 04:44:05 +07:00
|
|
|
if (!userdatum)
|
2010-11-23 23:40:08 +07:00
|
|
|
goto out;
|
|
|
|
tmprule->au_ctxt.user = userdatum->value;
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_ROLE:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_ROLE:
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2020-07-08 18:24:45 +07:00
|
|
|
roledatum = symtab_search(&policydb->p_roles, rulestr);
|
2006-02-25 04:44:05 +07:00
|
|
|
if (!roledatum)
|
2010-11-23 23:40:08 +07:00
|
|
|
goto out;
|
|
|
|
tmprule->au_ctxt.role = roledatum->value;
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_TYPE:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_TYPE:
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -EINVAL;
|
2020-07-08 18:24:45 +07:00
|
|
|
typedatum = symtab_search(&policydb->p_types, rulestr);
|
2006-02-25 04:44:05 +07:00
|
|
|
if (!typedatum)
|
2010-11-23 23:40:08 +07:00
|
|
|
goto out;
|
|
|
|
tmprule->au_ctxt.type = typedatum->value;
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_SEN:
|
|
|
|
case AUDIT_SUBJ_CLR:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_LEV_LOW:
|
|
|
|
case AUDIT_OBJ_LEV_HIGH:
|
2018-03-02 06:48:02 +07:00
|
|
|
rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
|
|
|
|
GFP_ATOMIC);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
|
|
|
}
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = 0;
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2006-02-25 04:44:05 +07:00
|
|
|
|
|
|
|
if (rc) {
|
|
|
|
selinux_audit_rule_free(tmprule);
|
|
|
|
tmprule = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rule = tmprule;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-03-02 03:03:14 +07:00
|
|
|
/* Check to see if the rule contains any selinux fields */
|
|
|
|
int selinux_audit_rule_known(struct audit_krule *rule)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < rule->field_count; i++) {
|
|
|
|
struct audit_field *f = &rule->fields[i];
|
|
|
|
switch (f->type) {
|
|
|
|
case AUDIT_SUBJ_USER:
|
|
|
|
case AUDIT_SUBJ_ROLE:
|
|
|
|
case AUDIT_SUBJ_TYPE:
|
|
|
|
case AUDIT_SUBJ_SEN:
|
|
|
|
case AUDIT_SUBJ_CLR:
|
|
|
|
case AUDIT_OBJ_USER:
|
|
|
|
case AUDIT_OBJ_ROLE:
|
|
|
|
case AUDIT_OBJ_TYPE:
|
|
|
|
case AUDIT_OBJ_LEV_LOW:
|
|
|
|
case AUDIT_OBJ_LEV_HIGH:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-31 23:52:11 +07:00
|
|
|
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
|
2006-02-25 04:44:05 +07:00
|
|
|
{
|
2018-03-02 06:48:02 +07:00
|
|
|
struct selinux_state *state = &selinux_state;
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2006-02-25 04:44:05 +07:00
|
|
|
struct context *ctxt;
|
|
|
|
struct mls_level *level;
|
2008-03-02 03:03:14 +07:00
|
|
|
struct selinux_audit_rule *rule = vrule;
|
2006-02-25 04:44:05 +07:00
|
|
|
int match = 0;
|
|
|
|
|
2013-11-22 01:31:40 +07:00
|
|
|
if (unlikely(!rule)) {
|
|
|
|
WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
|
2006-02-25 04:44:05 +07:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2020-08-19 20:45:41 +07:00
|
|
|
if (!selinux_initialized(state))
|
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
policy = rcu_dereference(state->policy);
|
2006-02-25 04:44:05 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
if (rule->au_seqno < policy->latest_granting) {
|
2006-02-25 04:44:05 +07:00
|
|
|
match = -ESTALE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
ctxt = sidtab_search(policy->sidtab, sid);
|
2013-11-22 01:31:40 +07:00
|
|
|
if (unlikely(!ctxt)) {
|
|
|
|
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
|
2008-04-19 04:38:33 +07:00
|
|
|
sid);
|
2006-02-25 04:44:05 +07:00
|
|
|
match = -ENOENT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* a field/op pair that is not caught here will simply fall through
|
|
|
|
without a match */
|
|
|
|
switch (field) {
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_USER:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_USER:
|
2006-02-25 04:44:05 +07:00
|
|
|
switch (op) {
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_equal:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = (ctxt->user == rule->au_ctxt.user);
|
|
|
|
break;
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_not_equal:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = (ctxt->user != rule->au_ctxt.user);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_ROLE:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_ROLE:
|
2006-02-25 04:44:05 +07:00
|
|
|
switch (op) {
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_equal:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = (ctxt->role == rule->au_ctxt.role);
|
|
|
|
break;
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_not_equal:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = (ctxt->role != rule->au_ctxt.role);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_TYPE:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_TYPE:
|
2006-02-25 04:44:05 +07:00
|
|
|
switch (op) {
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_equal:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = (ctxt->type == rule->au_ctxt.type);
|
|
|
|
break;
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_not_equal:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = (ctxt->type != rule->au_ctxt.type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2006-06-30 04:56:39 +07:00
|
|
|
case AUDIT_SUBJ_SEN:
|
|
|
|
case AUDIT_SUBJ_CLR:
|
2006-06-30 04:57:08 +07:00
|
|
|
case AUDIT_OBJ_LEV_LOW:
|
|
|
|
case AUDIT_OBJ_LEV_HIGH:
|
|
|
|
level = ((field == AUDIT_SUBJ_SEN ||
|
2008-04-19 04:38:33 +07:00
|
|
|
field == AUDIT_OBJ_LEV_LOW) ?
|
|
|
|
&ctxt->range.level[0] : &ctxt->range.level[1]);
|
2006-02-25 04:44:05 +07:00
|
|
|
switch (op) {
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_equal:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = mls_level_eq(&rule->au_ctxt.range.level[0],
|
2008-04-19 04:38:33 +07:00
|
|
|
level);
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_not_equal:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = !mls_level_eq(&rule->au_ctxt.range.level[0],
|
2008-04-19 04:38:33 +07:00
|
|
|
level);
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_lt:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = (mls_level_dom(&rule->au_ctxt.range.level[0],
|
2008-04-19 04:38:33 +07:00
|
|
|
level) &&
|
|
|
|
!mls_level_eq(&rule->au_ctxt.range.level[0],
|
|
|
|
level));
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_le:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = mls_level_dom(&rule->au_ctxt.range.level[0],
|
2008-04-19 04:38:33 +07:00
|
|
|
level);
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_gt:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = (mls_level_dom(level,
|
2008-04-19 04:38:33 +07:00
|
|
|
&rule->au_ctxt.range.level[0]) &&
|
|
|
|
!mls_level_eq(level,
|
|
|
|
&rule->au_ctxt.range.level[0]));
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
2008-12-16 17:59:26 +07:00
|
|
|
case Audit_ge:
|
2006-02-25 04:44:05 +07:00
|
|
|
match = mls_level_dom(level,
|
2008-04-19 04:38:33 +07:00
|
|
|
&rule->au_ctxt.range.level[0]);
|
2006-02-25 04:44:05 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2006-02-25 04:44:05 +07:00
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
2008-03-02 03:03:14 +07:00
|
|
|
static int (*aurule_callback)(void) = audit_update_lsm_rules;
|
2006-02-25 04:44:05 +07:00
|
|
|
|
2012-03-07 21:17:14 +07:00
|
|
|
static int aurule_avc_callback(u32 event)
|
2006-02-25 04:44:05 +07:00
|
|
|
{
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (event == AVC_CALLBACK_RESET && aurule_callback)
|
|
|
|
err = aurule_callback();
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init aurule_init(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2012-03-07 21:17:14 +07:00
|
|
|
err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
|
2006-02-25 04:44:05 +07:00
|
|
|
if (err)
|
|
|
|
panic("avc_add_callback() failed, error %d\n", err);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
__initcall(aurule_init);
|
|
|
|
|
2006-08-05 13:17:57 +07:00
|
|
|
#ifdef CONFIG_NETLABEL
|
|
|
|
/**
|
2007-03-01 03:14:22 +07:00
|
|
|
* security_netlbl_cache_add - Add an entry to the NetLabel cache
|
|
|
|
* @secattr: the NetLabel packet security attributes
|
2008-01-29 20:44:18 +07:00
|
|
|
* @sid: the SELinux SID
|
2006-08-05 13:17:57 +07:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Attempt to cache the context in @ctx, which was derived from the packet in
|
2007-03-01 03:14:22 +07:00
|
|
|
* @skb, in the NetLabel subsystem cache. This function assumes @secattr has
|
|
|
|
* already been initialized.
|
2006-08-05 13:17:57 +07:00
|
|
|
*
|
|
|
|
*/
|
2007-03-01 03:14:22 +07:00
|
|
|
static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
|
2008-01-29 20:44:18 +07:00
|
|
|
u32 sid)
|
2006-08-05 13:17:57 +07:00
|
|
|
{
|
2008-01-29 20:44:18 +07:00
|
|
|
u32 *sid_cache;
|
2006-08-05 13:17:57 +07:00
|
|
|
|
2008-01-29 20:44:18 +07:00
|
|
|
sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
|
|
|
|
if (sid_cache == NULL)
|
2007-03-01 03:14:22 +07:00
|
|
|
return;
|
2008-01-29 20:44:18 +07:00
|
|
|
secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
|
|
|
|
if (secattr->cache == NULL) {
|
|
|
|
kfree(sid_cache);
|
2007-03-01 03:14:22 +07:00
|
|
|
return;
|
2007-07-21 05:12:44 +07:00
|
|
|
}
|
2006-08-05 13:17:57 +07:00
|
|
|
|
2008-01-29 20:44:18 +07:00
|
|
|
*sid_cache = sid;
|
|
|
|
secattr->cache->free = kfree;
|
|
|
|
secattr->cache->data = sid_cache;
|
2007-03-01 03:14:22 +07:00
|
|
|
secattr->flags |= NETLBL_SECATTR_CACHE;
|
2006-08-05 13:17:57 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-03-01 03:14:22 +07:00
|
|
|
* security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
|
2006-08-05 13:17:57 +07:00
|
|
|
* @secattr: the NetLabel packet security attributes
|
|
|
|
* @sid: the SELinux SID
|
|
|
|
*
|
|
|
|
* Description:
|
2007-03-01 03:14:22 +07:00
|
|
|
* Convert the given NetLabel security attributes in @secattr into a
|
2006-08-05 13:17:57 +07:00
|
|
|
* SELinux SID. If the @secattr field does not contain a full SELinux
|
2011-03-31 08:57:33 +07:00
|
|
|
* SID/context then use SECINITSID_NETMSG as the foundation. If possible the
|
2008-01-29 20:44:18 +07:00
|
|
|
* 'cache' field of @secattr is set and the CACHE flag is set; this is to
|
|
|
|
* allow the @secattr to be used by NetLabel to cache the secattr to SID
|
|
|
|
* conversion for future lookups. Returns zero on success, negative values on
|
|
|
|
* failure.
|
2006-08-05 13:17:57 +07:00
|
|
|
*
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_netlbl_secattr_to_sid(struct selinux_state *state,
|
|
|
|
struct netlbl_lsm_secattr *secattr,
|
2007-03-01 03:14:22 +07:00
|
|
|
u32 *sid)
|
2006-08-05 13:17:57 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2020-08-07 20:29:33 +07:00
|
|
|
struct policydb *policydb;
|
|
|
|
struct sidtab *sidtab;
|
2010-11-23 23:40:09 +07:00
|
|
|
int rc;
|
2006-08-05 13:17:57 +07:00
|
|
|
struct context *ctx;
|
|
|
|
struct context ctx_new;
|
2007-03-01 03:14:22 +07:00
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state)) {
|
2007-03-01 03:14:22 +07:00
|
|
|
*sid = SECSID_NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
2006-08-05 13:17:57 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
|
|
|
sidtab = policy->sidtab;
|
2020-08-07 20:29:33 +07:00
|
|
|
|
2010-11-23 23:40:09 +07:00
|
|
|
if (secattr->flags & NETLBL_SECATTR_CACHE)
|
2008-01-29 20:44:18 +07:00
|
|
|
*sid = *(u32 *)secattr->cache->data;
|
2010-11-23 23:40:09 +07:00
|
|
|
else if (secattr->flags & NETLBL_SECATTR_SECID)
|
2008-01-29 20:37:59 +07:00
|
|
|
*sid = secattr->attr.secid;
|
2010-11-23 23:40:09 +07:00
|
|
|
else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
|
|
|
|
rc = -EIDRM;
|
2018-03-02 06:48:02 +07:00
|
|
|
ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
|
2006-08-05 13:17:57 +07:00
|
|
|
if (ctx == NULL)
|
2010-11-23 23:40:09 +07:00
|
|
|
goto out;
|
2006-08-05 13:17:57 +07:00
|
|
|
|
2008-10-03 21:51:15 +07:00
|
|
|
context_init(&ctx_new);
|
2006-08-05 13:17:57 +07:00
|
|
|
ctx_new.user = ctx->user;
|
|
|
|
ctx_new.role = ctx->role;
|
|
|
|
ctx_new.type = ctx->type;
|
2018-03-02 06:48:02 +07:00
|
|
|
mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
|
2006-11-18 05:38:46 +07:00
|
|
|
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
|
2018-03-02 06:48:02 +07:00
|
|
|
rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
|
2010-11-23 23:40:09 +07:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
2006-08-05 13:17:57 +07:00
|
|
|
}
|
2010-11-23 23:40:09 +07:00
|
|
|
rc = -EIDRM;
|
2018-03-02 06:48:02 +07:00
|
|
|
if (!mls_context_isvalid(policydb, &ctx_new))
|
2010-11-23 23:40:09 +07:00
|
|
|
goto out_free;
|
2006-08-05 13:17:57 +07:00
|
|
|
|
2020-04-17 15:11:57 +07:00
|
|
|
rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
|
2010-11-23 23:40:09 +07:00
|
|
|
if (rc)
|
|
|
|
goto out_free;
|
2006-08-05 13:17:57 +07:00
|
|
|
|
2008-01-29 20:44:18 +07:00
|
|
|
security_netlbl_cache_add(secattr, *sid);
|
2007-03-01 03:14:22 +07:00
|
|
|
|
2006-08-05 13:17:57 +07:00
|
|
|
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
2010-11-23 23:40:09 +07:00
|
|
|
} else
|
2006-10-06 05:28:24 +07:00
|
|
|
*sid = SECSID_NULL;
|
2006-08-05 13:17:57 +07:00
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2010-11-23 23:40:09 +07:00
|
|
|
return 0;
|
|
|
|
out_free:
|
2006-08-05 13:17:57 +07:00
|
|
|
ebitmap_destroy(&ctx_new.range.level[0].cat);
|
2010-11-23 23:40:09 +07:00
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2010-11-23 23:40:09 +07:00
|
|
|
return rc;
|
2006-08-05 13:17:57 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-03-01 03:14:22 +07:00
|
|
|
* security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
|
|
|
|
* @sid: the SELinux SID
|
|
|
|
* @secattr: the NetLabel packet security attributes
|
2006-08-05 13:17:57 +07:00
|
|
|
*
|
|
|
|
* Description:
|
2007-03-01 03:14:22 +07:00
|
|
|
* Convert the given SELinux SID in @sid into a NetLabel security attribute.
|
|
|
|
* Returns zero on success, negative values on failure.
|
2006-08-05 13:17:57 +07:00
|
|
|
*
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_netlbl_sid_to_secattr(struct selinux_state *state,
|
|
|
|
u32 sid, struct netlbl_lsm_secattr *secattr)
|
2006-08-05 13:17:57 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2020-08-07 20:29:33 +07:00
|
|
|
struct policydb *policydb;
|
2008-10-10 21:16:30 +07:00
|
|
|
int rc;
|
2006-08-05 13:17:57 +07:00
|
|
|
struct context *ctx;
|
|
|
|
|
2020-01-07 20:31:53 +07:00
|
|
|
if (!selinux_initialized(state))
|
2006-08-05 13:17:57 +07:00
|
|
|
return 0;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_lock();
|
|
|
|
policy = rcu_dereference(state->policy);
|
|
|
|
policydb = &policy->policydb;
|
2020-08-07 20:29:33 +07:00
|
|
|
|
2010-11-23 23:40:08 +07:00
|
|
|
rc = -ENOENT;
|
2020-08-20 02:45:16 +07:00
|
|
|
ctx = sidtab_search(policy->sidtab, sid);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (ctx == NULL)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = -ENOMEM;
|
2018-03-02 06:48:02 +07:00
|
|
|
secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
|
2007-03-01 03:14:22 +07:00
|
|
|
GFP_ATOMIC);
|
2010-11-23 23:40:08 +07:00
|
|
|
if (secattr->domain == NULL)
|
|
|
|
goto out;
|
|
|
|
|
2008-10-10 21:16:33 +07:00
|
|
|
secattr->attr.secid = sid;
|
|
|
|
secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
|
2018-03-02 06:48:02 +07:00
|
|
|
mls_export_netlbl_lvl(policydb, ctx, secattr);
|
|
|
|
rc = mls_export_netlbl_cat(policydb, ctx, secattr);
|
2010-11-23 23:40:08 +07:00
|
|
|
out:
|
2020-08-20 02:45:16 +07:00
|
|
|
rcu_read_unlock();
|
2006-10-31 06:22:15 +07:00
|
|
|
return rc;
|
|
|
|
}
|
2006-08-05 13:17:57 +07:00
|
|
|
#endif /* CONFIG_NETLABEL */
|
2010-10-14 04:50:25 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* security_read_policy - read the policy.
|
|
|
|
* @data: binary policy data
|
|
|
|
* @len: length of data in bytes
|
|
|
|
*
|
|
|
|
*/
|
2018-03-02 06:48:02 +07:00
|
|
|
int security_read_policy(struct selinux_state *state,
|
|
|
|
void **data, size_t *len)
|
2010-10-14 04:50:25 +07:00
|
|
|
{
|
2020-08-20 02:45:16 +07:00
|
|
|
struct selinux_policy *policy;
|
2010-10-14 04:50:25 +07:00
|
|
|
int rc;
|
|
|
|
struct policy_file fp;
|
|
|
|
|
2020-08-27 23:27:53 +07:00
|
|
|
policy = rcu_dereference_protected(
|
|
|
|
state->policy, lockdep_is_held(&state->policy_mutex));
|
|
|
|
if (!policy)
|
2010-10-14 04:50:25 +07:00
|
|
|
return -EINVAL;
|
|
|
|
|
2020-08-27 23:27:53 +07:00
|
|
|
*len = policy->policydb.len;
|
2010-10-14 04:50:31 +07:00
|
|
|
*data = vmalloc_user(*len);
|
2010-10-14 04:50:25 +07:00
|
|
|
if (!*data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
fp.data = *data;
|
|
|
|
fp.len = *len;
|
|
|
|
|
2020-08-20 02:45:16 +07:00
|
|
|
rc = policydb_write(&policy->policydb, &fp);
|
2010-10-14 04:50:25 +07:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
*len = (unsigned long)fp.data - (unsigned long)*data;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|