12b29f3455
Introduce SELinux support for deferred mapping of security contexts in the SID table upon policy reload, and use this support for inode security contexts when the context is not yet valid under the current policy. Only processes with CAP_MAC_ADMIN + mac_admin permission in policy can set undefined security contexts on inodes. Inodes with such undefined contexts are treated as having the unlabeled context until the context becomes valid upon a policy reload that defines the context. Context invalidation upon policy reload also uses this support to save the context information in the SID table and later recover it upon a subsequent policy reload that defines the context again. This support is to enable package managers and similar programs to set down file contexts unknown to the system policy at the time the file is created in order to better support placing loadable policy modules in packages and to support build systems that need to create images of different distro releases with different policies w/o requiring all of the contexts to be defined or legal in the build host policy. With this patch applied, the following sequence is possible, although in practice it is recommended that this permission only be allowed to specific program domains such as the package manager. # rmdir baz # rm bar # touch bar # chcon -t foo_exec_t bar # foo_exec_t is not yet defined chcon: failed to change context of `bar' to `system_u:object_r:foo_exec_t': Invalid argument # mkdir -Z system_u:object_r:foo_exec_t baz mkdir: failed to set default file creation context to `system_u:object_r:foo_exec_t': Invalid argument # cat setundefined.te policy_module(setundefined, 1.0) require { type unconfined_t; type unlabeled_t; } files_type(unlabeled_t) allow unconfined_t self:capability2 mac_admin; # make -f /usr/share/selinux/devel/Makefile setundefined.pp # semodule -i setundefined.pp # chcon -t foo_exec_t bar # foo_exec_t is not yet defined # mkdir -Z system_u:object_r:foo_exec_t baz # ls -Zd bar baz -rw-r--r-- root root system_u:object_r:unlabeled_t bar drwxr-xr-x root root system_u:object_r:unlabeled_t baz # cat foo.te policy_module(foo, 1.0) type foo_exec_t; files_type(foo_exec_t) # make -f /usr/share/selinux/devel/Makefile foo.pp # semodule -i foo.pp # defines foo_exec_t # ls -Zd bar baz -rw-r--r-- root root user_u:object_r:foo_exec_t bar drwxr-xr-x root root system_u:object_r:foo_exec_t baz # semodule -r foo # ls -Zd bar baz -rw-r--r-- root root system_u:object_r:unlabeled_t bar drwxr-xr-x root root system_u:object_r:unlabeled_t baz # semodule -i foo.pp # ls -Zd bar baz -rw-r--r-- root root user_u:object_r:foo_exec_t bar drwxr-xr-x root root system_u:object_r:foo_exec_t baz # semodule -r setundefined foo # chcon -t foo_exec_t bar # no longer defined and not allowed chcon: failed to change context of `bar' to `system_u:object_r:foo_exec_t': Invalid argument # rmdir baz # mkdir -Z system_u:object_r:foo_exec_t baz mkdir: failed to set default file creation context to `system_u:object_r:foo_exec_t': Invalid argument Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
155 lines
3.6 KiB
C
155 lines
3.6 KiB
C
/*
|
|
* A security context is a set of security attributes
|
|
* associated with each subject and object controlled
|
|
* by the security policy. Security contexts are
|
|
* externally represented as variable-length strings
|
|
* that can be interpreted by a user or application
|
|
* with an understanding of the security policy.
|
|
* Internally, the security server uses a simple
|
|
* structure. This structure is private to the
|
|
* security server and can be changed without affecting
|
|
* clients of the security server.
|
|
*
|
|
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
|
*/
|
|
#ifndef _SS_CONTEXT_H_
|
|
#define _SS_CONTEXT_H_
|
|
|
|
#include "ebitmap.h"
|
|
#include "mls_types.h"
|
|
#include "security.h"
|
|
|
|
/*
|
|
* A security context consists of an authenticated user
|
|
* identity, a role, a type and a MLS range.
|
|
*/
|
|
struct context {
|
|
u32 user;
|
|
u32 role;
|
|
u32 type;
|
|
struct mls_range range;
|
|
char *str; /* string representation if context cannot be mapped. */
|
|
u32 len; /* length of string in bytes */
|
|
};
|
|
|
|
static inline void mls_context_init(struct context *c)
|
|
{
|
|
memset(&c->range, 0, sizeof(c->range));
|
|
}
|
|
|
|
static inline int mls_context_cpy(struct context *dst, struct context *src)
|
|
{
|
|
int rc;
|
|
|
|
if (!selinux_mls_enabled)
|
|
return 0;
|
|
|
|
dst->range.level[0].sens = src->range.level[0].sens;
|
|
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
|
|
if (rc)
|
|
goto out;
|
|
|
|
dst->range.level[1].sens = src->range.level[1].sens;
|
|
rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
|
|
if (rc)
|
|
ebitmap_destroy(&dst->range.level[0].cat);
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Sets both levels in the MLS range of 'dst' to the low level of 'src'.
|
|
*/
|
|
static inline int mls_context_cpy_low(struct context *dst, struct context *src)
|
|
{
|
|
int rc;
|
|
|
|
if (!selinux_mls_enabled)
|
|
return 0;
|
|
|
|
dst->range.level[0].sens = src->range.level[0].sens;
|
|
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
|
|
if (rc)
|
|
goto out;
|
|
|
|
dst->range.level[1].sens = src->range.level[0].sens;
|
|
rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[0].cat);
|
|
if (rc)
|
|
ebitmap_destroy(&dst->range.level[0].cat);
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
static inline int mls_context_cmp(struct context *c1, struct context *c2)
|
|
{
|
|
if (!selinux_mls_enabled)
|
|
return 1;
|
|
|
|
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
|
|
ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
|
|
(c1->range.level[1].sens == c2->range.level[1].sens) &&
|
|
ebitmap_cmp(&c1->range.level[1].cat, &c2->range.level[1].cat));
|
|
}
|
|
|
|
static inline void mls_context_destroy(struct context *c)
|
|
{
|
|
if (!selinux_mls_enabled)
|
|
return;
|
|
|
|
ebitmap_destroy(&c->range.level[0].cat);
|
|
ebitmap_destroy(&c->range.level[1].cat);
|
|
mls_context_init(c);
|
|
}
|
|
|
|
static inline void context_init(struct context *c)
|
|
{
|
|
memset(c, 0, sizeof(*c));
|
|
}
|
|
|
|
static inline int context_cpy(struct context *dst, struct context *src)
|
|
{
|
|
int rc;
|
|
|
|
dst->user = src->user;
|
|
dst->role = src->role;
|
|
dst->type = src->type;
|
|
if (src->str) {
|
|
dst->str = kstrdup(src->str, GFP_ATOMIC);
|
|
if (!dst->str)
|
|
return -ENOMEM;
|
|
dst->len = src->len;
|
|
} else {
|
|
dst->str = NULL;
|
|
dst->len = 0;
|
|
}
|
|
rc = mls_context_cpy(dst, src);
|
|
if (rc) {
|
|
kfree(dst->str);
|
|
return rc;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline void context_destroy(struct context *c)
|
|
{
|
|
c->user = c->role = c->type = 0;
|
|
kfree(c->str);
|
|
c->str = NULL;
|
|
c->len = 0;
|
|
mls_context_destroy(c);
|
|
}
|
|
|
|
static inline int context_cmp(struct context *c1, struct context *c2)
|
|
{
|
|
if (c1->len && c2->len)
|
|
return (c1->len == c2->len && !strcmp(c1->str, c2->str));
|
|
if (c1->len || c2->len)
|
|
return 0;
|
|
return ((c1->user == c2->user) &&
|
|
(c1->role == c2->role) &&
|
|
(c1->type == c2->type) &&
|
|
mls_context_cmp(c1, c2));
|
|
}
|
|
|
|
#endif /* _SS_CONTEXT_H_ */
|
|
|