2019-05-31 16:09:32 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Implementation of the policy database.
|
|
|
|
*
|
2017-08-18 01:32:36 +08:00
|
|
|
* Author : Stephen Smalley, <sds@tycho.nsa.gov>
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
|
|
|
|
*
|
|
|
|
* Support for enhanced MLS infrastructure.
|
|
|
|
*
|
|
|
|
* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
|
|
|
|
*
|
2008-04-18 01:37:12 +08:00
|
|
|
* Added conditional policy language extensions
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2011-08-01 19:10:33 +08:00
|
|
|
* Updated: Hewlett-Packard <paul@paul-moore.com>
|
2008-01-29 21:38:19 +08:00
|
|
|
*
|
|
|
|
* Added support for the policy capability bitmap
|
|
|
|
*
|
2017-05-19 20:48:55 +08:00
|
|
|
* Update: Mellanox Techonologies
|
|
|
|
*
|
|
|
|
* Added Infiniband support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016 Mellanox Techonologies
|
2008-01-29 21:38:19 +08:00
|
|
|
* Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
|
2005-04-17 06:20:36 +08:00
|
|
|
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
|
|
|
|
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
2007-06-05 05:41:22 +08:00
|
|
|
#include <linux/sched.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/errno.h>
|
2008-08-28 15:35:57 +08:00
|
|
|
#include <linux/audit.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include "security.h"
|
|
|
|
|
|
|
|
#include "policydb.h"
|
|
|
|
#include "conditional.h"
|
|
|
|
#include "mls.h"
|
2010-10-14 05:50:25 +08:00
|
|
|
#include "services.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#define _DEBUG_HASHES
|
|
|
|
|
|
|
|
#ifdef DEBUG_HASHES
|
2010-03-05 13:59:03 +08:00
|
|
|
static const char *symtab_name[SYM_NUM] = {
|
2005-04-17 06:20:36 +08:00
|
|
|
"common prefixes",
|
|
|
|
"classes",
|
|
|
|
"roles",
|
|
|
|
"types",
|
|
|
|
"users",
|
|
|
|
"bools",
|
|
|
|
"levels",
|
|
|
|
"categories",
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct policydb_compat_info {
|
|
|
|
int version;
|
|
|
|
int sym_num;
|
|
|
|
int ocon_num;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* These need to be updated if SYM_NUM or OCON_NUM changes */
|
|
|
|
static struct policydb_compat_info policydb_compat[] = {
|
|
|
|
{
|
2008-04-18 01:37:12 +08:00
|
|
|
.version = POLICYDB_VERSION_BASE,
|
|
|
|
.sym_num = SYM_NUM - 3,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 3,
|
2005-04-17 06:20:36 +08:00
|
|
|
},
|
|
|
|
{
|
2008-04-18 01:37:12 +08:00
|
|
|
.version = POLICYDB_VERSION_BOOL,
|
|
|
|
.sym_num = SYM_NUM - 2,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 3,
|
2005-04-17 06:20:36 +08:00
|
|
|
},
|
|
|
|
{
|
2008-04-18 01:37:12 +08:00
|
|
|
.version = POLICYDB_VERSION_IPV6,
|
|
|
|
.sym_num = SYM_NUM - 2,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2005-04-17 06:20:36 +08:00
|
|
|
},
|
|
|
|
{
|
2008-04-18 01:37:12 +08:00
|
|
|
.version = POLICYDB_VERSION_NLCLASS,
|
|
|
|
.sym_num = SYM_NUM - 2,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2005-04-17 06:20:36 +08:00
|
|
|
},
|
|
|
|
{
|
2008-04-18 01:37:12 +08:00
|
|
|
.version = POLICYDB_VERSION_MLS,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2005-04-17 06:20:36 +08:00
|
|
|
},
|
2005-09-04 06:55:16 +08:00
|
|
|
{
|
2008-04-18 01:37:12 +08:00
|
|
|
.version = POLICYDB_VERSION_AVTAB,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2005-09-04 06:55:16 +08:00
|
|
|
},
|
2006-09-26 14:31:59 +08:00
|
|
|
{
|
2008-04-18 01:37:12 +08:00
|
|
|
.version = POLICYDB_VERSION_RANGETRANS,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2006-09-26 14:31:59 +08:00
|
|
|
},
|
2008-01-29 21:38:19 +08:00
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_POLCAP,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2008-03-31 09:17:33 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_PERMISSIVE,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2008-08-28 15:35:57 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_BOUNDARY,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2008-08-28 15:35:57 +08:00
|
|
|
},
|
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-02 00:05:40 +08:00
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_FILENAME_TRANS,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
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-02 00:05:40 +08:00
|
|
|
},
|
2011-03-25 13:51:56 +08:00
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_ROLETRANS,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2011-03-25 13:51:56 +08:00
|
|
|
},
|
2012-03-21 02:35:12 +08:00
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2012-03-21 02:35:12 +08:00
|
|
|
},
|
2012-03-21 02:35:12 +08:00
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_DEFAULT_TYPE,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2012-03-21 02:35:12 +08:00
|
|
|
},
|
2013-11-20 06:34:23 +08:00
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_CONSTRAINT_NAMES,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
2013-11-20 06:34:23 +08:00
|
|
|
},
|
2015-07-11 05:19:56 +08:00
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_XPERMS_IOCTL,
|
|
|
|
.sym_num = SYM_NUM,
|
2017-05-19 20:48:55 +08:00
|
|
|
.ocon_num = OCON_NUM - 2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_INFINIBAND,
|
|
|
|
.sym_num = SYM_NUM,
|
2015-07-11 05:19:56 +08:00
|
|
|
.ocon_num = OCON_NUM,
|
|
|
|
},
|
2019-09-05 05:03:23 +08:00
|
|
|
{
|
|
|
|
.version = POLICYDB_VERSION_GLBLUB,
|
|
|
|
.sym_num = SYM_NUM,
|
|
|
|
.ocon_num = OCON_NUM,
|
|
|
|
},
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct policydb_compat_info *policydb_lookup_compat(int version)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct policydb_compat_info *info = NULL;
|
|
|
|
|
2006-01-06 16:11:23 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(policydb_compat); i++) {
|
2005-04-17 06:20:36 +08:00
|
|
|
if (policydb_compat[i].version == version) {
|
|
|
|
info = &policydb_compat[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2019-08-01 07:29:14 +08:00
|
|
|
/*
|
|
|
|
* The following *_destroy functions are used to
|
|
|
|
* free any memory allocated for each kind of
|
|
|
|
* symbol data in the policy database.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int perm_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
kfree(key);
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int common_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
struct common_datum *comdatum;
|
|
|
|
|
|
|
|
kfree(key);
|
|
|
|
if (datum) {
|
|
|
|
comdatum = datum;
|
|
|
|
hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
|
|
|
|
hashtab_destroy(comdatum->permissions.table);
|
|
|
|
}
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void constraint_expr_destroy(struct constraint_expr *expr)
|
|
|
|
{
|
|
|
|
if (expr) {
|
|
|
|
ebitmap_destroy(&expr->names);
|
|
|
|
if (expr->type_names) {
|
|
|
|
ebitmap_destroy(&expr->type_names->types);
|
|
|
|
ebitmap_destroy(&expr->type_names->negset);
|
|
|
|
kfree(expr->type_names);
|
|
|
|
}
|
|
|
|
kfree(expr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cls_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
struct class_datum *cladatum;
|
|
|
|
struct constraint_node *constraint, *ctemp;
|
|
|
|
struct constraint_expr *e, *etmp;
|
|
|
|
|
|
|
|
kfree(key);
|
|
|
|
if (datum) {
|
|
|
|
cladatum = datum;
|
|
|
|
hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
|
|
|
|
hashtab_destroy(cladatum->permissions.table);
|
|
|
|
constraint = cladatum->constraints;
|
|
|
|
while (constraint) {
|
|
|
|
e = constraint->expr;
|
|
|
|
while (e) {
|
|
|
|
etmp = e;
|
|
|
|
e = e->next;
|
|
|
|
constraint_expr_destroy(etmp);
|
|
|
|
}
|
|
|
|
ctemp = constraint;
|
|
|
|
constraint = constraint->next;
|
|
|
|
kfree(ctemp);
|
|
|
|
}
|
|
|
|
|
|
|
|
constraint = cladatum->validatetrans;
|
|
|
|
while (constraint) {
|
|
|
|
e = constraint->expr;
|
|
|
|
while (e) {
|
|
|
|
etmp = e;
|
|
|
|
e = e->next;
|
|
|
|
constraint_expr_destroy(etmp);
|
|
|
|
}
|
|
|
|
ctemp = constraint;
|
|
|
|
constraint = constraint->next;
|
|
|
|
kfree(ctemp);
|
|
|
|
}
|
|
|
|
kfree(cladatum->comkey);
|
|
|
|
}
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int role_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
struct role_datum *role;
|
|
|
|
|
|
|
|
kfree(key);
|
|
|
|
if (datum) {
|
|
|
|
role = datum;
|
|
|
|
ebitmap_destroy(&role->dominates);
|
|
|
|
ebitmap_destroy(&role->types);
|
|
|
|
}
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int type_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
kfree(key);
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
struct user_datum *usrdatum;
|
|
|
|
|
|
|
|
kfree(key);
|
|
|
|
if (datum) {
|
|
|
|
usrdatum = datum;
|
|
|
|
ebitmap_destroy(&usrdatum->roles);
|
|
|
|
ebitmap_destroy(&usrdatum->range.level[0].cat);
|
|
|
|
ebitmap_destroy(&usrdatum->range.level[1].cat);
|
|
|
|
ebitmap_destroy(&usrdatum->dfltlevel.cat);
|
|
|
|
}
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sens_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
struct level_datum *levdatum;
|
|
|
|
|
|
|
|
kfree(key);
|
|
|
|
if (datum) {
|
|
|
|
levdatum = datum;
|
|
|
|
if (levdatum->level)
|
|
|
|
ebitmap_destroy(&levdatum->level->cat);
|
|
|
|
kfree(levdatum->level);
|
|
|
|
}
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cat_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
kfree(key);
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
|
|
|
|
{
|
|
|
|
common_destroy,
|
|
|
|
cls_destroy,
|
|
|
|
role_destroy,
|
|
|
|
type_destroy,
|
|
|
|
user_destroy,
|
|
|
|
cond_destroy_bool,
|
|
|
|
sens_destroy,
|
|
|
|
cat_destroy,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int filenametr_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
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 19:27:34 +08:00
|
|
|
struct filename_trans_key *ft = key;
|
|
|
|
struct filename_trans_datum *next, *d = datum;
|
2019-07-29 16:41:16 +08:00
|
|
|
|
2019-08-01 07:29:14 +08:00
|
|
|
kfree(ft->name);
|
|
|
|
kfree(key);
|
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 19:27:34 +08:00
|
|
|
do {
|
|
|
|
ebitmap_destroy(&d->stypes);
|
|
|
|
next = d->next;
|
|
|
|
kfree(d);
|
|
|
|
d = next;
|
|
|
|
} while (unlikely(d));
|
2019-08-01 07:29:14 +08:00
|
|
|
cond_resched();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int range_tr_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
struct mls_range *rt = datum;
|
2019-07-29 16:41:16 +08:00
|
|
|
|
2019-08-01 07:29:14 +08:00
|
|
|
kfree(key);
|
|
|
|
ebitmap_destroy(&rt->level[0].cat);
|
|
|
|
ebitmap_destroy(&rt->level[1].cat);
|
|
|
|
kfree(datum);
|
|
|
|
cond_resched();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-08 02:28:58 +08:00
|
|
|
static int role_tr_destroy(void *key, void *datum, void *p)
|
|
|
|
{
|
|
|
|
kfree(key);
|
|
|
|
kfree(datum);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-01 07:29:14 +08:00
|
|
|
static void ocontext_destroy(struct ocontext *c, int i)
|
|
|
|
{
|
|
|
|
if (!c)
|
|
|
|
return;
|
|
|
|
|
|
|
|
context_destroy(&c->context[0]);
|
|
|
|
context_destroy(&c->context[1]);
|
|
|
|
if (i == OCON_ISID || i == OCON_FS ||
|
|
|
|
i == OCON_NETIF || i == OCON_FSUSE)
|
|
|
|
kfree(c->u.name);
|
|
|
|
kfree(c);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Initialize the role table.
|
|
|
|
*/
|
|
|
|
static int roles_init(struct policydb *p)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
int rc;
|
|
|
|
struct role_datum *role;
|
|
|
|
|
2005-10-31 06:59:21 +08:00
|
|
|
role = kzalloc(sizeof(*role), GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!role)
|
2017-01-15 19:10:09 +08:00
|
|
|
return -ENOMEM;
|
2010-11-24 00:40:08 +08:00
|
|
|
|
|
|
|
rc = -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
role->value = ++p->p_roles.nprim;
|
2010-11-24 00:40:08 +08:00
|
|
|
if (role->value != OBJECT_R_VAL)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = -ENOMEM;
|
2010-05-15 03:30:30 +08:00
|
|
|
key = kstrdup(OBJECT_R, GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!key)
|
|
|
|
goto out;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = hashtab_insert(p->p_roles.table, key, role);
|
|
|
|
if (rc)
|
2010-11-24 00:40:08 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
|
|
|
out:
|
2005-04-17 06:20:36 +08:00
|
|
|
kfree(key);
|
|
|
|
kfree(role);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
static u32 filenametr_hash(struct hashtab *h, const void *k)
|
|
|
|
{
|
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 19:27:34 +08:00
|
|
|
const struct filename_trans_key *ft = k;
|
2011-04-29 03:11:21 +08:00
|
|
|
unsigned long hash;
|
|
|
|
unsigned int byte_num;
|
|
|
|
unsigned char focus;
|
|
|
|
|
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 19:27:34 +08:00
|
|
|
hash = ft->ttype ^ ft->tclass;
|
2011-04-29 03:11:21 +08:00
|
|
|
|
|
|
|
byte_num = 0;
|
|
|
|
while ((focus = ft->name[byte_num++]))
|
|
|
|
hash = partial_name_hash(focus, hash);
|
|
|
|
return hash & (h->size - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
|
|
|
|
{
|
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 19:27:34 +08:00
|
|
|
const struct filename_trans_key *ft1 = k1;
|
|
|
|
const struct filename_trans_key *ft2 = k2;
|
2011-04-29 03:11:21 +08:00
|
|
|
int v;
|
|
|
|
|
|
|
|
v = ft1->ttype - ft2->ttype;
|
|
|
|
if (v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
v = ft1->tclass - ft2->tclass;
|
|
|
|
if (v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
return strcmp(ft1->name, ft2->name);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-01-08 04:55:16 +08:00
|
|
|
static u32 rangetr_hash(struct hashtab *h, const void *k)
|
|
|
|
{
|
|
|
|
const struct range_trans *key = k;
|
2019-07-29 16:41:16 +08:00
|
|
|
|
2010-01-08 04:55:16 +08:00
|
|
|
return (key->source_type + (key->target_type << 3) +
|
|
|
|
(key->target_class << 5)) & (h->size - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
|
|
|
|
{
|
|
|
|
const struct range_trans *key1 = k1, *key2 = k2;
|
2010-10-14 05:50:14 +08:00
|
|
|
int v;
|
|
|
|
|
|
|
|
v = key1->source_type - key2->source_type;
|
|
|
|
if (v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
v = key1->target_type - key2->target_type;
|
|
|
|
if (v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
v = key1->target_class - key2->target_class;
|
|
|
|
|
|
|
|
return v;
|
2010-01-08 04:55:16 +08:00
|
|
|
}
|
|
|
|
|
2020-04-08 02:28:58 +08:00
|
|
|
static u32 role_trans_hash(struct hashtab *h, const void *k)
|
|
|
|
{
|
|
|
|
const struct role_trans_key *key = k;
|
|
|
|
|
|
|
|
return (key->role + (key->type << 3) + (key->tclass << 5)) &
|
|
|
|
(h->size - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int role_trans_cmp(struct hashtab *h, const void *k1, const void *k2)
|
|
|
|
{
|
|
|
|
const struct role_trans_key *key1 = k1, *key2 = k2;
|
|
|
|
int v;
|
|
|
|
|
|
|
|
v = key1->role - key2->role;
|
|
|
|
if (v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
v = key1->type - key2->type;
|
|
|
|
if (v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
return key1->tclass - key2->tclass;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Initialize a policy database structure.
|
|
|
|
*/
|
|
|
|
static int policydb_init(struct policydb *p)
|
|
|
|
{
|
|
|
|
memset(p, 0, sizeof(*p));
|
|
|
|
|
2020-03-06 03:55:43 +08:00
|
|
|
avtab_init(&p->te_avtab);
|
|
|
|
cond_policydb_init(p);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2019-07-29 16:41:16 +08:00
|
|
|
p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp,
|
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 19:27:34 +08:00
|
|
|
(1 << 11));
|
2020-03-03 19:29:10 +08:00
|
|
|
if (!p->filename_trans)
|
|
|
|
return -ENOMEM;
|
2011-04-29 03:11:21 +08:00
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
ebitmap_init(&p->filename_trans_ttypes);
|
2008-01-29 21:38:19 +08:00
|
|
|
ebitmap_init(&p->policycaps);
|
2008-03-31 09:17:33 +08:00
|
|
|
ebitmap_init(&p->permissive_map);
|
2008-01-29 21:38:19 +08:00
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The following *_index functions are used to
|
|
|
|
* define the val_to_name and val_to_struct arrays
|
|
|
|
* in a policy database structure. The val_to_name
|
|
|
|
* arrays are used when converting security context
|
|
|
|
* structures into string representations. The
|
|
|
|
* val_to_struct arrays are used when the attributes
|
|
|
|
* of a class, role, or user are needed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int common_index(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct policydb *p;
|
|
|
|
struct common_datum *comdatum;
|
|
|
|
|
|
|
|
comdatum = datum;
|
|
|
|
p = datap;
|
|
|
|
if (!comdatum->value || comdatum->value > p->p_commons.nprim)
|
|
|
|
return -EINVAL;
|
2010-11-30 04:47:09 +08:00
|
|
|
|
2019-03-12 14:31:10 +08:00
|
|
|
p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int class_index(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct policydb *p;
|
|
|
|
struct class_datum *cladatum;
|
|
|
|
|
|
|
|
cladatum = datum;
|
|
|
|
p = datap;
|
|
|
|
if (!cladatum->value || cladatum->value > p->p_classes.nprim)
|
|
|
|
return -EINVAL;
|
2019-03-12 14:31:10 +08:00
|
|
|
|
|
|
|
p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key;
|
2005-04-17 06:20:36 +08:00
|
|
|
p->class_val_to_struct[cladatum->value - 1] = cladatum;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int role_index(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct policydb *p;
|
|
|
|
struct role_datum *role;
|
|
|
|
|
|
|
|
role = datum;
|
|
|
|
p = datap;
|
2008-08-28 15:35:57 +08:00
|
|
|
if (!role->value
|
|
|
|
|| role->value > p->p_roles.nprim
|
|
|
|
|| role->bounds > p->p_roles.nprim)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EINVAL;
|
2010-11-30 04:47:09 +08:00
|
|
|
|
2019-03-12 14:31:10 +08:00
|
|
|
p->sym_val_to_name[SYM_ROLES][role->value - 1] = key;
|
2005-04-17 06:20:36 +08:00
|
|
|
p->role_val_to_struct[role->value - 1] = role;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int type_index(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct policydb *p;
|
|
|
|
struct type_datum *typdatum;
|
|
|
|
|
|
|
|
typdatum = datum;
|
|
|
|
p = datap;
|
|
|
|
|
|
|
|
if (typdatum->primary) {
|
2008-08-28 15:35:57 +08:00
|
|
|
if (!typdatum->value
|
|
|
|
|| typdatum->value > p->p_types.nprim
|
|
|
|
|| typdatum->bounds > p->p_types.nprim)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EINVAL;
|
2019-03-12 14:31:10 +08:00
|
|
|
p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
|
2019-07-29 16:41:17 +08:00
|
|
|
p->type_val_to_struct[typdatum->value - 1] = typdatum;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_index(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct policydb *p;
|
|
|
|
struct user_datum *usrdatum;
|
|
|
|
|
|
|
|
usrdatum = datum;
|
|
|
|
p = datap;
|
2008-08-28 15:35:57 +08:00
|
|
|
if (!usrdatum->value
|
|
|
|
|| usrdatum->value > p->p_users.nprim
|
|
|
|
|| usrdatum->bounds > p->p_users.nprim)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EINVAL;
|
2010-11-30 04:47:09 +08:00
|
|
|
|
2019-03-12 14:31:10 +08:00
|
|
|
p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key;
|
2005-04-17 06:20:36 +08:00
|
|
|
p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sens_index(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct policydb *p;
|
|
|
|
struct level_datum *levdatum;
|
|
|
|
|
|
|
|
levdatum = datum;
|
|
|
|
p = datap;
|
|
|
|
|
|
|
|
if (!levdatum->isalias) {
|
|
|
|
if (!levdatum->level->sens ||
|
|
|
|
levdatum->level->sens > p->p_levels.nprim)
|
|
|
|
return -EINVAL;
|
2019-03-12 14:31:10 +08:00
|
|
|
|
|
|
|
p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cat_index(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct policydb *p;
|
|
|
|
struct cat_datum *catdatum;
|
|
|
|
|
|
|
|
catdatum = datum;
|
|
|
|
p = datap;
|
|
|
|
|
|
|
|
if (!catdatum->isalias) {
|
|
|
|
if (!catdatum->value || catdatum->value > p->p_cats.nprim)
|
|
|
|
return -EINVAL;
|
2019-03-12 14:31:10 +08:00
|
|
|
|
|
|
|
p->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
|
|
|
|
{
|
|
|
|
common_index,
|
|
|
|
class_index,
|
|
|
|
role_index,
|
|
|
|
type_index,
|
|
|
|
user_index,
|
|
|
|
cond_index_bool,
|
|
|
|
sens_index,
|
|
|
|
cat_index,
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef DEBUG_HASHES
|
2011-04-29 03:11:21 +08:00
|
|
|
static void hash_eval(struct hashtab *h, const char *hash_name)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2011-04-29 03:11:21 +08:00
|
|
|
struct hashtab_info info;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
hashtab_stat(h, &info);
|
2019-07-29 16:41:16 +08:00
|
|
|
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n",
|
|
|
|
hash_name, h->nel, info.slots_used, h->size,
|
|
|
|
info.max_chain_len);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2010-01-08 04:55:16 +08:00
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
static void symtab_hash_eval(struct symtab *s)
|
2010-01-08 04:55:16 +08:00
|
|
|
{
|
2011-04-29 03:11:21 +08:00
|
|
|
int i;
|
2010-01-08 04:55:16 +08:00
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
for (i = 0; i < SYM_NUM; i++)
|
|
|
|
hash_eval(s[i].table, symtab_name[i]);
|
2010-01-08 04:55:16 +08:00
|
|
|
}
|
2011-04-29 03:11:21 +08:00
|
|
|
|
2010-01-08 04:55:16 +08:00
|
|
|
#else
|
2011-04-29 03:11:21 +08:00
|
|
|
static inline void hash_eval(struct hashtab *h, char *hash_name)
|
2010-01-08 04:55:16 +08:00
|
|
|
{
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Define the other val_to_name and val_to_struct arrays
|
|
|
|
* in a policy database structure.
|
|
|
|
*
|
|
|
|
* Caller must clean up on failure.
|
|
|
|
*/
|
2010-11-30 04:47:09 +08:00
|
|
|
static int policydb_index(struct policydb *p)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2010-11-24 00:40:08 +08:00
|
|
|
int i, rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-02-03 23:40:20 +08:00
|
|
|
if (p->mls_enabled)
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n",
|
|
|
|
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
|
|
|
|
p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim);
|
|
|
|
else
|
|
|
|
pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n",
|
|
|
|
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
|
|
|
|
p->p_bools.nprim);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_debug("SELinux: %d classes, %d rules\n",
|
|
|
|
p->p_classes.nprim, p->te_avtab.nel);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#ifdef DEBUG_HASHES
|
|
|
|
avtab_hash_eval(&p->te_avtab, "rules");
|
|
|
|
symtab_hash_eval(p->symtab);
|
|
|
|
#endif
|
|
|
|
|
2017-01-14 20:08:59 +08:00
|
|
|
p->class_val_to_struct = kcalloc(p->p_classes.nprim,
|
|
|
|
sizeof(*p->class_val_to_struct),
|
|
|
|
GFP_KERNEL);
|
2010-11-30 04:47:09 +08:00
|
|
|
if (!p->class_val_to_struct)
|
2017-04-04 16:20:46 +08:00
|
|
|
return -ENOMEM;
|
2010-11-30 04:47:09 +08:00
|
|
|
|
2017-01-14 20:08:59 +08:00
|
|
|
p->role_val_to_struct = kcalloc(p->p_roles.nprim,
|
|
|
|
sizeof(*p->role_val_to_struct),
|
|
|
|
GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!p->role_val_to_struct)
|
2017-04-04 16:20:46 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2017-01-14 20:08:59 +08:00
|
|
|
p->user_val_to_struct = kcalloc(p->p_users.nprim,
|
|
|
|
sizeof(*p->user_val_to_struct),
|
|
|
|
GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!p->user_val_to_struct)
|
2017-04-04 16:20:46 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2019-07-29 16:41:17 +08:00
|
|
|
p->type_val_to_struct = kvcalloc(p->p_types.nprim,
|
|
|
|
sizeof(*p->type_val_to_struct),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!p->type_val_to_struct)
|
2017-04-04 16:20:46 +08:00
|
|
|
return -ENOMEM;
|
2010-11-30 04:47:09 +08:00
|
|
|
|
2011-01-21 23:28:04 +08:00
|
|
|
rc = cond_init_bool_indexes(p);
|
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
|
2010-11-30 04:47:09 +08:00
|
|
|
for (i = 0; i < SYM_NUM; i++) {
|
2019-03-12 14:31:10 +08:00
|
|
|
p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim,
|
|
|
|
sizeof(char *),
|
|
|
|
GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!p->sym_val_to_name[i])
|
2017-04-04 16:20:46 +08:00
|
|
|
return -ENOMEM;
|
2010-11-30 04:47:09 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = hashtab_map(p->symtab[i].table, index_f[i], p);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free any memory allocated by a policy database structure.
|
|
|
|
*/
|
|
|
|
void policydb_destroy(struct policydb *p)
|
|
|
|
{
|
|
|
|
struct ocontext *c, *ctmp;
|
|
|
|
struct genfs *g, *gtmp;
|
|
|
|
int i;
|
2005-09-04 06:55:16 +08:00
|
|
|
struct role_allow *ra, *lra = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
for (i = 0; i < SYM_NUM; i++) {
|
2007-06-05 05:41:22 +08:00
|
|
|
cond_resched();
|
2005-04-17 06:20:36 +08:00
|
|
|
hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
|
|
|
|
hashtab_destroy(p->symtab[i].table);
|
|
|
|
}
|
|
|
|
|
2019-03-12 14:31:10 +08:00
|
|
|
for (i = 0; i < SYM_NUM; i++)
|
|
|
|
kvfree(p->sym_val_to_name[i]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-06-26 05:58:51 +08:00
|
|
|
kfree(p->class_val_to_struct);
|
|
|
|
kfree(p->role_val_to_struct);
|
|
|
|
kfree(p->user_val_to_struct);
|
2019-07-29 16:41:17 +08:00
|
|
|
kvfree(p->type_val_to_struct);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
avtab_destroy(&p->te_avtab);
|
|
|
|
|
|
|
|
for (i = 0; i < OCON_NUM; i++) {
|
2007-06-05 05:41:22 +08:00
|
|
|
cond_resched();
|
2005-04-17 06:20:36 +08:00
|
|
|
c = p->ocontexts[i];
|
|
|
|
while (c) {
|
|
|
|
ctmp = c;
|
|
|
|
c = c->next;
|
2008-04-18 01:37:12 +08:00
|
|
|
ocontext_destroy(ctmp, i);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2006-10-07 04:09:52 +08:00
|
|
|
p->ocontexts[i] = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g = p->genfs;
|
|
|
|
while (g) {
|
2007-06-05 05:41:22 +08:00
|
|
|
cond_resched();
|
2005-04-17 06:20:36 +08:00
|
|
|
kfree(g->fstype);
|
|
|
|
c = g->head;
|
|
|
|
while (c) {
|
|
|
|
ctmp = c;
|
|
|
|
c = c->next;
|
2008-04-18 01:37:12 +08:00
|
|
|
ocontext_destroy(ctmp, OCON_FSUSE);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
gtmp = g;
|
|
|
|
g = g->next;
|
|
|
|
kfree(gtmp);
|
|
|
|
}
|
2006-10-07 04:09:52 +08:00
|
|
|
p->genfs = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
cond_policydb_destroy(p);
|
|
|
|
|
2020-04-08 02:28:58 +08:00
|
|
|
hashtab_map(p->role_tr, role_tr_destroy, NULL);
|
|
|
|
hashtab_destroy(p->role_tr);
|
2005-09-04 06:55:16 +08:00
|
|
|
|
2008-04-18 01:37:12 +08:00
|
|
|
for (ra = p->role_allow; ra; ra = ra->next) {
|
2007-06-05 05:41:22 +08:00
|
|
|
cond_resched();
|
2005-11-07 17:01:35 +08:00
|
|
|
kfree(lra);
|
2005-09-04 06:55:16 +08:00
|
|
|
lra = ra;
|
|
|
|
}
|
2005-11-07 17:01:35 +08:00
|
|
|
kfree(lra);
|
2005-09-04 06:55:16 +08:00
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
hashtab_map(p->filename_trans, filenametr_destroy, NULL);
|
|
|
|
hashtab_destroy(p->filename_trans);
|
|
|
|
|
2010-01-08 04:55:16 +08:00
|
|
|
hashtab_map(p->range_tr, range_tr_destroy, NULL);
|
|
|
|
hashtab_destroy(p->range_tr);
|
2005-09-04 06:55:16 +08:00
|
|
|
|
2019-03-17 21:46:53 +08:00
|
|
|
if (p->type_attr_map_array) {
|
|
|
|
for (i = 0; i < p->p_types.nprim; i++)
|
|
|
|
ebitmap_destroy(&p->type_attr_map_array[i]);
|
|
|
|
kvfree(p->type_attr_map_array);
|
|
|
|
}
|
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-02 00:05:40 +08:00
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
ebitmap_destroy(&p->filename_trans_ttypes);
|
2008-01-29 21:38:19 +08:00
|
|
|
ebitmap_destroy(&p->policycaps);
|
2008-03-31 09:17:33 +08:00
|
|
|
ebitmap_destroy(&p->permissive_map);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load the initial SIDs specified in a policy database
|
|
|
|
* structure into a SID table.
|
|
|
|
*/
|
|
|
|
int policydb_load_isids(struct policydb *p, struct sidtab *s)
|
|
|
|
{
|
|
|
|
struct ocontext *head, *c;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = sidtab_init(s);
|
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: out of memory on SID table init\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
head = p->ocontexts[OCON_ISID];
|
|
|
|
for (c = head; c; c = c->next) {
|
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-25 00:10:23 +08:00
|
|
|
u32 sid = c->sid[0];
|
|
|
|
const char *name = security_get_initial_sid_context(sid);
|
|
|
|
|
|
|
|
if (sid == SECSID_NULL) {
|
|
|
|
pr_err("SELinux: SID 0 was assigned a context.\n");
|
2018-11-30 23:24:07 +08:00
|
|
|
sidtab_destroy(s);
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
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-25 00:10:23 +08:00
|
|
|
|
|
|
|
/* Ignore initial SIDs unused by this kernel. */
|
|
|
|
if (!name)
|
|
|
|
continue;
|
|
|
|
|
2019-11-22 17:33:06 +08:00
|
|
|
rc = context_add_hash(p, &c->context[0]);
|
|
|
|
if (rc) {
|
|
|
|
sidtab_destroy(s);
|
|
|
|
goto out;
|
|
|
|
}
|
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-25 00:10:23 +08:00
|
|
|
rc = sidtab_set_initial(s, sid, &c->context[0]);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: unable to load initial SID %s.\n",
|
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-25 00:10:23 +08:00
|
|
|
name);
|
2018-11-30 23:24:07 +08:00
|
|
|
sidtab_destroy(s);
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-11-07 23:08:00 +08:00
|
|
|
int policydb_class_isvalid(struct policydb *p, unsigned int class)
|
|
|
|
{
|
|
|
|
if (!class || class > p->p_classes.nprim)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int policydb_role_isvalid(struct policydb *p, unsigned int role)
|
|
|
|
{
|
|
|
|
if (!role || role > p->p_roles.nprim)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int policydb_type_isvalid(struct policydb *p, unsigned int type)
|
|
|
|
{
|
|
|
|
if (!type || type > p->p_types.nprim)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Return 1 if the fields in the security context
|
|
|
|
* structure `c' are valid. Return 0 otherwise.
|
|
|
|
*/
|
|
|
|
int policydb_context_isvalid(struct policydb *p, struct context *c)
|
|
|
|
{
|
|
|
|
struct role_datum *role;
|
|
|
|
struct user_datum *usrdatum;
|
|
|
|
|
|
|
|
if (!c->role || c->role > p->p_roles.nprim)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!c->user || c->user > p->p_users.nprim)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!c->type || c->type > p->p_types.nprim)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (c->role != OBJECT_R_VAL) {
|
|
|
|
/*
|
|
|
|
* Role must be authorized for the type.
|
|
|
|
*/
|
|
|
|
role = p->role_val_to_struct[c->role - 1];
|
2016-08-24 04:49:24 +08:00
|
|
|
if (!role || !ebitmap_get_bit(&role->types, c->type - 1))
|
2005-04-17 06:20:36 +08:00
|
|
|
/* role may not be associated with type */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* User must be authorized for the role.
|
|
|
|
*/
|
|
|
|
usrdatum = p->user_val_to_struct[c->user - 1];
|
|
|
|
if (!usrdatum)
|
|
|
|
return 0;
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!ebitmap_get_bit(&usrdatum->roles, c->role - 1))
|
2005-04-17 06:20:36 +08:00
|
|
|
/* user may not be associated with role */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mls_context_isvalid(p, c))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read a MLS range structure from a policydb binary
|
|
|
|
* representation file.
|
|
|
|
*/
|
|
|
|
static int mls_read_range_helper(struct mls_range *r, void *fp)
|
|
|
|
{
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[2];
|
|
|
|
u32 items;
|
2005-04-17 06:20:36 +08:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
items = le32_to_cpu(buf[0]);
|
|
|
|
if (items > ARRAY_SIZE(buf)) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: mls: range overflow\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
2010-11-24 00:40:08 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = next_entry(buf, fp, sizeof(u32) * items);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: mls: truncated range\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
2010-11-24 00:40:08 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
r->level[0].sens = le32_to_cpu(buf[0]);
|
|
|
|
if (items > 1)
|
|
|
|
r->level[1].sens = le32_to_cpu(buf[1]);
|
|
|
|
else
|
|
|
|
r->level[1].sens = r->level[0].sens;
|
|
|
|
|
|
|
|
rc = ebitmap_read(&r->level[0].cat, fp);
|
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: mls: error reading low categories\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (items > 1) {
|
|
|
|
rc = ebitmap_read(&r->level[1].cat, fp);
|
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: mls: error reading high categories\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad_high;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
|
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: mls: out of memory\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad_high;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad_high:
|
|
|
|
ebitmap_destroy(&r->level[0].cat);
|
2010-11-24 00:40:08 +08:00
|
|
|
out:
|
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read and validate a security context structure
|
|
|
|
* from a policydb binary representation file.
|
|
|
|
*/
|
|
|
|
static int context_read_and_validate(struct context *c,
|
|
|
|
struct policydb *p,
|
|
|
|
void *fp)
|
|
|
|
{
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[3];
|
2005-04-17 06:20:36 +08:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof buf);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: context truncated\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
c->user = le32_to_cpu(buf[0]);
|
|
|
|
c->role = le32_to_cpu(buf[1]);
|
|
|
|
c->type = le32_to_cpu(buf[2]);
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_MLS) {
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = mls_read_range_helper(&c->range, fp);
|
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: error reading MLS range of context\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!policydb_context_isvalid(p, c)) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: invalid security context\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
context_destroy(c);
|
2010-11-24 00:40:08 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The following *_read functions are used to
|
|
|
|
* read the symbol data from a policy database
|
|
|
|
* binary representation file.
|
|
|
|
*/
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
static int str_read(char **strp, gfp_t flags, void *fp, u32 len)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
char *str;
|
|
|
|
|
2016-08-31 00:28:11 +08:00
|
|
|
if ((len == 0) || (len == (u32)-1))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-09-08 00:42:58 +08:00
|
|
|
str = kmalloc(len + 1, flags | __GFP_NOWARN);
|
2014-06-15 22:02:51 +08:00
|
|
|
if (!str)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* it's expected the caller should free the str */
|
|
|
|
*strp = str;
|
|
|
|
|
|
|
|
rc = next_entry(str, fp, len);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
str[len] = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
struct perm_datum *perdatum;
|
|
|
|
int rc;
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[2];
|
|
|
|
u32 len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-10-31 06:59:21 +08:00
|
|
|
perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!perdatum)
|
2017-01-15 18:20:13 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof buf);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
perdatum->value = le32_to_cpu(buf[1]);
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&key, GFP_KERNEL, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
rc = hashtab_insert(h, key, perdatum);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
|
|
|
perm_destroy(key, perdatum, NULL);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int common_read(struct policydb *p, struct hashtab *h, void *fp)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
struct common_datum *comdatum;
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[4];
|
|
|
|
u32 len, nel;
|
2005-04-17 06:20:36 +08:00
|
|
|
int i, rc;
|
|
|
|
|
2005-10-31 06:59:21 +08:00
|
|
|
comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!comdatum)
|
2017-01-15 18:15:19 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof buf);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
comdatum->value = le32_to_cpu(buf[1]);
|
2020-02-26 23:54:52 +08:00
|
|
|
nel = le32_to_cpu(buf[3]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2020-02-26 23:54:52 +08:00
|
|
|
rc = symtab_init(&comdatum->permissions, nel);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
comdatum->permissions.nprim = le32_to_cpu(buf[2]);
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&key, GFP_KERNEL, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
for (i = 0; i < nel; i++) {
|
|
|
|
rc = perm_read(p, comdatum->permissions.table, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = hashtab_insert(h, key, comdatum);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
|
|
|
common_destroy(key, comdatum, NULL);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2013-11-20 06:34:23 +08:00
|
|
|
static void type_set_init(struct type_set *t)
|
|
|
|
{
|
|
|
|
ebitmap_init(&t->types);
|
|
|
|
ebitmap_init(&t->negset);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int type_set_read(struct type_set *t, void *fp)
|
|
|
|
{
|
|
|
|
__le32 buf[1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (ebitmap_read(&t->types, fp))
|
|
|
|
return -EINVAL;
|
|
|
|
if (ebitmap_read(&t->negset, fp))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
t->flags = le32_to_cpu(buf[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int read_cons_helper(struct policydb *p,
|
|
|
|
struct constraint_node **nodep,
|
|
|
|
int ncons, int allowxtarget, void *fp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct constraint_node *c, *lc;
|
|
|
|
struct constraint_expr *e, *le;
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[3];
|
|
|
|
u32 nexpr;
|
2005-04-17 06:20:36 +08:00
|
|
|
int rc, i, j, depth;
|
|
|
|
|
|
|
|
lc = NULL;
|
|
|
|
for (i = 0; i < ncons; i++) {
|
2005-10-31 06:59:21 +08:00
|
|
|
c = kzalloc(sizeof(*c), GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!c)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2008-04-18 01:37:12 +08:00
|
|
|
if (lc)
|
2005-04-17 06:20:36 +08:00
|
|
|
lc->next = c;
|
2008-04-18 01:37:12 +08:00
|
|
|
else
|
2005-04-17 06:20:36 +08:00
|
|
|
*nodep = c;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, (sizeof(u32) * 2));
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
return rc;
|
|
|
|
c->permissions = le32_to_cpu(buf[0]);
|
|
|
|
nexpr = le32_to_cpu(buf[1]);
|
|
|
|
le = NULL;
|
|
|
|
depth = -1;
|
|
|
|
for (j = 0; j < nexpr; j++) {
|
2005-10-31 06:59:21 +08:00
|
|
|
e = kzalloc(sizeof(*e), GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!e)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2008-04-18 01:37:12 +08:00
|
|
|
if (le)
|
2005-04-17 06:20:36 +08:00
|
|
|
le->next = e;
|
2008-04-18 01:37:12 +08:00
|
|
|
else
|
2005-04-17 06:20:36 +08:00
|
|
|
c->expr = e;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, (sizeof(u32) * 3));
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
return rc;
|
|
|
|
e->expr_type = le32_to_cpu(buf[0]);
|
|
|
|
e->attr = le32_to_cpu(buf[1]);
|
|
|
|
e->op = le32_to_cpu(buf[2]);
|
|
|
|
|
|
|
|
switch (e->expr_type) {
|
|
|
|
case CEXPR_NOT:
|
|
|
|
if (depth < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
case CEXPR_AND:
|
|
|
|
case CEXPR_OR:
|
|
|
|
if (depth < 1)
|
|
|
|
return -EINVAL;
|
|
|
|
depth--;
|
|
|
|
break;
|
|
|
|
case CEXPR_ATTR:
|
|
|
|
if (depth == (CEXPR_MAXDEPTH - 1))
|
|
|
|
return -EINVAL;
|
|
|
|
depth++;
|
|
|
|
break;
|
|
|
|
case CEXPR_NAMES:
|
|
|
|
if (!allowxtarget && (e->attr & CEXPR_XTARGET))
|
|
|
|
return -EINVAL;
|
|
|
|
if (depth == (CEXPR_MAXDEPTH - 1))
|
|
|
|
return -EINVAL;
|
|
|
|
depth++;
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = ebitmap_read(&e->names, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
2013-11-20 06:34:23 +08:00
|
|
|
if (p->policyvers >=
|
2020-03-28 01:44:02 +08:00
|
|
|
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
|
|
|
e->type_names = kzalloc(sizeof
|
|
|
|
(*e->type_names), GFP_KERNEL);
|
2013-11-20 06:34:23 +08:00
|
|
|
if (!e->type_names)
|
|
|
|
return -ENOMEM;
|
|
|
|
type_set_init(e->type_names);
|
|
|
|
rc = type_set_read(e->type_names, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
le = e;
|
|
|
|
}
|
|
|
|
if (depth != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
lc = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
struct class_datum *cladatum;
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[6];
|
|
|
|
u32 len, len2, ncons, nel;
|
2005-04-17 06:20:36 +08:00
|
|
|
int i, rc;
|
|
|
|
|
2005-10-31 06:59:21 +08:00
|
|
|
cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!cladatum)
|
2017-01-15 05:30:51 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32)*6);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
len2 = le32_to_cpu(buf[1]);
|
|
|
|
cladatum->value = le32_to_cpu(buf[2]);
|
2020-02-26 23:54:52 +08:00
|
|
|
nel = le32_to_cpu(buf[4]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2020-02-26 23:54:52 +08:00
|
|
|
rc = symtab_init(&cladatum->permissions, nel);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
cladatum->permissions.nprim = le32_to_cpu(buf[3]);
|
|
|
|
|
|
|
|
ncons = le32_to_cpu(buf[5]);
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&key, GFP_KERNEL, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (len2) {
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&cladatum->comkey, GFP_KERNEL, fp, len2);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!cladatum->comdatum) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: unknown common %s\n",
|
|
|
|
cladatum->comkey);
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < nel; i++) {
|
|
|
|
rc = perm_read(p, cladatum->permissions.table, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2013-11-20 06:34:23 +08:00
|
|
|
rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_VALIDATETRANS) {
|
|
|
|
/* grab the validatetrans rules */
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
ncons = le32_to_cpu(buf[0]);
|
2013-11-20 06:34:23 +08:00
|
|
|
rc = read_cons_helper(p, &cladatum->validatetrans,
|
|
|
|
ncons, 1, fp);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2012-03-21 02:35:12 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32) * 3);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
cladatum->default_user = le32_to_cpu(buf[0]);
|
|
|
|
cladatum->default_role = le32_to_cpu(buf[1]);
|
|
|
|
cladatum->default_range = le32_to_cpu(buf[2]);
|
|
|
|
}
|
|
|
|
|
2012-03-21 02:35:12 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) {
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32) * 1);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
cladatum->default_type = le32_to_cpu(buf[0]);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = hashtab_insert(h, key, cladatum);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
2006-11-30 05:50:27 +08:00
|
|
|
cls_destroy(key, cladatum, NULL);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int role_read(struct policydb *p, struct hashtab *h, void *fp)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
struct role_datum *role;
|
2008-08-28 15:35:57 +08:00
|
|
|
int rc, to_read = 2;
|
|
|
|
__le32 buf[3];
|
2005-09-04 06:55:17 +08:00
|
|
|
u32 len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-10-31 06:59:21 +08:00
|
|
|
role = kzalloc(sizeof(*role), GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!role)
|
2017-01-15 05:20:25 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-08-28 15:35:57 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
|
|
|
|
to_read = 3;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
role->value = le32_to_cpu(buf[1]);
|
2008-08-28 15:35:57 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
|
|
|
|
role->bounds = le32_to_cpu(buf[2]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&key, GFP_KERNEL, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
rc = ebitmap_read(&role->dominates, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
rc = ebitmap_read(&role->types, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (strcmp(key, OBJECT_R) == 0) {
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (role->value != OBJECT_R_VAL) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: Role %s has wrong value %d\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
OBJECT_R, role->value);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = hashtab_insert(h, key, role);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
|
|
|
role_destroy(key, role, NULL);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int type_read(struct policydb *p, struct hashtab *h, void *fp)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
struct type_datum *typdatum;
|
2008-08-28 15:35:57 +08:00
|
|
|
int rc, to_read = 3;
|
|
|
|
__le32 buf[4];
|
2005-09-04 06:55:17 +08:00
|
|
|
u32 len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-04-18 01:37:12 +08:00
|
|
|
typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!typdatum)
|
2017-01-15 05:15:54 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-08-28 15:35:57 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
|
|
|
|
to_read = 4;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
typdatum->value = le32_to_cpu(buf[1]);
|
2008-08-28 15:35:57 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
|
|
|
|
u32 prop = le32_to_cpu(buf[2]);
|
|
|
|
|
|
|
|
if (prop & TYPEDATUM_PROPERTY_PRIMARY)
|
|
|
|
typdatum->primary = 1;
|
|
|
|
if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
|
|
|
|
typdatum->attribute = 1;
|
|
|
|
|
|
|
|
typdatum->bounds = le32_to_cpu(buf[3]);
|
|
|
|
} else {
|
|
|
|
typdatum->primary = le32_to_cpu(buf[2]);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&key, GFP_KERNEL, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
rc = hashtab_insert(h, key, typdatum);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
|
|
|
type_destroy(key, typdatum, NULL);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read a MLS level structure from a policydb binary
|
|
|
|
* representation file.
|
|
|
|
*/
|
|
|
|
static int mls_read_level(struct mls_level *lp, void *fp)
|
|
|
|
{
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[1];
|
2005-04-17 06:20:36 +08:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
memset(lp, 0, sizeof(*lp));
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof buf);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: mls: truncated level\n");
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
lp->sens = le32_to_cpu(buf[0]);
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = ebitmap_read(&lp->cat, fp);
|
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: mls: error reading level categories\n");
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_read(struct policydb *p, struct hashtab *h, void *fp)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
struct user_datum *usrdatum;
|
2008-08-28 15:35:57 +08:00
|
|
|
int rc, to_read = 2;
|
|
|
|
__le32 buf[3];
|
2005-09-04 06:55:17 +08:00
|
|
|
u32 len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-10-31 06:59:21 +08:00
|
|
|
usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!usrdatum)
|
2017-01-15 05:08:22 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-08-28 15:35:57 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
|
|
|
|
to_read = 3;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
usrdatum->value = le32_to_cpu(buf[1]);
|
2008-08-28 15:35:57 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
|
|
|
|
usrdatum->bounds = le32_to_cpu(buf[2]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&key, GFP_KERNEL, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
rc = ebitmap_read(&usrdatum->roles, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_MLS) {
|
|
|
|
rc = mls_read_range_helper(&usrdatum->range, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
rc = mls_read_level(&usrdatum->dfltlevel, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = hashtab_insert(h, key, usrdatum);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
|
|
|
user_destroy(key, usrdatum, NULL);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
struct level_datum *levdatum;
|
|
|
|
int rc;
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[2];
|
|
|
|
u32 len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-10-31 06:59:21 +08:00
|
|
|
levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!levdatum)
|
2017-01-15 04:42:02 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof buf);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
levdatum->isalias = le32_to_cpu(buf[1]);
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&key, GFP_ATOMIC, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -ENOMEM;
|
2017-01-15 04:52:55 +08:00
|
|
|
levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_ATOMIC);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!levdatum->level)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
|
|
|
|
rc = mls_read_level(levdatum->level, fp);
|
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
rc = hashtab_insert(h, key, levdatum);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
|
|
|
sens_destroy(key, levdatum, NULL);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
|
|
|
|
{
|
|
|
|
char *key = NULL;
|
|
|
|
struct cat_datum *catdatum;
|
|
|
|
int rc;
|
2005-09-04 06:55:17 +08:00
|
|
|
__le32 buf[3];
|
|
|
|
u32 len;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-10-31 06:59:21 +08:00
|
|
|
catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!catdatum)
|
2017-01-15 04:20:43 +08:00
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof buf);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
catdatum->value = le32_to_cpu(buf[1]);
|
|
|
|
catdatum->isalias = le32_to_cpu(buf[2]);
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&key, GFP_ATOMIC, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
|
|
|
rc = hashtab_insert(h, key, catdatum);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
bad:
|
|
|
|
cat_destroy(key, catdatum, NULL);
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
|
|
|
|
{
|
|
|
|
common_read,
|
|
|
|
class_read,
|
|
|
|
role_read,
|
|
|
|
type_read,
|
|
|
|
user_read,
|
|
|
|
cond_read_bool,
|
|
|
|
sens_read,
|
|
|
|
cat_read,
|
|
|
|
};
|
|
|
|
|
2008-08-28 15:35:57 +08:00
|
|
|
static int user_bounds_sanity_check(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct user_datum *upper, *user;
|
|
|
|
struct policydb *p = datap;
|
|
|
|
int depth = 0;
|
|
|
|
|
|
|
|
upper = user = datum;
|
|
|
|
while (upper->bounds) {
|
|
|
|
struct ebitmap_node *node;
|
|
|
|
unsigned long bit;
|
|
|
|
|
|
|
|
if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: user %s: "
|
2008-08-28 15:35:57 +08:00
|
|
|
"too deep or looped boundary",
|
|
|
|
(char *) key);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
upper = p->user_val_to_struct[upper->bounds - 1];
|
|
|
|
ebitmap_for_each_positive_bit(&user->roles, node, bit) {
|
|
|
|
if (ebitmap_get_bit(&upper->roles, bit))
|
|
|
|
continue;
|
|
|
|
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: boundary violated policy: "
|
2008-08-28 15:35:57 +08:00
|
|
|
"user=%s role=%s bounds=%s\n",
|
2010-11-30 04:47:09 +08:00
|
|
|
sym_name(p, SYM_USERS, user->value - 1),
|
|
|
|
sym_name(p, SYM_ROLES, bit),
|
|
|
|
sym_name(p, SYM_USERS, upper->value - 1));
|
2008-08-28 15:35:57 +08:00
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int role_bounds_sanity_check(void *key, void *datum, void *datap)
|
|
|
|
{
|
|
|
|
struct role_datum *upper, *role;
|
|
|
|
struct policydb *p = datap;
|
|
|
|
int depth = 0;
|
|
|
|
|
|
|
|
upper = role = datum;
|
|
|
|
while (upper->bounds) {
|
|
|
|
struct ebitmap_node *node;
|
|
|
|
unsigned long bit;
|
|
|
|
|
|
|
|
if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: role %s: "
|
2008-08-28 15:35:57 +08:00
|
|
|
"too deep or looped bounds\n",
|
|
|
|
(char *) key);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
upper = p->role_val_to_struct[upper->bounds - 1];
|
|
|
|
ebitmap_for_each_positive_bit(&role->types, node, bit) {
|
|
|
|
if (ebitmap_get_bit(&upper->types, bit))
|
|
|
|
continue;
|
|
|
|
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: boundary violated policy: "
|
2008-08-28 15:35:57 +08:00
|
|
|
"role=%s type=%s bounds=%s\n",
|
2010-11-30 04:47:09 +08:00
|
|
|
sym_name(p, SYM_ROLES, role->value - 1),
|
|
|
|
sym_name(p, SYM_TYPES, bit),
|
|
|
|
sym_name(p, SYM_ROLES, upper->value - 1));
|
2008-08-28 15:35:57 +08:00
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int type_bounds_sanity_check(void *key, void *datum, void *datap)
|
|
|
|
{
|
2010-08-04 03:26:05 +08:00
|
|
|
struct type_datum *upper;
|
2008-08-28 15:35:57 +08:00
|
|
|
struct policydb *p = datap;
|
|
|
|
int depth = 0;
|
|
|
|
|
2010-08-04 03:26:05 +08:00
|
|
|
upper = datum;
|
2008-08-28 15:35:57 +08:00
|
|
|
while (upper->bounds) {
|
|
|
|
if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: type %s: "
|
2008-08-28 15:35:57 +08:00
|
|
|
"too deep or looped boundary\n",
|
|
|
|
(char *) key);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-07-29 16:41:17 +08:00
|
|
|
upper = p->type_val_to_struct[upper->bounds - 1];
|
2010-11-30 04:47:09 +08:00
|
|
|
BUG_ON(!upper);
|
|
|
|
|
2008-08-28 15:35:57 +08:00
|
|
|
if (upper->attribute) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: type %s: "
|
2008-08-28 15:35:57 +08:00
|
|
|
"bounded by attribute %s",
|
|
|
|
(char *) key,
|
2010-11-30 04:47:09 +08:00
|
|
|
sym_name(p, SYM_TYPES, upper->value - 1));
|
2008-08-28 15:35:57 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int policydb_bounds_sanity_check(struct policydb *p)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rc = hashtab_map(p->p_users.table,
|
|
|
|
user_bounds_sanity_check, p);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = hashtab_map(p->p_roles.table,
|
|
|
|
role_bounds_sanity_check, p);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = hashtab_map(p->p_types.table,
|
|
|
|
type_bounds_sanity_check, p);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 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 01:37:50 +08:00
|
|
|
u16 string_to_security_class(struct policydb *p, const char *name)
|
|
|
|
{
|
|
|
|
struct class_datum *cladatum;
|
|
|
|
|
|
|
|
cladatum = hashtab_search(p->p_classes.table, name);
|
|
|
|
if (!cladatum)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return cladatum->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
|
|
|
|
{
|
|
|
|
struct class_datum *cladatum;
|
|
|
|
struct perm_datum *perdatum = NULL;
|
|
|
|
struct common_datum *comdatum;
|
|
|
|
|
|
|
|
if (!tclass || tclass > p->p_classes.nprim)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cladatum = p->class_val_to_struct[tclass-1];
|
|
|
|
comdatum = cladatum->comdatum;
|
|
|
|
if (comdatum)
|
|
|
|
perdatum = hashtab_search(comdatum->permissions.table,
|
|
|
|
name);
|
|
|
|
if (!perdatum)
|
|
|
|
perdatum = hashtab_search(cladatum->permissions.table,
|
|
|
|
name);
|
|
|
|
if (!perdatum)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1U << (perdatum->value-1);
|
|
|
|
}
|
|
|
|
|
2010-06-12 00:37:05 +08:00
|
|
|
static int range_read(struct policydb *p, void *fp)
|
|
|
|
{
|
2017-03-31 23:21:18 +08:00
|
|
|
struct range_trans *rt = NULL;
|
2010-06-12 00:37:05 +08:00
|
|
|
struct mls_range *r = NULL;
|
|
|
|
int i, rc;
|
|
|
|
__le32 buf[2];
|
|
|
|
u32 nel;
|
|
|
|
|
|
|
|
if (p->policyvers < POLICYDB_VERSION_MLS)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
2017-01-15 02:35:59 +08:00
|
|
|
return rc;
|
2010-06-12 00:37:05 +08:00
|
|
|
|
|
|
|
nel = le32_to_cpu(buf[0]);
|
2020-02-26 23:54:52 +08:00
|
|
|
|
|
|
|
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, nel);
|
|
|
|
if (!p->range_tr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-06-12 00:37:05 +08:00
|
|
|
for (i = 0; i < nel; i++) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
rt = kzalloc(sizeof(*rt), GFP_KERNEL);
|
|
|
|
if (!rt)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, (sizeof(u32) * 2));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rt->source_type = le32_to_cpu(buf[0]);
|
|
|
|
rt->target_type = le32_to_cpu(buf[1]);
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
rt->target_class = le32_to_cpu(buf[0]);
|
|
|
|
} else
|
|
|
|
rt->target_class = p->process_class;
|
|
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
|
if (!policydb_type_isvalid(p, rt->source_type) ||
|
|
|
|
!policydb_type_isvalid(p, rt->target_type) ||
|
|
|
|
!policydb_class_isvalid(p, rt->target_class))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = -ENOMEM;
|
|
|
|
r = kzalloc(sizeof(*r), GFP_KERNEL);
|
|
|
|
if (!r)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = mls_read_range_helper(r, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
|
if (!mls_range_isvalid(p, r)) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_warn("SELinux: rangetrans: invalid range\n");
|
2010-06-12 00:37:05 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = hashtab_insert(p->range_tr, rt, r);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rt = NULL;
|
|
|
|
r = NULL;
|
|
|
|
}
|
2011-04-29 03:11:21 +08:00
|
|
|
hash_eval(p->range_tr, "rangetr");
|
2010-06-12 00:37:05 +08:00
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
kfree(rt);
|
|
|
|
kfree(r);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-02-12 19:22:54 +08:00
|
|
|
static int filename_trans_read_one(struct policydb *p, void *fp)
|
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-02 00:05:40 +08: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 19:27:34 +08:00
|
|
|
struct filename_trans_key key, *ft = NULL;
|
|
|
|
struct filename_trans_datum *last, *datum = NULL;
|
2020-02-12 19:22:54 +08:00
|
|
|
char *name = NULL;
|
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 19:27:34 +08:00
|
|
|
u32 len, stype, otype;
|
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-02 00:05:40 +08:00
|
|
|
__le32 buf[4];
|
2020-02-12 19:22:54 +08:00
|
|
|
int rc;
|
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-02 00:05:40 +08:00
|
|
|
|
2020-02-12 19:22:54 +08:00
|
|
|
/* length of the path component string */
|
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-02 00:05:40 +08:00
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
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 19:27:34 +08:00
|
|
|
return rc;
|
2020-02-12 19:22:54 +08:00
|
|
|
len = le32_to_cpu(buf[0]);
|
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-02 00:05:40 +08:00
|
|
|
|
2020-02-12 19:22:54 +08:00
|
|
|
/* path component string */
|
|
|
|
rc = str_read(&name, GFP_KERNEL, fp, len);
|
|
|
|
if (rc)
|
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 19:27:34 +08:00
|
|
|
return rc;
|
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-02 00:05:40 +08:00
|
|
|
|
2020-02-12 19:22:54 +08:00
|
|
|
rc = next_entry(buf, fp, sizeof(u32) * 4);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
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-02 00:05:40 +08: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 19:27:34 +08:00
|
|
|
stype = le32_to_cpu(buf[0]);
|
|
|
|
key.ttype = le32_to_cpu(buf[1]);
|
|
|
|
key.tclass = le32_to_cpu(buf[2]);
|
|
|
|
key.name = name;
|
2011-04-29 03:11:21 +08: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 19:27:34 +08:00
|
|
|
otype = le32_to_cpu(buf[3]);
|
2011-04-29 03:11:21 +08: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 19:27:34 +08:00
|
|
|
last = NULL;
|
|
|
|
datum = hashtab_search(p->filename_trans, &key);
|
|
|
|
while (datum) {
|
|
|
|
if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
|
|
|
|
/* conflicting/duplicate rules are ignored */
|
|
|
|
datum = NULL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (likely(datum->otype == otype))
|
|
|
|
break;
|
|
|
|
last = datum;
|
|
|
|
datum = datum->next;
|
|
|
|
}
|
|
|
|
if (!datum) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
datum = kmalloc(sizeof(*datum), GFP_KERNEL);
|
|
|
|
if (!datum)
|
|
|
|
goto out;
|
2011-04-29 03:11:21 +08: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 19:27:34 +08:00
|
|
|
ebitmap_init(&datum->stypes);
|
|
|
|
datum->otype = otype;
|
|
|
|
datum->next = NULL;
|
|
|
|
|
|
|
|
if (unlikely(last)) {
|
|
|
|
last->next = datum;
|
|
|
|
} else {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
ft = kmemdup(&key, sizeof(key), GFP_KERNEL);
|
|
|
|
if (!ft)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = hashtab_insert(p->filename_trans, ft, datum);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
name = NULL;
|
|
|
|
|
|
|
|
rc = ebitmap_set_bit(&p->filename_trans_ttypes,
|
|
|
|
key.ttype, 1);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
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-02 00:05:40 +08: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 19:27:34 +08:00
|
|
|
kfree(name);
|
|
|
|
return ebitmap_set_bit(&datum->stypes, stype - 1, 1);
|
|
|
|
|
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-02 00:05:40 +08:00
|
|
|
out:
|
2011-04-29 03:11:21 +08:00
|
|
|
kfree(ft);
|
|
|
|
kfree(name);
|
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 19:27:34 +08:00
|
|
|
kfree(datum);
|
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-02 00:05:40 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-02-12 19:22:54 +08:00
|
|
|
static int filename_trans_read(struct policydb *p, void *fp)
|
|
|
|
{
|
|
|
|
u32 nel;
|
|
|
|
__le32 buf[1];
|
|
|
|
int rc, i;
|
|
|
|
|
|
|
|
if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
nel = le32_to_cpu(buf[0]);
|
|
|
|
|
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 19:27:34 +08:00
|
|
|
p->filename_trans_count = nel;
|
|
|
|
|
2020-02-12 19:22:54 +08:00
|
|
|
for (i = 0; i < nel; i++) {
|
|
|
|
rc = filename_trans_read_one(p, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
hash_eval(p->filename_trans, "filenametr");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-22 00:50:57 +08:00
|
|
|
static int genfs_read(struct policydb *p, void *fp)
|
|
|
|
{
|
|
|
|
int i, j, rc;
|
|
|
|
u32 nel, nel2, len, len2;
|
|
|
|
__le32 buf[1];
|
|
|
|
struct ocontext *l, *c;
|
|
|
|
struct ocontext *newc = NULL;
|
|
|
|
struct genfs *genfs_p, *genfs;
|
|
|
|
struct genfs *newgenfs = NULL;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
2017-01-14 23:34:25 +08:00
|
|
|
return rc;
|
2010-07-22 00:50:57 +08:00
|
|
|
nel = le32_to_cpu(buf[0]);
|
|
|
|
|
|
|
|
for (i = 0; i < nel; i++) {
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
|
|
|
|
rc = -ENOMEM;
|
|
|
|
newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
|
|
|
|
if (!newgenfs)
|
|
|
|
goto out;
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&newgenfs->fstype, GFP_KERNEL, fp, len);
|
2010-07-22 00:50:57 +08:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
for (genfs_p = NULL, genfs = p->genfs; genfs;
|
|
|
|
genfs_p = genfs, genfs = genfs->next) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: dup genfs fstype %s\n",
|
2010-07-22 00:50:57 +08:00
|
|
|
newgenfs->fstype);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
newgenfs->next = genfs;
|
|
|
|
if (genfs_p)
|
|
|
|
genfs_p->next = newgenfs;
|
|
|
|
else
|
|
|
|
p->genfs = newgenfs;
|
|
|
|
genfs = newgenfs;
|
|
|
|
newgenfs = NULL;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
nel2 = le32_to_cpu(buf[0]);
|
|
|
|
for (j = 0; j < nel2; j++) {
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
|
|
|
|
rc = -ENOMEM;
|
|
|
|
newc = kzalloc(sizeof(*newc), GFP_KERNEL);
|
|
|
|
if (!newc)
|
|
|
|
goto out;
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&newc->u.name, GFP_KERNEL, fp, len);
|
2010-07-22 00:50:57 +08:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
newc->v.sclass = le32_to_cpu(buf[0]);
|
|
|
|
rc = context_read_and_validate(&newc->context[0], p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
for (l = NULL, c = genfs->head; c;
|
|
|
|
l = c, c = c->next) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
if (!strcmp(newc->u.name, c->u.name) &&
|
|
|
|
(!c->v.sclass || !newc->v.sclass ||
|
|
|
|
newc->v.sclass == c->v.sclass)) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: dup genfs entry (%s,%s)\n",
|
2010-07-22 00:50:57 +08:00
|
|
|
genfs->fstype, c->u.name);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
len = strlen(newc->u.name);
|
|
|
|
len2 = strlen(c->u.name);
|
|
|
|
if (len > len2)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
newc->next = c;
|
|
|
|
if (l)
|
|
|
|
l->next = newc;
|
|
|
|
else
|
|
|
|
genfs->head = newc;
|
|
|
|
newc = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
out:
|
2017-01-15 00:43:47 +08:00
|
|
|
if (newgenfs) {
|
2010-07-22 00:50:57 +08:00
|
|
|
kfree(newgenfs->fstype);
|
2017-01-15 00:43:47 +08:00
|
|
|
kfree(newgenfs);
|
|
|
|
}
|
2010-07-22 00:50:57 +08:00
|
|
|
ocontext_destroy(newc, OCON_FSUSE);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-07-22 00:51:03 +08:00
|
|
|
static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
|
|
|
|
void *fp)
|
|
|
|
{
|
|
|
|
int i, j, rc;
|
|
|
|
u32 nel, len;
|
2018-10-23 15:02:17 +08:00
|
|
|
__be64 prefixbuf[1];
|
2010-07-22 00:51:03 +08:00
|
|
|
__le32 buf[3];
|
|
|
|
struct ocontext *l, *c;
|
|
|
|
u32 nodebuf[8];
|
|
|
|
|
|
|
|
for (i = 0; i < info->ocon_num; i++) {
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
nel = le32_to_cpu(buf[0]);
|
|
|
|
|
|
|
|
l = NULL;
|
|
|
|
for (j = 0; j < nel; j++) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
c = kzalloc(sizeof(*c), GFP_KERNEL);
|
|
|
|
if (!c)
|
|
|
|
goto out;
|
|
|
|
if (l)
|
|
|
|
l->next = c;
|
|
|
|
else
|
|
|
|
p->ocontexts[i] = c;
|
|
|
|
l = c;
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
case OCON_ISID:
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
c->sid[0] = le32_to_cpu(buf[0]);
|
|
|
|
rc = context_read_and_validate(&c->context[0], p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
case OCON_FS:
|
|
|
|
case OCON_NETIF:
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&c->u.name, GFP_KERNEL, fp, len);
|
2010-07-22 00:51:03 +08:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = context_read_and_validate(&c->context[0], p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
rc = context_read_and_validate(&c->context[1], p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
case OCON_PORT:
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32)*3);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
c->u.port.protocol = le32_to_cpu(buf[0]);
|
|
|
|
c->u.port.low_port = le32_to_cpu(buf[1]);
|
|
|
|
c->u.port.high_port = le32_to_cpu(buf[2]);
|
|
|
|
rc = context_read_and_validate(&c->context[0], p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
case OCON_NODE:
|
|
|
|
rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
c->u.node.addr = nodebuf[0]; /* network order */
|
|
|
|
c->u.node.mask = nodebuf[1]; /* network order */
|
|
|
|
rc = context_read_and_validate(&c->context[0], p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
case OCON_FSUSE:
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32)*2);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = -EINVAL;
|
|
|
|
c->v.behavior = le32_to_cpu(buf[0]);
|
2013-05-23 00:50:37 +08:00
|
|
|
/* Determined at runtime, not in policy DB. */
|
|
|
|
if (c->v.behavior == SECURITY_FS_USE_MNTPOINT)
|
|
|
|
goto out;
|
|
|
|
if (c->v.behavior > SECURITY_FS_USE_MAX)
|
2010-07-22 00:51:03 +08:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
len = le32_to_cpu(buf[1]);
|
2014-06-15 22:02:51 +08:00
|
|
|
rc = str_read(&c->u.name, GFP_KERNEL, fp, len);
|
2010-07-22 00:51:03 +08:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
2014-06-15 22:02:51 +08:00
|
|
|
|
2010-07-22 00:51:03 +08:00
|
|
|
rc = context_read_and_validate(&c->context[0], p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
case OCON_NODE6: {
|
|
|
|
int k;
|
|
|
|
|
|
|
|
rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
for (k = 0; k < 4; k++)
|
|
|
|
c->u.node6.addr[k] = nodebuf[k];
|
|
|
|
for (k = 0; k < 4; k++)
|
|
|
|
c->u.node6.mask[k] = nodebuf[k+4];
|
|
|
|
rc = context_read_and_validate(&c->context[0], p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
}
|
2018-10-23 15:02:17 +08:00
|
|
|
case OCON_IBPKEY: {
|
|
|
|
u32 pkey_lo, pkey_hi;
|
|
|
|
|
|
|
|
rc = next_entry(prefixbuf, fp, sizeof(u64));
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* we need to have subnet_prefix in CPU order */
|
|
|
|
c->u.ibpkey.subnet_prefix = be64_to_cpu(prefixbuf[0]);
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32) * 2);
|
2017-05-19 20:48:55 +08:00
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
2018-10-23 15:02:17 +08:00
|
|
|
pkey_lo = le32_to_cpu(buf[0]);
|
|
|
|
pkey_hi = le32_to_cpu(buf[1]);
|
2017-05-19 20:48:55 +08:00
|
|
|
|
2018-10-23 15:02:17 +08:00
|
|
|
if (pkey_lo > U16_MAX || pkey_hi > U16_MAX) {
|
2017-05-19 20:48:55 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-10-23 15:02:17 +08:00
|
|
|
c->u.ibpkey.low_pkey = pkey_lo;
|
|
|
|
c->u.ibpkey.high_pkey = pkey_hi;
|
2017-05-19 20:48:55 +08:00
|
|
|
|
|
|
|
rc = context_read_and_validate(&c->context[0],
|
|
|
|
p,
|
|
|
|
fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
break;
|
2018-10-23 15:02:17 +08:00
|
|
|
}
|
|
|
|
case OCON_IBENDPORT: {
|
|
|
|
u32 port;
|
|
|
|
|
2017-05-19 20:48:55 +08:00
|
|
|
rc = next_entry(buf, fp, sizeof(u32) * 2);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
len = le32_to_cpu(buf[0]);
|
|
|
|
|
|
|
|
rc = str_read(&c->u.ibendport.dev_name, GFP_KERNEL, fp, len);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
2018-10-23 15:02:17 +08:00
|
|
|
port = le32_to_cpu(buf[1]);
|
|
|
|
if (port > U8_MAX || port == 0) {
|
2017-05-19 20:48:55 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-10-23 15:02:17 +08:00
|
|
|
c->u.ibendport.port = port;
|
2017-05-19 20:48:55 +08:00
|
|
|
|
|
|
|
rc = context_read_and_validate(&c->context[0],
|
|
|
|
p,
|
|
|
|
fp);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
break;
|
2018-10-23 15:02:17 +08:00
|
|
|
} /* end case */
|
|
|
|
} /* end switch */
|
2010-07-22 00:51:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Read the configuration data from a policy database binary
|
|
|
|
* representation file into a policy database structure.
|
|
|
|
*/
|
|
|
|
int policydb_read(struct policydb *p, void *fp)
|
|
|
|
{
|
|
|
|
struct role_allow *ra, *lra;
|
2020-04-08 02:28:58 +08:00
|
|
|
struct role_trans_key *rtk = NULL;
|
|
|
|
struct role_trans_datum *rtd = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
int i, j, rc;
|
2008-06-05 21:48:51 +08:00
|
|
|
__le32 buf[4];
|
2010-07-22 00:50:57 +08:00
|
|
|
u32 len, nprim, nel;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
char *policydb_str;
|
|
|
|
struct policydb_compat_info *info;
|
|
|
|
|
|
|
|
rc = policydb_init(p);
|
|
|
|
if (rc)
|
2010-11-24 00:40:08 +08:00
|
|
|
return rc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Read the magic number and string length. */
|
2008-04-18 01:37:12 +08:00
|
|
|
rc = next_entry(buf, fp, sizeof(u32) * 2);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-09-04 06:55:17 +08:00
|
|
|
if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: policydb magic number 0x%x does "
|
2005-04-17 06:20:36 +08:00
|
|
|
"not match expected magic number 0x%x\n",
|
2005-09-04 06:55:17 +08:00
|
|
|
le32_to_cpu(buf[0]), POLICYDB_MAGIC);
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-09-04 06:55:17 +08:00
|
|
|
len = le32_to_cpu(buf[1]);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (len != strlen(POLICYDB_STRING)) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: policydb string length %d does not "
|
2017-02-28 06:30:02 +08:00
|
|
|
"match expected length %zu\n",
|
2005-04-17 06:20:36 +08:00
|
|
|
len, strlen(POLICYDB_STRING));
|
|
|
|
goto bad;
|
|
|
|
}
|
2010-11-24 00:40:08 +08:00
|
|
|
|
|
|
|
rc = -ENOMEM;
|
2008-04-18 01:37:12 +08:00
|
|
|
policydb_str = kmalloc(len + 1, GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!policydb_str) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: unable to allocate memory for policydb "
|
2005-04-17 06:20:36 +08:00
|
|
|
"string of length %d\n", len);
|
|
|
|
goto bad;
|
|
|
|
}
|
2010-11-24 00:40:08 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = next_entry(policydb_str, fp, len);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: truncated policydb string identifier\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
kfree(policydb_str);
|
|
|
|
goto bad;
|
|
|
|
}
|
2010-11-24 00:40:08 +08:00
|
|
|
|
|
|
|
rc = -EINVAL;
|
2008-07-21 04:57:01 +08:00
|
|
|
policydb_str[len] = '\0';
|
2005-04-17 06:20:36 +08:00
|
|
|
if (strcmp(policydb_str, POLICYDB_STRING)) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: policydb string %s does not match "
|
2005-04-17 06:20:36 +08:00
|
|
|
"my string %s\n", policydb_str, POLICYDB_STRING);
|
|
|
|
kfree(policydb_str);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
/* Done with policydb_str. */
|
|
|
|
kfree(policydb_str);
|
|
|
|
policydb_str = NULL;
|
|
|
|
|
2010-02-03 23:40:20 +08:00
|
|
|
/* Read the version and table sizes. */
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = next_entry(buf, fp, sizeof(u32)*4);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-09-04 06:55:17 +08:00
|
|
|
p->policyvers = le32_to_cpu(buf[0]);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (p->policyvers < POLICYDB_VERSION_MIN ||
|
|
|
|
p->policyvers > POLICYDB_VERSION_MAX) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: policydb version %d does not match "
|
2008-04-18 01:37:12 +08:00
|
|
|
"my version range %d-%d\n",
|
|
|
|
le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
|
|
|
|
goto bad;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-09-04 06:55:17 +08:00
|
|
|
if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
|
2010-02-03 23:40:20 +08:00
|
|
|
p->mls_enabled = 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (p->policyvers < POLICYDB_VERSION_MLS) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: security policydb version %d "
|
2008-04-17 23:52:44 +08:00
|
|
|
"(MLS) not backwards compatible\n",
|
|
|
|
p->policyvers);
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
}
|
2007-09-22 02:37:10 +08:00
|
|
|
p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
|
|
|
|
p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
|
|
|
|
rc = ebitmap_read(&p->policycaps, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
2008-01-29 21:38:19 +08:00
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
|
|
|
|
rc = ebitmap_read(&p->permissive_map, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
2008-03-31 09:17:33 +08:00
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
info = policydb_lookup_compat(p->policyvers);
|
|
|
|
if (!info) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: unable to find policy compat info "
|
2005-04-17 06:20:36 +08:00
|
|
|
"for version %d\n", p->policyvers);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
2005-09-04 06:55:17 +08:00
|
|
|
if (le32_to_cpu(buf[2]) != info->sym_num ||
|
|
|
|
le32_to_cpu(buf[3]) != info->ocon_num) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: policydb table sizes (%d,%d) do "
|
2005-09-04 06:55:17 +08:00
|
|
|
"not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
|
|
|
|
le32_to_cpu(buf[3]),
|
2005-04-17 06:20:36 +08:00
|
|
|
info->sym_num, info->ocon_num);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < info->sym_num; i++) {
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32)*2);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
nprim = le32_to_cpu(buf[0]);
|
|
|
|
nel = le32_to_cpu(buf[1]);
|
2020-02-26 23:54:52 +08:00
|
|
|
|
|
|
|
rc = symtab_init(&p->symtab[i], nel);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (i == SYM_ROLES) {
|
|
|
|
rc = roles_init(p);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
for (j = 0; j < nel; j++) {
|
|
|
|
rc = read_f[i](p, p->symtab[i].table, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->symtab[i].nprim = nprim;
|
|
|
|
}
|
|
|
|
|
2011-04-07 14:12:57 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
p->process_class = string_to_security_class(p, "process");
|
|
|
|
if (!p->process_class)
|
|
|
|
goto bad;
|
|
|
|
|
2007-11-07 23:08:00 +08:00
|
|
|
rc = avtab_read(&p->te_avtab, fp, p);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOOL) {
|
|
|
|
rc = cond_read_list(p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
nel = le32_to_cpu(buf[0]);
|
2020-04-08 02:28:58 +08:00
|
|
|
|
|
|
|
p->role_tr = hashtab_create(role_trans_hash, role_trans_cmp, nel);
|
|
|
|
if (!p->role_tr)
|
|
|
|
goto bad;
|
2005-04-17 06:20:36 +08:00
|
|
|
for (i = 0; i < nel; i++) {
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -ENOMEM;
|
2020-04-08 02:28:58 +08:00
|
|
|
rtk = kmalloc(sizeof(*rtk), GFP_KERNEL);
|
|
|
|
if (!rtk)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
2020-04-08 02:28:58 +08:00
|
|
|
|
|
|
|
rc = -ENOMEM;
|
|
|
|
rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
|
|
|
|
if (!rtd)
|
|
|
|
goto bad;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = next_entry(buf, fp, sizeof(u32)*3);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
|
|
|
|
rc = -EINVAL;
|
2020-04-08 02:28:58 +08:00
|
|
|
rtk->role = le32_to_cpu(buf[0]);
|
|
|
|
rtk->type = le32_to_cpu(buf[1]);
|
|
|
|
rtd->new_role = le32_to_cpu(buf[2]);
|
2011-03-25 13:51:56 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2020-04-08 02:28:58 +08:00
|
|
|
rtk->tclass = le32_to_cpu(buf[0]);
|
2011-03-25 13:51:56 +08:00
|
|
|
} else
|
2020-04-08 02:28:58 +08:00
|
|
|
rtk->tclass = p->process_class;
|
2011-03-25 13:51:56 +08:00
|
|
|
|
2016-09-10 15:43:48 +08:00
|
|
|
rc = -EINVAL;
|
2020-04-08 02:28:58 +08:00
|
|
|
if (!policydb_role_isvalid(p, rtk->role) ||
|
|
|
|
!policydb_type_isvalid(p, rtk->type) ||
|
|
|
|
!policydb_class_isvalid(p, rtk->tclass) ||
|
|
|
|
!policydb_role_isvalid(p, rtd->new_role))
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
rc = hashtab_insert(p->role_tr, rtk, rtd);
|
|
|
|
if (rc)
|
2007-11-07 23:08:00 +08:00
|
|
|
goto bad;
|
2020-04-08 02:28:58 +08:00
|
|
|
|
|
|
|
rtk = NULL;
|
|
|
|
rtd = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32));
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
nel = le32_to_cpu(buf[0]);
|
|
|
|
lra = NULL;
|
|
|
|
for (i = 0; i < nel; i++) {
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -ENOMEM;
|
2005-10-31 06:59:21 +08:00
|
|
|
ra = kzalloc(sizeof(*ra), GFP_KERNEL);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (!ra)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
2008-04-18 01:37:12 +08:00
|
|
|
if (lra)
|
2005-04-17 06:20:36 +08:00
|
|
|
lra->next = ra;
|
2008-04-18 01:37:12 +08:00
|
|
|
else
|
2005-04-17 06:20:36 +08:00
|
|
|
p->role_allow = ra;
|
|
|
|
rc = next_entry(buf, fp, sizeof(u32)*2);
|
2010-11-24 00:40:08 +08:00
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
2010-11-24 00:40:08 +08:00
|
|
|
|
|
|
|
rc = -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
ra->role = le32_to_cpu(buf[0]);
|
|
|
|
ra->new_role = le32_to_cpu(buf[1]);
|
2007-11-07 23:08:00 +08:00
|
|
|
if (!policydb_role_isvalid(p, ra->role) ||
|
2010-11-24 00:40:08 +08:00
|
|
|
!policydb_role_isvalid(p, ra->new_role))
|
2007-11-07 23:08:00 +08:00
|
|
|
goto bad;
|
2005-04-17 06:20:36 +08:00
|
|
|
lra = ra;
|
|
|
|
}
|
|
|
|
|
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-02 00:05:40 +08:00
|
|
|
rc = filename_trans_read(p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
2010-11-30 04:47:09 +08:00
|
|
|
rc = policydb_index(p);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
2010-11-24 00:40:08 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
|
|
|
|
p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
|
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 01:37:50 +08:00
|
|
|
if (!p->process_trans_perms)
|
|
|
|
goto bad;
|
|
|
|
|
2010-07-22 00:51:03 +08:00
|
|
|
rc = ocontext_read(p, info, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-07-22 00:50:57 +08:00
|
|
|
rc = genfs_read(p, fp);
|
|
|
|
if (rc)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto bad;
|
|
|
|
|
2010-06-12 00:37:05 +08:00
|
|
|
rc = range_read(p, fp);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2019-03-12 14:31:10 +08:00
|
|
|
p->type_attr_map_array = kvcalloc(p->p_types.nprim,
|
|
|
|
sizeof(*p->type_attr_map_array),
|
|
|
|
GFP_KERNEL);
|
2010-07-30 11:02:34 +08:00
|
|
|
if (!p->type_attr_map_array)
|
|
|
|
goto bad;
|
|
|
|
|
2019-03-17 21:46:53 +08:00
|
|
|
/* just in case ebitmap_init() becomes more than just a memset(0): */
|
|
|
|
for (i = 0; i < p->p_types.nprim; i++)
|
|
|
|
ebitmap_init(&p->type_attr_map_array[i]);
|
|
|
|
|
2005-09-04 06:55:16 +08:00
|
|
|
for (i = 0; i < p->p_types.nprim; i++) {
|
2019-03-12 14:31:10 +08:00
|
|
|
struct ebitmap *e = &p->type_attr_map_array[i];
|
2010-07-30 11:02:34 +08:00
|
|
|
|
2005-09-04 06:55:16 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
|
2010-07-30 11:02:34 +08:00
|
|
|
rc = ebitmap_read(e, fp);
|
|
|
|
if (rc)
|
2005-09-04 06:55:16 +08:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
/* add the type itself as the degenerate case */
|
2010-07-30 11:02:34 +08:00
|
|
|
rc = ebitmap_set_bit(e, i, 1);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
2005-09-04 06:55:16 +08:00
|
|
|
}
|
|
|
|
|
2008-08-28 15:35:57 +08:00
|
|
|
rc = policydb_bounds_sanity_check(p);
|
|
|
|
if (rc)
|
|
|
|
goto bad;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
bad:
|
2020-04-08 02:28:58 +08:00
|
|
|
kfree(rtk);
|
|
|
|
kfree(rtd);
|
2005-04-17 06:20:36 +08:00
|
|
|
policydb_destroy(p);
|
|
|
|
goto out;
|
|
|
|
}
|
2010-10-14 05:50:25 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Write a MLS level structure to a policydb binary
|
|
|
|
* representation file.
|
|
|
|
*/
|
|
|
|
static int mls_write_level(struct mls_level *l, void *fp)
|
|
|
|
{
|
|
|
|
__le32 buf[1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(l->sens);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = ebitmap_write(&l->cat, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write a MLS range structure to a policydb binary
|
|
|
|
* representation file.
|
|
|
|
*/
|
|
|
|
static int mls_write_range_helper(struct mls_range *r, void *fp)
|
|
|
|
{
|
|
|
|
__le32 buf[3];
|
|
|
|
size_t items;
|
|
|
|
int rc, eq;
|
|
|
|
|
|
|
|
eq = mls_level_eq(&r->level[1], &r->level[0]);
|
|
|
|
|
|
|
|
if (eq)
|
|
|
|
items = 2;
|
|
|
|
else
|
|
|
|
items = 3;
|
|
|
|
buf[0] = cpu_to_le32(items-1);
|
|
|
|
buf[1] = cpu_to_le32(r->level[0].sens);
|
|
|
|
if (!eq)
|
|
|
|
buf[2] = cpu_to_le32(r->level[1].sens);
|
|
|
|
|
2014-06-17 04:11:05 +08:00
|
|
|
BUG_ON(items > ARRAY_SIZE(buf));
|
2010-10-14 05:50:25 +08:00
|
|
|
|
|
|
|
rc = put_entry(buf, sizeof(u32), items, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = ebitmap_write(&r->level[0].cat, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
if (!eq) {
|
|
|
|
rc = ebitmap_write(&r->level[1].cat, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sens_write(void *vkey, void *datum, void *ptr)
|
|
|
|
{
|
|
|
|
char *key = vkey;
|
|
|
|
struct level_datum *levdatum = datum;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
__le32 buf[2];
|
|
|
|
size_t len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = strlen(key);
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
buf[1] = cpu_to_le32(levdatum->isalias);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = put_entry(key, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = mls_write_level(levdatum->level, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cat_write(void *vkey, void *datum, void *ptr)
|
|
|
|
{
|
|
|
|
char *key = vkey;
|
|
|
|
struct cat_datum *catdatum = datum;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
__le32 buf[3];
|
|
|
|
size_t len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = strlen(key);
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
buf[1] = cpu_to_le32(catdatum->value);
|
|
|
|
buf[2] = cpu_to_le32(catdatum->isalias);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 3, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = put_entry(key, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-08 02:28:58 +08:00
|
|
|
static int role_trans_write_one(void *key, void *datum, void *ptr)
|
2010-10-14 05:50:25 +08:00
|
|
|
{
|
2020-04-08 02:28:58 +08:00
|
|
|
struct role_trans_key *rtk = key;
|
|
|
|
struct role_trans_datum *rtd = datum;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
struct policydb *p = pd->p;
|
2020-01-17 02:45:57 +08:00
|
|
|
__le32 buf[3];
|
2010-10-14 05:50:25 +08:00
|
|
|
int rc;
|
|
|
|
|
2020-04-08 02:28:58 +08:00
|
|
|
buf[0] = cpu_to_le32(rtk->role);
|
|
|
|
buf[1] = cpu_to_le32(rtk->type);
|
|
|
|
buf[2] = cpu_to_le32(rtd->new_role);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 3, fp);
|
2010-10-14 05:50:25 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
2020-04-08 02:28:58 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
|
|
|
|
buf[0] = cpu_to_le32(rtk->tclass);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
2010-10-14 05:50:25 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-08 02:28:58 +08:00
|
|
|
static int role_trans_write(struct policydb *p, void *fp)
|
|
|
|
{
|
|
|
|
struct policy_data pd = { .p = p, .fp = fp };
|
|
|
|
__le32 buf[1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(p->role_tr->nel);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return hashtab_map(p->role_tr, role_trans_write_one, &pd);
|
|
|
|
}
|
|
|
|
|
2010-10-14 05:50:25 +08:00
|
|
|
static int role_allow_write(struct role_allow *r, void *fp)
|
|
|
|
{
|
|
|
|
struct role_allow *ra;
|
2020-01-17 02:45:57 +08:00
|
|
|
__le32 buf[2];
|
2010-10-14 05:50:25 +08:00
|
|
|
size_t nel;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
nel = 0;
|
|
|
|
for (ra = r; ra; ra = ra->next)
|
|
|
|
nel++;
|
|
|
|
buf[0] = cpu_to_le32(nel);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
for (ra = r; ra; ra = ra->next) {
|
|
|
|
buf[0] = cpu_to_le32(ra->role);
|
|
|
|
buf[1] = cpu_to_le32(ra->new_role);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write a security context structure
|
|
|
|
* to a policydb binary representation file.
|
|
|
|
*/
|
|
|
|
static int context_write(struct policydb *p, struct context *c,
|
|
|
|
void *fp)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__le32 buf[3];
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(c->user);
|
|
|
|
buf[1] = cpu_to_le32(c->role);
|
|
|
|
buf[2] = cpu_to_le32(c->type);
|
|
|
|
|
|
|
|
rc = put_entry(buf, sizeof(u32), 3, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = mls_write_range_helper(&c->range, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The following *_write functions are used to
|
|
|
|
* write the symbol data to a policy database
|
|
|
|
* binary representation file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int perm_write(void *vkey, void *datum, void *fp)
|
|
|
|
{
|
|
|
|
char *key = vkey;
|
|
|
|
struct perm_datum *perdatum = datum;
|
|
|
|
__le32 buf[2];
|
|
|
|
size_t len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = strlen(key);
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
buf[1] = cpu_to_le32(perdatum->value);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = put_entry(key, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int common_write(void *vkey, void *datum, void *ptr)
|
|
|
|
{
|
|
|
|
char *key = vkey;
|
|
|
|
struct common_datum *comdatum = datum;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
__le32 buf[4];
|
|
|
|
size_t len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = strlen(key);
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
buf[1] = cpu_to_le32(comdatum->value);
|
|
|
|
buf[2] = cpu_to_le32(comdatum->permissions.nprim);
|
|
|
|
buf[3] = cpu_to_le32(comdatum->permissions.table->nel);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 4, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = put_entry(key, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = hashtab_map(comdatum->permissions.table, perm_write, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-11-20 06:34:23 +08:00
|
|
|
static int type_set_write(struct type_set *t, void *fp)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__le32 buf[1];
|
|
|
|
|
|
|
|
if (ebitmap_write(&t->types, fp))
|
|
|
|
return -EINVAL;
|
|
|
|
if (ebitmap_write(&t->negset, fp))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(t->flags);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-14 05:50:25 +08:00
|
|
|
static int write_cons_helper(struct policydb *p, struct constraint_node *node,
|
|
|
|
void *fp)
|
|
|
|
{
|
|
|
|
struct constraint_node *c;
|
|
|
|
struct constraint_expr *e;
|
|
|
|
__le32 buf[3];
|
|
|
|
u32 nel;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
for (c = node; c; c = c->next) {
|
|
|
|
nel = 0;
|
|
|
|
for (e = c->expr; e; e = e->next)
|
|
|
|
nel++;
|
|
|
|
buf[0] = cpu_to_le32(c->permissions);
|
|
|
|
buf[1] = cpu_to_le32(nel);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
for (e = c->expr; e; e = e->next) {
|
|
|
|
buf[0] = cpu_to_le32(e->expr_type);
|
|
|
|
buf[1] = cpu_to_le32(e->attr);
|
|
|
|
buf[2] = cpu_to_le32(e->op);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 3, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
switch (e->expr_type) {
|
|
|
|
case CEXPR_NAMES:
|
|
|
|
rc = ebitmap_write(&e->names, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
2013-11-20 06:34:23 +08:00
|
|
|
if (p->policyvers >=
|
|
|
|
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
|
|
|
rc = type_set_write(e->type_names, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
2010-10-14 05:50:25 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int class_write(void *vkey, void *datum, void *ptr)
|
|
|
|
{
|
|
|
|
char *key = vkey;
|
|
|
|
struct class_datum *cladatum = datum;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
struct policydb *p = pd->p;
|
|
|
|
struct constraint_node *c;
|
|
|
|
__le32 buf[6];
|
|
|
|
u32 ncons;
|
|
|
|
size_t len, len2;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = strlen(key);
|
|
|
|
if (cladatum->comkey)
|
|
|
|
len2 = strlen(cladatum->comkey);
|
|
|
|
else
|
|
|
|
len2 = 0;
|
|
|
|
|
|
|
|
ncons = 0;
|
|
|
|
for (c = cladatum->constraints; c; c = c->next)
|
|
|
|
ncons++;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
buf[1] = cpu_to_le32(len2);
|
|
|
|
buf[2] = cpu_to_le32(cladatum->value);
|
|
|
|
buf[3] = cpu_to_le32(cladatum->permissions.nprim);
|
|
|
|
if (cladatum->permissions.table)
|
|
|
|
buf[4] = cpu_to_le32(cladatum->permissions.table->nel);
|
|
|
|
else
|
|
|
|
buf[4] = 0;
|
|
|
|
buf[5] = cpu_to_le32(ncons);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 6, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = put_entry(key, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (cladatum->comkey) {
|
|
|
|
rc = put_entry(cladatum->comkey, 1, len2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = hashtab_map(cladatum->permissions.table, perm_write, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = write_cons_helper(p, cladatum->constraints, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* write out the validatetrans rule */
|
|
|
|
ncons = 0;
|
|
|
|
for (c = cladatum->validatetrans; c; c = c->next)
|
|
|
|
ncons++;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(ncons);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = write_cons_helper(p, cladatum->validatetrans, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2012-03-21 02:35:12 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
|
|
|
|
buf[0] = cpu_to_le32(cladatum->default_user);
|
|
|
|
buf[1] = cpu_to_le32(cladatum->default_role);
|
|
|
|
buf[2] = cpu_to_le32(cladatum->default_range);
|
|
|
|
|
|
|
|
rc = put_entry(buf, sizeof(uint32_t), 3, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-03-21 02:35:12 +08:00
|
|
|
if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) {
|
|
|
|
buf[0] = cpu_to_le32(cladatum->default_type);
|
|
|
|
rc = put_entry(buf, sizeof(uint32_t), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-10-14 05:50:25 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int role_write(void *vkey, void *datum, void *ptr)
|
|
|
|
{
|
|
|
|
char *key = vkey;
|
|
|
|
struct role_datum *role = datum;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
struct policydb *p = pd->p;
|
|
|
|
__le32 buf[3];
|
|
|
|
size_t items, len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = strlen(key);
|
|
|
|
items = 0;
|
|
|
|
buf[items++] = cpu_to_le32(len);
|
|
|
|
buf[items++] = cpu_to_le32(role->value);
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
|
|
|
|
buf[items++] = cpu_to_le32(role->bounds);
|
|
|
|
|
2014-06-17 04:11:05 +08:00
|
|
|
BUG_ON(items > ARRAY_SIZE(buf));
|
2010-10-14 05:50:25 +08:00
|
|
|
|
|
|
|
rc = put_entry(buf, sizeof(u32), items, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = put_entry(key, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = ebitmap_write(&role->dominates, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = ebitmap_write(&role->types, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int type_write(void *vkey, void *datum, void *ptr)
|
|
|
|
{
|
|
|
|
char *key = vkey;
|
|
|
|
struct type_datum *typdatum = datum;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
struct policydb *p = pd->p;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
__le32 buf[4];
|
|
|
|
int rc;
|
|
|
|
size_t items, len;
|
|
|
|
|
|
|
|
len = strlen(key);
|
|
|
|
items = 0;
|
|
|
|
buf[items++] = cpu_to_le32(len);
|
|
|
|
buf[items++] = cpu_to_le32(typdatum->value);
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
|
|
|
|
u32 properties = 0;
|
|
|
|
|
|
|
|
if (typdatum->primary)
|
|
|
|
properties |= TYPEDATUM_PROPERTY_PRIMARY;
|
|
|
|
|
|
|
|
if (typdatum->attribute)
|
|
|
|
properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
|
|
|
|
|
|
|
|
buf[items++] = cpu_to_le32(properties);
|
|
|
|
buf[items++] = cpu_to_le32(typdatum->bounds);
|
|
|
|
} else {
|
|
|
|
buf[items++] = cpu_to_le32(typdatum->primary);
|
|
|
|
}
|
2014-06-17 04:11:05 +08:00
|
|
|
BUG_ON(items > ARRAY_SIZE(buf));
|
2010-10-14 05:50:25 +08:00
|
|
|
rc = put_entry(buf, sizeof(u32), items, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = put_entry(key, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int user_write(void *vkey, void *datum, void *ptr)
|
|
|
|
{
|
|
|
|
char *key = vkey;
|
|
|
|
struct user_datum *usrdatum = datum;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
struct policydb *p = pd->p;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
__le32 buf[3];
|
|
|
|
size_t items, len;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = strlen(key);
|
|
|
|
items = 0;
|
|
|
|
buf[items++] = cpu_to_le32(len);
|
|
|
|
buf[items++] = cpu_to_le32(usrdatum->value);
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
|
|
|
|
buf[items++] = cpu_to_le32(usrdatum->bounds);
|
2014-06-17 04:11:05 +08:00
|
|
|
BUG_ON(items > ARRAY_SIZE(buf));
|
2010-10-14 05:50:25 +08:00
|
|
|
rc = put_entry(buf, sizeof(u32), items, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = put_entry(key, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = ebitmap_write(&usrdatum->roles, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = mls_write_range_helper(&usrdatum->range, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = mls_write_level(&usrdatum->dfltlevel, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int (*write_f[SYM_NUM]) (void *key, void *datum,
|
|
|
|
void *datap) =
|
|
|
|
{
|
|
|
|
common_write,
|
|
|
|
class_write,
|
|
|
|
role_write,
|
|
|
|
type_write,
|
|
|
|
user_write,
|
|
|
|
cond_write_bool,
|
|
|
|
sens_write,
|
|
|
|
cat_write,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int ocontext_write(struct policydb *p, struct policydb_compat_info *info,
|
|
|
|
void *fp)
|
|
|
|
{
|
|
|
|
unsigned int i, j, rc;
|
|
|
|
size_t nel, len;
|
2018-10-23 15:02:17 +08:00
|
|
|
__be64 prefixbuf[1];
|
2010-10-14 05:50:25 +08:00
|
|
|
__le32 buf[3];
|
|
|
|
u32 nodebuf[8];
|
|
|
|
struct ocontext *c;
|
|
|
|
for (i = 0; i < info->ocon_num; i++) {
|
|
|
|
nel = 0;
|
|
|
|
for (c = p->ocontexts[i]; c; c = c->next)
|
|
|
|
nel++;
|
|
|
|
buf[0] = cpu_to_le32(nel);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
for (c = p->ocontexts[i]; c; c = c->next) {
|
|
|
|
switch (i) {
|
|
|
|
case OCON_ISID:
|
|
|
|
buf[0] = cpu_to_le32(c->sid[0]);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
break;
|
|
|
|
case OCON_FS:
|
|
|
|
case OCON_NETIF:
|
|
|
|
len = strlen(c->u.name);
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = put_entry(c->u.name, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[1], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
break;
|
|
|
|
case OCON_PORT:
|
|
|
|
buf[0] = cpu_to_le32(c->u.port.protocol);
|
|
|
|
buf[1] = cpu_to_le32(c->u.port.low_port);
|
|
|
|
buf[2] = cpu_to_le32(c->u.port.high_port);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 3, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
break;
|
|
|
|
case OCON_NODE:
|
|
|
|
nodebuf[0] = c->u.node.addr; /* network order */
|
|
|
|
nodebuf[1] = c->u.node.mask; /* network order */
|
|
|
|
rc = put_entry(nodebuf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
break;
|
|
|
|
case OCON_FSUSE:
|
|
|
|
buf[0] = cpu_to_le32(c->v.behavior);
|
|
|
|
len = strlen(c->u.name);
|
|
|
|
buf[1] = cpu_to_le32(len);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = put_entry(c->u.name, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
break;
|
|
|
|
case OCON_NODE6:
|
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
nodebuf[j] = c->u.node6.addr[j]; /* network order */
|
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */
|
|
|
|
rc = put_entry(nodebuf, sizeof(u32), 8, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
break;
|
2017-05-19 20:48:55 +08:00
|
|
|
case OCON_IBPKEY:
|
2018-10-23 15:02:17 +08:00
|
|
|
/* subnet_prefix is in CPU order */
|
|
|
|
prefixbuf[0] = cpu_to_be64(c->u.ibpkey.subnet_prefix);
|
2017-05-19 20:48:55 +08:00
|
|
|
|
2018-10-23 15:02:17 +08:00
|
|
|
rc = put_entry(prefixbuf, sizeof(u64), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(c->u.ibpkey.low_pkey);
|
|
|
|
buf[1] = cpu_to_le32(c->u.ibpkey.high_pkey);
|
2017-05-19 20:48:55 +08:00
|
|
|
|
2018-10-23 15:02:17 +08:00
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
2017-05-19 20:48:55 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
break;
|
|
|
|
case OCON_IBENDPORT:
|
|
|
|
len = strlen(c->u.ibendport.dev_name);
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
buf[1] = cpu_to_le32(c->u.ibendport.port);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = put_entry(c->u.ibendport.dev_name, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
break;
|
2010-10-14 05:50:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int genfs_write(struct policydb *p, void *fp)
|
|
|
|
{
|
|
|
|
struct genfs *genfs;
|
|
|
|
struct ocontext *c;
|
|
|
|
size_t len;
|
|
|
|
__le32 buf[1];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
for (genfs = p->genfs; genfs; genfs = genfs->next)
|
|
|
|
len++;
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
for (genfs = p->genfs; genfs; genfs = genfs->next) {
|
|
|
|
len = strlen(genfs->fstype);
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = put_entry(genfs->fstype, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
len = 0;
|
|
|
|
for (c = genfs->head; c; c = c->next)
|
|
|
|
len++;
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
for (c = genfs->head; c; c = c->next) {
|
|
|
|
len = strlen(c->u.name);
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = put_entry(c->u.name, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
buf[0] = cpu_to_le32(c->v.sclass);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = context_write(p, &c->context[0], fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
static int hashtab_cnt(void *key, void *data, void *ptr)
|
2010-10-14 05:50:25 +08:00
|
|
|
{
|
|
|
|
int *cnt = ptr;
|
|
|
|
*cnt = *cnt + 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int range_write_helper(void *key, void *data, void *ptr)
|
|
|
|
{
|
|
|
|
__le32 buf[2];
|
|
|
|
struct range_trans *rt = key;
|
|
|
|
struct mls_range *r = data;
|
|
|
|
struct policy_data *pd = ptr;
|
|
|
|
void *fp = pd->fp;
|
|
|
|
struct policydb *p = pd->p;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(rt->source_type);
|
|
|
|
buf[1] = cpu_to_le32(rt->target_type);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
|
|
|
|
buf[0] = cpu_to_le32(rt->target_class);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
rc = mls_write_range_helper(r, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int range_write(struct policydb *p, void *fp)
|
|
|
|
{
|
|
|
|
__le32 buf[1];
|
SELinux: fix selinuxfs policy file on big endian systems
The /sys/fs/selinux/policy file is not valid on big endian systems like
ppc64 or s390. Let's see why:
static int hashtab_cnt(void *key, void *data, void *ptr)
{
int *cnt = ptr;
*cnt = *cnt + 1;
return 0;
}
static int range_write(struct policydb *p, void *fp)
{
size_t nel;
[...]
/* count the number of entries in the hashtab */
nel = 0;
rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
if (rc)
return rc;
buf[0] = cpu_to_le32(nel);
rc = put_entry(buf, sizeof(u32), 1, fp);
So size_t is 64 bits. But then we pass a pointer to it as we do to
hashtab_cnt. hashtab_cnt thinks it is a 32 bit int and only deals with
the first 4 bytes. On x86_64 which is little endian, those first 4
bytes and the least significant, so this works out fine. On ppc64/s390
those first 4 bytes of memory are the high order bits. So at the end of
the call to hashtab_map nel has a HUGE number. But the least
significant 32 bits are all 0's.
We then pass that 64 bit number to cpu_to_le32() which happily truncates
it to a 32 bit number and does endian swapping. But the low 32 bits are
all 0's. So no matter how many entries are in the hashtab, big endian
systems always say there are 0 entries because I screwed up the
counting.
The fix is easy. Use a 32 bit int, as the hashtab_cnt expects, for nel.
Signed-off-by: Eric Paris <eparis@redhat.com>
Signed-off-by: Paul Moore <pmoore@redhat.com>
2013-07-24 05:38:42 +08:00
|
|
|
int rc, nel;
|
2010-10-14 05:50:25 +08:00
|
|
|
struct policy_data pd;
|
|
|
|
|
|
|
|
pd.p = p;
|
|
|
|
pd.fp = fp;
|
|
|
|
|
|
|
|
/* count the number of entries in the hashtab */
|
|
|
|
nel = 0;
|
2011-04-29 03:11:21 +08:00
|
|
|
rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
|
2010-10-14 05:50:25 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(nel);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* actually write all of the entries */
|
|
|
|
rc = hashtab_map(p->range_tr, range_write_helper, &pd);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-29 03:11:21 +08:00
|
|
|
static int filename_write_helper(void *key, void *data, void *ptr)
|
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-02 00:05:40 +08: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 19:27:34 +08:00
|
|
|
struct filename_trans_key *ft = key;
|
|
|
|
struct filename_trans_datum *datum = data;
|
|
|
|
struct ebitmap_node *node;
|
2011-04-29 03:11:21 +08:00
|
|
|
void *fp = ptr;
|
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 19:27:34 +08:00
|
|
|
__le32 buf[4];
|
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-02 00:05:40 +08:00
|
|
|
int rc;
|
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 19:27:34 +08:00
|
|
|
u32 bit, len = strlen(ft->name);
|
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-02 00:05:40 +08: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 19:27:34 +08:00
|
|
|
do {
|
|
|
|
ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
|
|
|
|
buf[0] = cpu_to_le32(len);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
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-02 00:05:40 +08: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 19:27:34 +08:00
|
|
|
rc = put_entry(ft->name, sizeof(char), len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
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-02 00:05:40 +08: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 19:27:34 +08:00
|
|
|
buf[0] = cpu_to_le32(bit + 1);
|
|
|
|
buf[1] = cpu_to_le32(ft->ttype);
|
|
|
|
buf[2] = cpu_to_le32(ft->tclass);
|
|
|
|
buf[3] = cpu_to_le32(datum->otype);
|
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-02 00:05:40 +08: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 19:27:34 +08:00
|
|
|
rc = put_entry(buf, sizeof(u32), 4, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
datum = datum->next;
|
|
|
|
} while (unlikely(datum));
|
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-02 00:05:40 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2011-04-29 03:11:21 +08:00
|
|
|
|
|
|
|
static int filename_trans_write(struct policydb *p, void *fp)
|
|
|
|
{
|
|
|
|
__le32 buf[1];
|
|
|
|
int rc;
|
|
|
|
|
2011-05-20 10:38:06 +08:00
|
|
|
if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
|
|
|
|
return 0;
|
|
|
|
|
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 19:27:34 +08:00
|
|
|
buf[0] = cpu_to_le32(p->filename_trans_count);
|
2011-04-29 03:11:21 +08:00
|
|
|
rc = put_entry(buf, sizeof(u32), 1, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-14 05:50:25 +08:00
|
|
|
/*
|
|
|
|
* Write the configuration data in a policy database
|
|
|
|
* structure to a policy database binary representation
|
|
|
|
* file.
|
|
|
|
*/
|
|
|
|
int policydb_write(struct policydb *p, void *fp)
|
|
|
|
{
|
|
|
|
unsigned int i, num_syms;
|
|
|
|
int rc;
|
|
|
|
__le32 buf[4];
|
|
|
|
u32 config;
|
|
|
|
size_t len;
|
|
|
|
struct policydb_compat_info *info;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* refuse to write policy older than compressed avtab
|
|
|
|
* to simplify the writer. There are other tests dropped
|
|
|
|
* since we assume this throughout the writer code. Be
|
|
|
|
* careful if you ever try to remove this restriction
|
|
|
|
*/
|
|
|
|
if (p->policyvers < POLICYDB_VERSION_AVTAB) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: refusing to write policy version %d."
|
2010-10-14 05:50:25 +08:00
|
|
|
" Because it is less than version %d\n", p->policyvers,
|
|
|
|
POLICYDB_VERSION_AVTAB);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
config = 0;
|
|
|
|
if (p->mls_enabled)
|
|
|
|
config |= POLICYDB_CONFIG_MLS;
|
|
|
|
|
|
|
|
if (p->reject_unknown)
|
|
|
|
config |= REJECT_UNKNOWN;
|
|
|
|
if (p->allow_unknown)
|
|
|
|
config |= ALLOW_UNKNOWN;
|
|
|
|
|
|
|
|
/* Write the magic number and string identifiers. */
|
|
|
|
buf[0] = cpu_to_le32(POLICYDB_MAGIC);
|
|
|
|
len = strlen(POLICYDB_STRING);
|
|
|
|
buf[1] = cpu_to_le32(len);
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = put_entry(POLICYDB_STRING, 1, len, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* Write the version, config, and table sizes. */
|
|
|
|
info = policydb_lookup_compat(p->policyvers);
|
|
|
|
if (!info) {
|
2018-06-12 16:09:02 +08:00
|
|
|
pr_err("SELinux: compatibility lookup failed for policy "
|
2010-10-14 05:50:25 +08:00
|
|
|
"version %d", p->policyvers);
|
2010-11-24 00:40:08 +08:00
|
|
|
return -EINVAL;
|
2010-10-14 05:50:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(p->policyvers);
|
|
|
|
buf[1] = cpu_to_le32(config);
|
|
|
|
buf[2] = cpu_to_le32(info->sym_num);
|
|
|
|
buf[3] = cpu_to_le32(info->ocon_num);
|
|
|
|
|
|
|
|
rc = put_entry(buf, sizeof(u32), 4, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
|
|
|
|
rc = ebitmap_write(&p->policycaps, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
|
|
|
|
rc = ebitmap_write(&p->permissive_map, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_syms = info->sym_num;
|
|
|
|
for (i = 0; i < num_syms; i++) {
|
|
|
|
struct policy_data pd;
|
|
|
|
|
|
|
|
pd.fp = fp;
|
|
|
|
pd.p = p;
|
|
|
|
|
|
|
|
buf[0] = cpu_to_le32(p->symtab[i].nprim);
|
|
|
|
buf[1] = cpu_to_le32(p->symtab[i].table->nel);
|
|
|
|
|
|
|
|
rc = put_entry(buf, sizeof(u32), 2, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
rc = hashtab_map(p->symtab[i].table, write_f[i], &pd);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = avtab_write(p, &p->te_avtab, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2020-02-03 19:27:20 +08:00
|
|
|
rc = cond_write_list(p, fp);
|
2010-10-14 05:50:25 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2011-03-25 13:52:00 +08:00
|
|
|
rc = role_trans_write(p, fp);
|
2010-10-14 05:50:25 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = role_allow_write(p->role_allow, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
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-02 00:05:40 +08:00
|
|
|
rc = filename_trans_write(p, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2010-10-14 05:50:25 +08:00
|
|
|
rc = ocontext_write(p, info, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = genfs_write(p, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = range_write(p, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
for (i = 0; i < p->p_types.nprim; i++) {
|
2019-03-12 14:31:10 +08:00
|
|
|
struct ebitmap *e = &p->type_attr_map_array[i];
|
2010-10-14 05:50:25 +08:00
|
|
|
|
|
|
|
rc = ebitmap_write(e, fp);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|