Skip to content

Commit

Permalink
selinux: support deferred mapping of contexts
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: James Morris <[email protected]>
  • Loading branch information
stephensmalley authored and James Morris committed Jul 14, 2008
1 parent bce7f79 commit 12b29f3
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 128 deletions.
20 changes: 16 additions & 4 deletions security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -2495,7 +2495,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
}

if (value && len) {
rc = security_sid_to_context(newsid, &context, &clen);
rc = security_sid_to_context_force(newsid, &context, &clen);
if (rc) {
kfree(namep);
return rc;
Expand Down Expand Up @@ -2669,6 +2669,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
return rc;

rc = security_context_to_sid(value, size, &newsid);
if (rc == -EINVAL) {
if (!capable(CAP_MAC_ADMIN))
return rc;
rc = security_context_to_sid_force(value, size, &newsid);
}
if (rc)
return rc;

Expand Down Expand Up @@ -2703,10 +2708,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}

rc = security_context_to_sid(value, size, &newsid);
rc = security_context_to_sid_force(value, size, &newsid);
if (rc) {
printk(KERN_WARNING "%s: unable to obtain SID for context "
"%s, rc=%d\n", __func__, (char *)value, -rc);
printk(KERN_ERR "SELinux: unable to map context to SID"
"for (%s, %lu), rc=%d\n",
inode->i_sb->s_id, inode->i_ino, -rc);
return;
}

Expand Down Expand Up @@ -5153,6 +5159,12 @@ static int selinux_setprocattr(struct task_struct *p,
size--;
}
error = security_context_to_sid(value, size, &sid);
if (error == -EINVAL && !strcmp(name, "fscreate")) {
if (!capable(CAP_MAC_ADMIN))
return error;
error = security_context_to_sid_force(value, size,
&sid);
}
if (error)
return error;
}
Expand Down
5 changes: 5 additions & 0 deletions security/selinux/include/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,17 @@ int security_change_sid(u32 ssid, u32 tsid,
int security_sid_to_context(u32 sid, char **scontext,
u32 *scontext_len);

int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);

int security_context_to_sid(const char *scontext, u32 scontext_len,
u32 *out_sid);

int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);

int security_context_to_sid_force(const char *scontext, u32 scontext_len,
u32 *sid);

int security_get_user_sids(u32 callsid, char *username,
u32 **sids, u32 *nel);

Expand Down
27 changes: 26 additions & 1 deletion security/selinux/ss/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ struct context {
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)
Expand Down Expand Up @@ -106,20 +108,43 @@ static inline void context_init(struct context *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;
return mls_context_cpy(dst, src);
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) &&
Expand Down
11 changes: 6 additions & 5 deletions security/selinux/ss/mls.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
* Policy read-lock must be held for sidtab lookup.
*
*/
int mls_context_to_sid(char oldc,
int mls_context_to_sid(struct policydb *pol,
char oldc,
char **scontext,
struct context *context,
struct sidtab *s,
Expand Down Expand Up @@ -286,7 +287,7 @@ int mls_context_to_sid(char oldc,
*p++ = 0;

for (l = 0; l < 2; l++) {
levdatum = hashtab_search(policydb.p_levels.table, scontextp);
levdatum = hashtab_search(pol->p_levels.table, scontextp);
if (!levdatum) {
rc = -EINVAL;
goto out;
Expand All @@ -311,7 +312,7 @@ int mls_context_to_sid(char oldc,
*rngptr++ = 0;
}

catdatum = hashtab_search(policydb.p_cats.table,
catdatum = hashtab_search(pol->p_cats.table,
scontextp);
if (!catdatum) {
rc = -EINVAL;
Expand All @@ -327,7 +328,7 @@ int mls_context_to_sid(char oldc,
if (rngptr) {
int i;

rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
rngdatum = hashtab_search(pol->p_cats.table, rngptr);
if (!rngdatum) {
rc = -EINVAL;
goto out;
Expand Down Expand Up @@ -395,7 +396,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
if (!tmpstr) {
rc = -ENOMEM;
} else {
rc = mls_context_to_sid(':', &tmpstr, context,
rc = mls_context_to_sid(&policydb, ':', &tmpstr, context,
NULL, SECSID_NULL);
kfree(freestr);
}
Expand Down
3 changes: 2 additions & 1 deletion security/selinux/ss/mls.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c);
int mls_range_isvalid(struct policydb *p, struct mls_range *r);
int mls_level_isvalid(struct policydb *p, struct mls_level *l);

int mls_context_to_sid(char oldc,
int mls_context_to_sid(struct policydb *p,
char oldc,
char **scontext,
struct context *context,
struct sidtab *s,
Expand Down
Loading

0 comments on commit 12b29f3

Please sign in to comment.