* [PATCH v3] selinux: support deferred mapping of contexts
@ 2008-05-05 15:43 Stephen Smalley
2008-05-05 17:49 ` Stephen Smalley
2008-05-05 23:31 ` James Morris
0 siblings, 2 replies; 25+ messages in thread
From: Stephen Smalley @ 2008-05-05 15:43 UTC (permalink / raw)
To: selinux; +Cc: Eric Paris, James Morris
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.
# 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
# touch bar
# chcon -t foo_exec_t bar # foo_exec_t is not yet defined
# ls -Z bar
-rw-r--r-- root root system_u:object_r:unlabeled_t bar
# 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 -Z bar
-rw-r--r-- root root user_u:object_r:foo_exec_t bar
# semodule -r foo
# ls -Z bar
-rw-r--r-- root root system_u:object_r:unlabeled_t bar
# semodule -i foo.pp
# ls -Z bar
-rw-r--r-- root root user_u:object_r:foo_exec_t bar
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
---
security/selinux/hooks.c | 18 ++-
security/selinux/include/security.h | 2
security/selinux/ss/context.h | 27 ++++
security/selinux/ss/mls.c | 11 +-
security/selinux/ss/mls.h | 3
security/selinux/ss/services.c | 198 +++++++++++++++++++++++++-----------
security/selinux/ss/sidtab.c | 6 -
7 files changed, 194 insertions(+), 71 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 308e2cf..530aa00 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2667,6 +2667,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
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;
@@ -2700,10 +2705,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, 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;
}
@@ -5152,6 +5158,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;
}
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 1904c46..112d4b1 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -99,6 +99,8 @@ int security_context_to_sid(char *scontext, u32 scontext_len,
int security_context_to_sid_default(char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
+int security_context_to_sid_force(char *scontext, u32 scontext_len, u32 *sid);
+
int security_get_user_sids(u32 callsid, char *username,
u32 **sids, u32 *nel);
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index 2eee0da..776d90f 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -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)
@@ -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) &&
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 8b1706b..a6ca058 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -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,
@@ -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;
@@ -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;
@@ -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;
@@ -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);
}
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index ab53663..900fb0e 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -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,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 2daaddb..6724b4f 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -708,36 +708,24 @@ out:
}
-static int security_context_to_sid_core(char *scontext, u32 scontext_len,
- u32 *sid, u32 def_sid, gfp_t gfp_flags)
+static int string_to_context_struct(struct policydb *pol,
+ struct sidtab *sidtabp,
+ char *scontext,
+ u32 scontext_len,
+ struct context *ctx,
+ u32 def_sid,
+ gfp_t gfp_flags)
{
- char *scontext2;
- struct context context;
+ char *scontext2 = NULL;
struct role_datum *role;
struct type_datum *typdatum;
struct user_datum *usrdatum;
char *scontextp, *p, oldc;
int rc = 0;
- if (!ss_initialized) {
- int i;
+ context_init(ctx);
- for (i = 1; i < SECINITSID_NUM; i++) {
- if (!strcmp(initial_sid_to_string[i], scontext)) {
- *sid = i;
- goto out;
- }
- }
- *sid = SECINITSID_KERNEL;
- goto out;
- }
- *sid = SECSID_NULL;
-
- /* Copy the string so that we can modify the copy as we parse it.
- The string should already by null terminated, but we append a
- null suffix to the copy to avoid problems with the existing
- attr package, which doesn't view the null terminator as part
- of the attribute value. */
+ /* Copy the string so that we can modify the copy as we parse it. */
scontext2 = kmalloc(scontext_len+1, gfp_flags);
if (!scontext2) {
rc = -ENOMEM;
@@ -746,11 +734,6 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len,
memcpy(scontext2, scontext, scontext_len);
scontext2[scontext_len] = 0;
- context_init(&context);
- *sid = SECSID_NULL;
-
- POLICY_RDLOCK;
-
/* Parse the security context. */
rc = -EINVAL;
@@ -762,15 +745,15 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len,
p++;
if (*p == 0)
- goto out_unlock;
+ goto out;
*p++ = 0;
- usrdatum = hashtab_search(policydb.p_users.table, scontextp);
+ usrdatum = hashtab_search(pol->p_users.table, scontextp);
if (!usrdatum)
- goto out_unlock;
+ goto out;
- context.user = usrdatum->value;
+ ctx->user = usrdatum->value;
/* Extract role. */
scontextp = p;
@@ -778,14 +761,14 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len,
p++;
if (*p == 0)
- goto out_unlock;
+ goto out;
*p++ = 0;
- role = hashtab_search(policydb.p_roles.table, scontextp);
+ role = hashtab_search(pol->p_roles.table, scontextp);
if (!role)
- goto out_unlock;
- context.role = role->value;
+ goto out;
+ ctx->role = role->value;
/* Extract type. */
scontextp = p;
@@ -794,33 +777,74 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len,
oldc = *p;
*p++ = 0;
- typdatum = hashtab_search(policydb.p_types.table, scontextp);
+ typdatum = hashtab_search(pol->p_types.table, scontextp);
if (!typdatum)
- goto out_unlock;
+ goto out;
- context.type = typdatum->value;
+ ctx->type = typdatum->value;
- rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
+ rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
if (rc)
- goto out_unlock;
+ goto out;
if ((p - scontext2) < scontext_len) {
rc = -EINVAL;
- goto out_unlock;
+ goto out;
}
/* Check the validity of the new context. */
- if (!policydb_context_isvalid(&policydb, &context)) {
+ if (!policydb_context_isvalid(pol, ctx)) {
rc = -EINVAL;
- goto out_unlock;
+ context_destroy(ctx);
+ goto out;
}
- /* Obtain the new sid. */
- rc = sidtab_context_to_sid(&sidtab, &context, sid);
-out_unlock:
- POLICY_RDUNLOCK;
- context_destroy(&context);
+ rc = 0;
+out:
kfree(scontext2);
+ return rc;
+}
+
+static int security_context_to_sid_core(char *scontext, u32 scontext_len,
+ u32 *sid, u32 def_sid, gfp_t gfp_flags,
+ int force)
+{
+ struct context context;
+ int rc = 0;
+
+ if (!ss_initialized) {
+ int i;
+
+ for (i = 1; i < SECINITSID_NUM; i++) {
+ if (!strcmp(initial_sid_to_string[i], scontext)) {
+ *sid = i;
+ goto out;
+ }
+ }
+ *sid = SECINITSID_KERNEL;
+ goto out;
+ }
+ *sid = SECSID_NULL;
+
+ POLICY_RDLOCK;
+ rc = string_to_context_struct(&policydb, &sidtab,
+ scontext, scontext_len,
+ &context, def_sid, gfp_flags);
+ if (rc == -EINVAL && force) {
+ context.str = kmalloc(scontext_len+1, gfp_flags);
+ if (!context.str) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memcpy(context.str, scontext, scontext_len);
+ context.str[scontext_len] = 0;
+ context.len = scontext_len;
+ } else if (rc)
+ goto out;
+ rc = sidtab_context_to_sid(&sidtab, &context, sid);
+ if (rc)
+ context_destroy(&context);
out:
+ POLICY_RDUNLOCK;
return rc;
}
@@ -838,7 +862,7 @@ out:
int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, SECSID_NULL, GFP_KERNEL);
+ sid, SECSID_NULL, GFP_KERNEL, 0);
}
/**
@@ -855,6 +879,7 @@ int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
* The default SID is passed to the MLS layer to be used to allow
* kernel labeling of the MLS field if the MLS field is not present
* (for upgrading to MLS without full relabel).
+ * Implicitly forces adding of the context even if it cannot be mapped yet.
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
@@ -862,7 +887,13 @@ int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid,
u32 def_sid, gfp_t gfp_flags)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, def_sid, gfp_flags);
+ sid, def_sid, gfp_flags, 1);
+}
+
+int security_context_to_sid_force(char *scontext, u32 scontext_len, u32 *sid)
+{
+ return security_context_to_sid_core(scontext, scontext_len,
+ sid, SECSID_NULL, GFP_KERNEL, 1);
}
static int compute_sid_handle_invalid_context(
@@ -1246,9 +1277,12 @@ static inline int convert_context_handle_invalid_context(struct context *context
char *s;
u32 len;
- context_struct_to_string(context, &s, &len);
- printk(KERN_ERR "SELinux: context %s is invalid\n", s);
- kfree(s);
+ if (!context_struct_to_string(context, &s, &len)) {
+ printk(KERN_WARNING
+ "SELinux: Context %s would be invalid if enforcing\n",
+ s);
+ kfree(s);
+ }
}
return rc;
}
@@ -1280,6 +1314,32 @@ static int convert_context(u32 key,
args = p;
+ if (c->str) {
+ struct context ctx;
+ rc = string_to_context_struct(args->newp, NULL, c->str,
+ c->len, &ctx, SECSID_NULL,
+ GFP_KERNEL);
+ if (!rc) {
+ printk(KERN_INFO
+ "SELinux: Context %s became valid (mapped).\n",
+ c->str);
+ /* Replace string with mapped representation. */
+ kfree(c->str);
+ memcpy(c, &ctx, sizeof(*c));
+ goto out;
+ } else if (rc == -EINVAL) {
+ /* Retain string representation for later mapping. */
+ rc = 0;
+ goto out;
+ } else {
+ /* Other error condition, e.g. ENOMEM. */
+ printk(KERN_ERR
+ "SELinux: Unable to map context %s, rc = %d.\n",
+ c->str, -rc);
+ goto out;
+ }
+ }
+
rc = context_cpy(&oldc, c);
if (rc)
goto out;
@@ -1319,13 +1379,21 @@ static int convert_context(u32 key,
}
context_destroy(&oldc);
+ rc = 0;
out:
return rc;
bad:
- context_struct_to_string(&oldc, &s, &len);
+ /* Map old representation to string and save it. */
+ if (context_struct_to_string(&oldc, &s, &len))
+ return -ENOMEM;
context_destroy(&oldc);
- printk(KERN_ERR "SELinux: invalidating context %s\n", s);
- kfree(s);
+ context_destroy(c);
+ c->str = s;
+ c->len = len;
+ printk(KERN_INFO
+ "SELinux: Context %s became invalid (unmapped).\n",
+ c->str);
+ rc = 0;
goto out;
}
@@ -1406,7 +1474,11 @@ int security_load_policy(void *data, size_t len)
return -EINVAL;
}
- sidtab_init(&newsidtab);
+ if (sidtab_init(&newsidtab)) {
+ LOAD_UNLOCK;
+ policydb_destroy(&newpolicydb);
+ return -ENOMEM;
+ }
/* Verify that the kernel defined classes are correct. */
if (validate_classes(&newpolicydb)) {
@@ -1429,11 +1501,15 @@ int security_load_policy(void *data, size_t len)
goto err;
}
- /* Convert the internal representations of contexts
- in the new SID table and remove invalid SIDs. */
+ /*
+ * Convert the internal representations of contexts
+ * in the new SID table.
+ */
args.oldp = &policydb;
args.newp = &newpolicydb;
- sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+ rc = sidtab_map(&newsidtab, convert_context, &args);
+ if (rc)
+ goto err;
/* Save the old policydb and SID table to free later. */
memcpy(&oldpolicydb, &policydb, sizeof policydb);
@@ -1673,6 +1749,8 @@ int security_get_user_sids(u32 fromsid,
POLICY_RDLOCK;
+ context_init(&usercon);
+
fromcon = sidtab_search(&sidtab, fromsid);
if (!fromcon) {
rc = -EINVAL;
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 4a516ff..7f4c0d0 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -99,7 +99,7 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
while (cur != NULL && sid > cur->sid)
cur = cur->next;
- if (cur == NULL || sid != cur->sid) {
+ if (cur == NULL || sid != cur->sid || cur->context.len) {
/* Remap invalid SIDs to the unlabeled SID. */
sid = SECINITSID_UNLABELED;
hvalue = SIDTAB_HASH(sid);
@@ -215,6 +215,10 @@ int sidtab_context_to_sid(struct sidtab *s,
goto unlock_out;
}
sid = s->next_sid++;
+ if (context->len)
+ printk(KERN_INFO
+ "SELinux: Context %s is not valid (left unmapped).\n",
+ context->str);
ret = sidtab_insert(s, sid, context);
if (ret)
s->next_sid--;
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v3] selinux: support deferred mapping of contexts
2008-05-05 15:43 [PATCH v3] selinux: support deferred mapping of contexts Stephen Smalley
@ 2008-05-05 17:49 ` Stephen Smalley
2008-05-05 23:31 ` James Morris
1 sibling, 0 replies; 25+ messages in thread
From: Stephen Smalley @ 2008-05-05 17:49 UTC (permalink / raw)
To: selinux; +Cc: Eric Paris, James Morris
On Mon, 2008-05-05 at 11:43 -0400, Stephen Smalley wrote:
> 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.
BTW, I assume that this patch will bake in -mm for a while and only go
in for 2.6.27, since 2.6.26 merge window is now closed and this is
definitely not a bug fix or minor cleanup.
> 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.
>
> # 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
> # touch bar
> # chcon -t foo_exec_t bar # foo_exec_t is not yet defined
> # ls -Z bar
> -rw-r--r-- root root system_u:object_r:unlabeled_t bar
> # 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 -Z bar
> -rw-r--r-- root root user_u:object_r:foo_exec_t bar
> # semodule -r foo
> # ls -Z bar
> -rw-r--r-- root root system_u:object_r:unlabeled_t bar
> # semodule -i foo.pp
> # ls -Z bar
> -rw-r--r-- root root user_u:object_r:foo_exec_t bar
>
> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
>
> ---
>
> security/selinux/hooks.c | 18 ++-
> security/selinux/include/security.h | 2
> security/selinux/ss/context.h | 27 ++++
> security/selinux/ss/mls.c | 11 +-
> security/selinux/ss/mls.h | 3
> security/selinux/ss/services.c | 198 +++++++++++++++++++++++++-----------
> security/selinux/ss/sidtab.c | 6 -
> 7 files changed, 194 insertions(+), 71 deletions(-)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 308e2cf..530aa00 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2667,6 +2667,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
> 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;
>
> @@ -2700,10 +2705,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, 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;
> }
>
> @@ -5152,6 +5158,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;
> }
> diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
> index 1904c46..112d4b1 100644
> --- a/security/selinux/include/security.h
> +++ b/security/selinux/include/security.h
> @@ -99,6 +99,8 @@ int security_context_to_sid(char *scontext, u32 scontext_len,
> int security_context_to_sid_default(char *scontext, u32 scontext_len,
> u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
>
> +int security_context_to_sid_force(char *scontext, u32 scontext_len, u32 *sid);
> +
> int security_get_user_sids(u32 callsid, char *username,
> u32 **sids, u32 *nel);
>
> diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
> index 2eee0da..776d90f 100644
> --- a/security/selinux/ss/context.h
> +++ b/security/selinux/ss/context.h
> @@ -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)
> @@ -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) &&
> diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
> index 8b1706b..a6ca058 100644
> --- a/security/selinux/ss/mls.c
> +++ b/security/selinux/ss/mls.c
> @@ -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,
> @@ -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;
> @@ -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;
> @@ -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;
> @@ -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);
> }
> diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
> index ab53663..900fb0e 100644
> --- a/security/selinux/ss/mls.h
> +++ b/security/selinux/ss/mls.h
> @@ -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,
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index 2daaddb..6724b4f 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -708,36 +708,24 @@ out:
>
> }
>
> -static int security_context_to_sid_core(char *scontext, u32 scontext_len,
> - u32 *sid, u32 def_sid, gfp_t gfp_flags)
> +static int string_to_context_struct(struct policydb *pol,
> + struct sidtab *sidtabp,
> + char *scontext,
> + u32 scontext_len,
> + struct context *ctx,
> + u32 def_sid,
> + gfp_t gfp_flags)
> {
> - char *scontext2;
> - struct context context;
> + char *scontext2 = NULL;
> struct role_datum *role;
> struct type_datum *typdatum;
> struct user_datum *usrdatum;
> char *scontextp, *p, oldc;
> int rc = 0;
>
> - if (!ss_initialized) {
> - int i;
> + context_init(ctx);
>
> - for (i = 1; i < SECINITSID_NUM; i++) {
> - if (!strcmp(initial_sid_to_string[i], scontext)) {
> - *sid = i;
> - goto out;
> - }
> - }
> - *sid = SECINITSID_KERNEL;
> - goto out;
> - }
> - *sid = SECSID_NULL;
> -
> - /* Copy the string so that we can modify the copy as we parse it.
> - The string should already by null terminated, but we append a
> - null suffix to the copy to avoid problems with the existing
> - attr package, which doesn't view the null terminator as part
> - of the attribute value. */
> + /* Copy the string so that we can modify the copy as we parse it. */
> scontext2 = kmalloc(scontext_len+1, gfp_flags);
> if (!scontext2) {
> rc = -ENOMEM;
> @@ -746,11 +734,6 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len,
> memcpy(scontext2, scontext, scontext_len);
> scontext2[scontext_len] = 0;
>
> - context_init(&context);
> - *sid = SECSID_NULL;
> -
> - POLICY_RDLOCK;
> -
> /* Parse the security context. */
>
> rc = -EINVAL;
> @@ -762,15 +745,15 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len,
> p++;
>
> if (*p == 0)
> - goto out_unlock;
> + goto out;
>
> *p++ = 0;
>
> - usrdatum = hashtab_search(policydb.p_users.table, scontextp);
> + usrdatum = hashtab_search(pol->p_users.table, scontextp);
> if (!usrdatum)
> - goto out_unlock;
> + goto out;
>
> - context.user = usrdatum->value;
> + ctx->user = usrdatum->value;
>
> /* Extract role. */
> scontextp = p;
> @@ -778,14 +761,14 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len,
> p++;
>
> if (*p == 0)
> - goto out_unlock;
> + goto out;
>
> *p++ = 0;
>
> - role = hashtab_search(policydb.p_roles.table, scontextp);
> + role = hashtab_search(pol->p_roles.table, scontextp);
> if (!role)
> - goto out_unlock;
> - context.role = role->value;
> + goto out;
> + ctx->role = role->value;
>
> /* Extract type. */
> scontextp = p;
> @@ -794,33 +777,74 @@ static int security_context_to_sid_core(char *scontext, u32 scontext_len,
> oldc = *p;
> *p++ = 0;
>
> - typdatum = hashtab_search(policydb.p_types.table, scontextp);
> + typdatum = hashtab_search(pol->p_types.table, scontextp);
> if (!typdatum)
> - goto out_unlock;
> + goto out;
>
> - context.type = typdatum->value;
> + ctx->type = typdatum->value;
>
> - rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
> + rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
> if (rc)
> - goto out_unlock;
> + goto out;
>
> if ((p - scontext2) < scontext_len) {
> rc = -EINVAL;
> - goto out_unlock;
> + goto out;
> }
>
> /* Check the validity of the new context. */
> - if (!policydb_context_isvalid(&policydb, &context)) {
> + if (!policydb_context_isvalid(pol, ctx)) {
> rc = -EINVAL;
> - goto out_unlock;
> + context_destroy(ctx);
> + goto out;
> }
> - /* Obtain the new sid. */
> - rc = sidtab_context_to_sid(&sidtab, &context, sid);
> -out_unlock:
> - POLICY_RDUNLOCK;
> - context_destroy(&context);
> + rc = 0;
> +out:
> kfree(scontext2);
> + return rc;
> +}
> +
> +static int security_context_to_sid_core(char *scontext, u32 scontext_len,
> + u32 *sid, u32 def_sid, gfp_t gfp_flags,
> + int force)
> +{
> + struct context context;
> + int rc = 0;
> +
> + if (!ss_initialized) {
> + int i;
> +
> + for (i = 1; i < SECINITSID_NUM; i++) {
> + if (!strcmp(initial_sid_to_string[i], scontext)) {
> + *sid = i;
> + goto out;
> + }
> + }
> + *sid = SECINITSID_KERNEL;
> + goto out;
> + }
> + *sid = SECSID_NULL;
> +
> + POLICY_RDLOCK;
> + rc = string_to_context_struct(&policydb, &sidtab,
> + scontext, scontext_len,
> + &context, def_sid, gfp_flags);
> + if (rc == -EINVAL && force) {
> + context.str = kmalloc(scontext_len+1, gfp_flags);
> + if (!context.str) {
> + rc = -ENOMEM;
> + goto out;
> + }
> + memcpy(context.str, scontext, scontext_len);
> + context.str[scontext_len] = 0;
> + context.len = scontext_len;
> + } else if (rc)
> + goto out;
> + rc = sidtab_context_to_sid(&sidtab, &context, sid);
> + if (rc)
> + context_destroy(&context);
> out:
> + POLICY_RDUNLOCK;
> return rc;
> }
>
> @@ -838,7 +862,7 @@ out:
> int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
> {
> return security_context_to_sid_core(scontext, scontext_len,
> - sid, SECSID_NULL, GFP_KERNEL);
> + sid, SECSID_NULL, GFP_KERNEL, 0);
> }
>
> /**
> @@ -855,6 +879,7 @@ int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
> * The default SID is passed to the MLS layer to be used to allow
> * kernel labeling of the MLS field if the MLS field is not present
> * (for upgrading to MLS without full relabel).
> + * Implicitly forces adding of the context even if it cannot be mapped yet.
> * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
> * memory is available, or 0 on success.
> */
> @@ -862,7 +887,13 @@ int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid,
> u32 def_sid, gfp_t gfp_flags)
> {
> return security_context_to_sid_core(scontext, scontext_len,
> - sid, def_sid, gfp_flags);
> + sid, def_sid, gfp_flags, 1);
> +}
> +
> +int security_context_to_sid_force(char *scontext, u32 scontext_len, u32 *sid)
> +{
> + return security_context_to_sid_core(scontext, scontext_len,
> + sid, SECSID_NULL, GFP_KERNEL, 1);
> }
>
> static int compute_sid_handle_invalid_context(
> @@ -1246,9 +1277,12 @@ static inline int convert_context_handle_invalid_context(struct context *context
> char *s;
> u32 len;
>
> - context_struct_to_string(context, &s, &len);
> - printk(KERN_ERR "SELinux: context %s is invalid\n", s);
> - kfree(s);
> + if (!context_struct_to_string(context, &s, &len)) {
> + printk(KERN_WARNING
> + "SELinux: Context %s would be invalid if enforcing\n",
> + s);
> + kfree(s);
> + }
> }
> return rc;
> }
> @@ -1280,6 +1314,32 @@ static int convert_context(u32 key,
>
> args = p;
>
> + if (c->str) {
> + struct context ctx;
> + rc = string_to_context_struct(args->newp, NULL, c->str,
> + c->len, &ctx, SECSID_NULL,
> + GFP_KERNEL);
> + if (!rc) {
> + printk(KERN_INFO
> + "SELinux: Context %s became valid (mapped).\n",
> + c->str);
> + /* Replace string with mapped representation. */
> + kfree(c->str);
> + memcpy(c, &ctx, sizeof(*c));
> + goto out;
> + } else if (rc == -EINVAL) {
> + /* Retain string representation for later mapping. */
> + rc = 0;
> + goto out;
> + } else {
> + /* Other error condition, e.g. ENOMEM. */
> + printk(KERN_ERR
> + "SELinux: Unable to map context %s, rc = %d.\n",
> + c->str, -rc);
> + goto out;
> + }
> + }
> +
> rc = context_cpy(&oldc, c);
> if (rc)
> goto out;
> @@ -1319,13 +1379,21 @@ static int convert_context(u32 key,
> }
>
> context_destroy(&oldc);
> + rc = 0;
> out:
> return rc;
> bad:
> - context_struct_to_string(&oldc, &s, &len);
> + /* Map old representation to string and save it. */
> + if (context_struct_to_string(&oldc, &s, &len))
> + return -ENOMEM;
> context_destroy(&oldc);
> - printk(KERN_ERR "SELinux: invalidating context %s\n", s);
> - kfree(s);
> + context_destroy(c);
> + c->str = s;
> + c->len = len;
> + printk(KERN_INFO
> + "SELinux: Context %s became invalid (unmapped).\n",
> + c->str);
> + rc = 0;
> goto out;
> }
>
> @@ -1406,7 +1474,11 @@ int security_load_policy(void *data, size_t len)
> return -EINVAL;
> }
>
> - sidtab_init(&newsidtab);
> + if (sidtab_init(&newsidtab)) {
> + LOAD_UNLOCK;
> + policydb_destroy(&newpolicydb);
> + return -ENOMEM;
> + }
>
> /* Verify that the kernel defined classes are correct. */
> if (validate_classes(&newpolicydb)) {
> @@ -1429,11 +1501,15 @@ int security_load_policy(void *data, size_t len)
> goto err;
> }
>
> - /* Convert the internal representations of contexts
> - in the new SID table and remove invalid SIDs. */
> + /*
> + * Convert the internal representations of contexts
> + * in the new SID table.
> + */
> args.oldp = &policydb;
> args.newp = &newpolicydb;
> - sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
> + rc = sidtab_map(&newsidtab, convert_context, &args);
> + if (rc)
> + goto err;
>
> /* Save the old policydb and SID table to free later. */
> memcpy(&oldpolicydb, &policydb, sizeof policydb);
> @@ -1673,6 +1749,8 @@ int security_get_user_sids(u32 fromsid,
>
> POLICY_RDLOCK;
>
> + context_init(&usercon);
> +
> fromcon = sidtab_search(&sidtab, fromsid);
> if (!fromcon) {
> rc = -EINVAL;
> diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
> index 4a516ff..7f4c0d0 100644
> --- a/security/selinux/ss/sidtab.c
> +++ b/security/selinux/ss/sidtab.c
> @@ -99,7 +99,7 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
> while (cur != NULL && sid > cur->sid)
> cur = cur->next;
>
> - if (cur == NULL || sid != cur->sid) {
> + if (cur == NULL || sid != cur->sid || cur->context.len) {
> /* Remap invalid SIDs to the unlabeled SID. */
> sid = SECINITSID_UNLABELED;
> hvalue = SIDTAB_HASH(sid);
> @@ -215,6 +215,10 @@ int sidtab_context_to_sid(struct sidtab *s,
> goto unlock_out;
> }
> sid = s->next_sid++;
> + if (context->len)
> + printk(KERN_INFO
> + "SELinux: Context %s is not valid (left unmapped).\n",
> + context->str);
> ret = sidtab_insert(s, sid, context);
> if (ret)
> s->next_sid--;
>
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v3] selinux: support deferred mapping of contexts
2008-05-05 15:43 [PATCH v3] selinux: support deferred mapping of contexts Stephen Smalley
2008-05-05 17:49 ` Stephen Smalley
@ 2008-05-05 23:31 ` James Morris
2008-05-06 15:40 ` [PATCH v4] " Stephen Smalley
1 sibling, 1 reply; 25+ messages in thread
From: James Morris @ 2008-05-05 23:31 UTC (permalink / raw)
To: Stephen Smalley; +Cc: selinux, Eric Paris
On Mon, 5 May 2008, Stephen Smalley wrote:
> Introduce SELinux support for deferred mapping of security contexts in
> the SID table upon policy reload, and use this support for inode
This does not apply to my tree.
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v4] selinux: support deferred mapping of contexts
2008-05-05 23:31 ` James Morris
@ 2008-05-06 15:40 ` Stephen Smalley
2008-05-06 20:17 ` Stephen Smalley
0 siblings, 1 reply; 25+ messages in thread
From: Stephen Smalley @ 2008-05-06 15:40 UTC (permalink / raw)
To: James Morris; +Cc: selinux, Eric Paris
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.
# 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
# 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
# ls -Z bar
-rw-r--r-- root root system_u:object_r:unlabeled_t bar
# 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 -Z bar
-rw-r--r-- root root user_u:object_r:foo_exec_t bar
# semodule -r foo
# ls -Z bar
-rw-r--r-- root root system_u:object_r:unlabeled_t bar
# semodule -i foo.pp
# ls -Z bar
-rw-r--r-- root root user_u:object_r:foo_exec_t bar
# 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
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
---
I would like this to bake in -mm for a while, but ideally also get testing
in Fedora devel for F10 prior to mainline merge.
security/selinux/hooks.c | 18 ++-
security/selinux/include/security.h | 3
security/selinux/ss/context.h | 27 ++++
security/selinux/ss/mls.c | 11 +
security/selinux/ss/mls.h | 3
security/selinux/ss/services.c | 199 +++++++++++++++++++++++++-----------
security/selinux/ss/sidtab.c | 6 -
7 files changed, 196 insertions(+), 71 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1c864c0..1fe4550 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -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;
@@ -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;
}
@@ -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;
}
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ad30ac4..ad204f8 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -99,6 +99,9 @@ int security_context_to_sid(const char *scontext, u32 scontext_len,
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);
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index b9a6f7f..658c2bd 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -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)
@@ -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) &&
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 8b1706b..a6ca058 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -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,
@@ -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;
@@ -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;
@@ -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;
@@ -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);
}
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 0fdf625..1276715 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -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,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index dcc2e1c..9d41484 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -708,36 +708,24 @@ out:
}
-static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
- u32 *sid, u32 def_sid, gfp_t gfp_flags)
+static int string_to_context_struct(struct policydb *pol,
+ struct sidtab *sidtabp,
+ const char *scontext,
+ u32 scontext_len,
+ struct context *ctx,
+ u32 def_sid,
+ gfp_t gfp_flags)
{
- char *scontext2;
- struct context context;
+ char *scontext2 = NULL;
struct role_datum *role;
struct type_datum *typdatum;
struct user_datum *usrdatum;
char *scontextp, *p, oldc;
int rc = 0;
- if (!ss_initialized) {
- int i;
+ context_init(ctx);
- for (i = 1; i < SECINITSID_NUM; i++) {
- if (!strcmp(initial_sid_to_string[i], scontext)) {
- *sid = i;
- goto out;
- }
- }
- *sid = SECINITSID_KERNEL;
- goto out;
- }
- *sid = SECSID_NULL;
-
- /* Copy the string so that we can modify the copy as we parse it.
- The string should already by null terminated, but we append a
- null suffix to the copy to avoid problems with the existing
- attr package, which doesn't view the null terminator as part
- of the attribute value. */
+ /* Copy the string so that we can modify the copy as we parse it. */
scontext2 = kmalloc(scontext_len+1, gfp_flags);
if (!scontext2) {
rc = -ENOMEM;
@@ -746,11 +734,6 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
memcpy(scontext2, scontext, scontext_len);
scontext2[scontext_len] = 0;
- context_init(&context);
- *sid = SECSID_NULL;
-
- POLICY_RDLOCK;
-
/* Parse the security context. */
rc = -EINVAL;
@@ -762,15 +745,15 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
p++;
if (*p == 0)
- goto out_unlock;
+ goto out;
*p++ = 0;
- usrdatum = hashtab_search(policydb.p_users.table, scontextp);
+ usrdatum = hashtab_search(pol->p_users.table, scontextp);
if (!usrdatum)
- goto out_unlock;
+ goto out;
- context.user = usrdatum->value;
+ ctx->user = usrdatum->value;
/* Extract role. */
scontextp = p;
@@ -778,14 +761,14 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
p++;
if (*p == 0)
- goto out_unlock;
+ goto out;
*p++ = 0;
- role = hashtab_search(policydb.p_roles.table, scontextp);
+ role = hashtab_search(pol->p_roles.table, scontextp);
if (!role)
- goto out_unlock;
- context.role = role->value;
+ goto out;
+ ctx->role = role->value;
/* Extract type. */
scontextp = p;
@@ -794,33 +777,74 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
oldc = *p;
*p++ = 0;
- typdatum = hashtab_search(policydb.p_types.table, scontextp);
+ typdatum = hashtab_search(pol->p_types.table, scontextp);
if (!typdatum)
- goto out_unlock;
+ goto out;
- context.type = typdatum->value;
+ ctx->type = typdatum->value;
- rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
+ rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
if (rc)
- goto out_unlock;
+ goto out;
if ((p - scontext2) < scontext_len) {
rc = -EINVAL;
- goto out_unlock;
+ goto out;
}
/* Check the validity of the new context. */
- if (!policydb_context_isvalid(&policydb, &context)) {
+ if (!policydb_context_isvalid(pol, ctx)) {
rc = -EINVAL;
- goto out_unlock;
+ context_destroy(ctx);
+ goto out;
}
- /* Obtain the new sid. */
- rc = sidtab_context_to_sid(&sidtab, &context, sid);
-out_unlock:
- POLICY_RDUNLOCK;
- context_destroy(&context);
+ rc = 0;
+out:
kfree(scontext2);
+ return rc;
+}
+
+static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
+ u32 *sid, u32 def_sid, gfp_t gfp_flags,
+ int force)
+{
+ struct context context;
+ int rc = 0;
+
+ if (!ss_initialized) {
+ int i;
+
+ for (i = 1; i < SECINITSID_NUM; i++) {
+ if (!strcmp(initial_sid_to_string[i], scontext)) {
+ *sid = i;
+ goto out;
+ }
+ }
+ *sid = SECINITSID_KERNEL;
+ goto out;
+ }
+ *sid = SECSID_NULL;
+
+ POLICY_RDLOCK;
+ rc = string_to_context_struct(&policydb, &sidtab,
+ scontext, scontext_len,
+ &context, def_sid, gfp_flags);
+ if (rc == -EINVAL && force) {
+ context.str = kmalloc(scontext_len+1, gfp_flags);
+ if (!context.str) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memcpy(context.str, scontext, scontext_len);
+ context.str[scontext_len] = 0;
+ context.len = scontext_len;
+ } else if (rc)
+ goto out;
+ rc = sidtab_context_to_sid(&sidtab, &context, sid);
+ if (rc)
+ context_destroy(&context);
out:
+ POLICY_RDUNLOCK;
return rc;
}
@@ -838,7 +862,7 @@ out:
int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, SECSID_NULL, GFP_KERNEL);
+ sid, SECSID_NULL, GFP_KERNEL, 0);
}
/**
@@ -855,6 +879,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
* The default SID is passed to the MLS layer to be used to allow
* kernel labeling of the MLS field if the MLS field is not present
* (for upgrading to MLS without full relabel).
+ * Implicitly forces adding of the context even if it cannot be mapped yet.
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
@@ -862,7 +887,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, def_sid, gfp_flags);
+ sid, def_sid, gfp_flags, 1);
+}
+
+int security_context_to_sid_force(const char *scontext, u32 scontext_len,
+ u32 *sid)
+{
+ return security_context_to_sid_core(scontext, scontext_len,
+ sid, SECSID_NULL, GFP_KERNEL, 1);
}
static int compute_sid_handle_invalid_context(
@@ -1246,9 +1278,12 @@ static inline int convert_context_handle_invalid_context(struct context *context
char *s;
u32 len;
- context_struct_to_string(context, &s, &len);
- printk(KERN_ERR "SELinux: context %s is invalid\n", s);
- kfree(s);
+ if (!context_struct_to_string(context, &s, &len)) {
+ printk(KERN_WARNING
+ "SELinux: Context %s would be invalid if enforcing\n",
+ s);
+ kfree(s);
+ }
}
return rc;
}
@@ -1280,6 +1315,32 @@ static int convert_context(u32 key,
args = p;
+ if (c->str) {
+ struct context ctx;
+ rc = string_to_context_struct(args->newp, NULL, c->str,
+ c->len, &ctx, SECSID_NULL,
+ GFP_KERNEL);
+ if (!rc) {
+ printk(KERN_INFO
+ "SELinux: Context %s became valid (mapped).\n",
+ c->str);
+ /* Replace string with mapped representation. */
+ kfree(c->str);
+ memcpy(c, &ctx, sizeof(*c));
+ goto out;
+ } else if (rc == -EINVAL) {
+ /* Retain string representation for later mapping. */
+ rc = 0;
+ goto out;
+ } else {
+ /* Other error condition, e.g. ENOMEM. */
+ printk(KERN_ERR
+ "SELinux: Unable to map context %s, rc = %d.\n",
+ c->str, -rc);
+ goto out;
+ }
+ }
+
rc = context_cpy(&oldc, c);
if (rc)
goto out;
@@ -1319,13 +1380,21 @@ static int convert_context(u32 key,
}
context_destroy(&oldc);
+ rc = 0;
out:
return rc;
bad:
- context_struct_to_string(&oldc, &s, &len);
+ /* Map old representation to string and save it. */
+ if (context_struct_to_string(&oldc, &s, &len))
+ return -ENOMEM;
context_destroy(&oldc);
- printk(KERN_ERR "SELinux: invalidating context %s\n", s);
- kfree(s);
+ context_destroy(c);
+ c->str = s;
+ c->len = len;
+ printk(KERN_INFO
+ "SELinux: Context %s became invalid (unmapped).\n",
+ c->str);
+ rc = 0;
goto out;
}
@@ -1406,7 +1475,11 @@ int security_load_policy(void *data, size_t len)
return -EINVAL;
}
- sidtab_init(&newsidtab);
+ if (sidtab_init(&newsidtab)) {
+ LOAD_UNLOCK;
+ policydb_destroy(&newpolicydb);
+ return -ENOMEM;
+ }
/* Verify that the kernel defined classes are correct. */
if (validate_classes(&newpolicydb)) {
@@ -1429,11 +1502,15 @@ int security_load_policy(void *data, size_t len)
goto err;
}
- /* Convert the internal representations of contexts
- in the new SID table and remove invalid SIDs. */
+ /*
+ * Convert the internal representations of contexts
+ * in the new SID table.
+ */
args.oldp = &policydb;
args.newp = &newpolicydb;
- sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+ rc = sidtab_map(&newsidtab, convert_context, &args);
+ if (rc)
+ goto err;
/* Save the old policydb and SID table to free later. */
memcpy(&oldpolicydb, &policydb, sizeof policydb);
@@ -1673,6 +1750,8 @@ int security_get_user_sids(u32 fromsid,
POLICY_RDLOCK;
+ context_init(&usercon);
+
fromcon = sidtab_search(&sidtab, fromsid);
if (!fromcon) {
rc = -EINVAL;
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 4a516ff..7f4c0d0 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -99,7 +99,7 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
while (cur != NULL && sid > cur->sid)
cur = cur->next;
- if (cur == NULL || sid != cur->sid) {
+ if (cur == NULL || sid != cur->sid || cur->context.len) {
/* Remap invalid SIDs to the unlabeled SID. */
sid = SECINITSID_UNLABELED;
hvalue = SIDTAB_HASH(sid);
@@ -215,6 +215,10 @@ int sidtab_context_to_sid(struct sidtab *s,
goto unlock_out;
}
sid = s->next_sid++;
+ if (context->len)
+ printk(KERN_INFO
+ "SELinux: Context %s is not valid (left unmapped).\n",
+ context->str);
ret = sidtab_insert(s, sid, context);
if (ret)
s->next_sid--;
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-06 15:40 ` [PATCH v4] " Stephen Smalley
@ 2008-05-06 20:17 ` Stephen Smalley
2008-05-06 22:31 ` James Morris
0 siblings, 1 reply; 25+ messages in thread
From: Stephen Smalley @ 2008-05-06 20:17 UTC (permalink / raw)
To: James Morris; +Cc: selinux, Eric Paris, Daniel J Walsh
On Tue, 2008-05-06 at 11:40 -0400, Stephen Smalley wrote:
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 1c864c0..1fe4550 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -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;
> }
I realized that this part of the patch won't work as advertised, at
least not presently.
The corresponding logic in the setxattr hooks will work, and is what I
exercised in my example sequence. And I believe that rpm does
setfilecon() the files after creation rather than using setfscreatecon()
followed by creat, so it should work for rpm's purposes.
The problem with this support in the fscreate case is that we later turn
the SID back into a context in selinux_inode_init_security() for setting
the xattr for the new file in the same transaction as the create, and as
the context will still be undefined by policy, we will get back the
unlabeled context instead and that will be stored on disk.
So, the question is should we just drop this hunk of the patch and only
support this functionality for setxattr, or do we need
selinux_inode_init_security() to recover the original context string
(which is available in the SID table, just not returned by
security_sid_to_context when it isn't defined by policy) and use that
for the on-disk xattr value?
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-06 20:17 ` Stephen Smalley
@ 2008-05-06 22:31 ` James Morris
2008-05-07 12:45 ` Stephen Smalley
0 siblings, 1 reply; 25+ messages in thread
From: James Morris @ 2008-05-06 22:31 UTC (permalink / raw)
To: Stephen Smalley; +Cc: selinux, Eric Paris, Daniel J Walsh
On Tue, 6 May 2008, Stephen Smalley wrote:
> So, the question is should we just drop this hunk of the patch and only
> support this functionality for setxattr, or do we need
> selinux_inode_init_security() to recover the original context string
> (which is available in the SID table, just not returned by
> security_sid_to_context when it isn't defined by policy) and use that
> for the on-disk xattr value?
I think we need to use the "alternative" context if it exists, so yes.
- James
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-06 22:31 ` James Morris
@ 2008-05-07 12:45 ` Stephen Smalley
2008-05-07 13:45 ` James Morris
2008-05-07 15:17 ` [PATCH v4] " Eric Paris
0 siblings, 2 replies; 25+ messages in thread
From: Stephen Smalley @ 2008-05-07 12:45 UTC (permalink / raw)
To: James Morris; +Cc: selinux, Eric Paris, Daniel J Walsh
On Wed, 2008-05-07 at 08:31 +1000, James Morris wrote:
> On Tue, 6 May 2008, Stephen Smalley wrote:
>
> > So, the question is should we just drop this hunk of the patch and only
> > support this functionality for setxattr, or do we need
> > selinux_inode_init_security() to recover the original context string
> > (which is available in the SID table, just not returned by
> > security_sid_to_context when it isn't defined by policy) and use that
> > for the on-disk xattr value?
>
> I think we need to use the "alternative" context if it exists, so yes.
I assume this means that you want to retain the fscreate support,
introduce a variant interface to security_sid_to_context() that will
return the original context string rather than the unlabeled context for
these undefined contexts, and use that interface from
selinux_inode_init_security().
So the next question is whether there are any other cases where we want
to use this variant interface. For example, if
selinux_inode_getsecurity() were to use this variant interface, then we
would report the original context string to userspace upon getxattr()
rather than the unlabeled context, and thus in my example sequence, the
ls -Z would always show the system_u:object_r:foo_exec_t label on the
bar file regardless of whether it was defined in the policy.
I assume we do NOT want to use this variant interface when getting
contexts to display in audit messages, as we want the audit messages to
correspond to the actual denial and to yield proper policy if turned
into an allow rule.
Likewise, are there any other cases where we want to use the reverse
interface (security_context_to_sid_force) beyond just setxattr and
fscreate to permit userspace to set undefined contexts on anything else?
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 12:45 ` Stephen Smalley
@ 2008-05-07 13:45 ` James Morris
2008-05-07 15:12 ` Stephen Smalley
2008-05-07 15:17 ` [PATCH v4] " Eric Paris
1 sibling, 1 reply; 25+ messages in thread
From: James Morris @ 2008-05-07 13:45 UTC (permalink / raw)
To: Stephen Smalley; +Cc: selinux, Eric Paris, Daniel J Walsh
On Wed, 7 May 2008, Stephen Smalley wrote:
> So the next question is whether there are any other cases where we want
> to use this variant interface. For example, if
> selinux_inode_getsecurity() were to use this variant interface, then we
> would report the original context string to userspace upon getxattr()
> rather than the unlabeled context, and thus in my example sequence, the
> ls -Z would always show the system_u:object_r:foo_exec_t label on the
> bar file regardless of whether it was defined in the policy.
I wonder if it makes sense to only show the external labels if the process
has CAP_MAC_ADMIN ?
> I assume we do NOT want to use this variant interface when getting
> contexts to display in audit messages, as we want the audit messages to
> correspond to the actual denial and to yield proper policy if turned
> into an allow rule.
Correct.
> Likewise, are there any other cases where we want to use the reverse
> interface (security_context_to_sid_force) beyond just setxattr and
> fscreate to permit userspace to set undefined contexts on anything else?
Not that I can think of.
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 13:45 ` James Morris
@ 2008-05-07 15:12 ` Stephen Smalley
2008-05-07 17:03 ` [PATCH v5] " Stephen Smalley
0 siblings, 1 reply; 25+ messages in thread
From: Stephen Smalley @ 2008-05-07 15:12 UTC (permalink / raw)
To: James Morris; +Cc: selinux, Eric Paris, Daniel J Walsh
On Wed, 2008-05-07 at 23:45 +1000, James Morris wrote:
> On Wed, 7 May 2008, Stephen Smalley wrote:
>
> > So the next question is whether there are any other cases where we want
> > to use this variant interface. For example, if
> > selinux_inode_getsecurity() were to use this variant interface, then we
> > would report the original context string to userspace upon getxattr()
> > rather than the unlabeled context, and thus in my example sequence, the
> > ls -Z would always show the system_u:object_r:foo_exec_t label on the
> > bar file regardless of whether it was defined in the policy.
>
> I wonder if it makes sense to only show the external labels if the process
> has CAP_MAC_ADMIN ?
Seems somewhat intuitive (a process that can set an undefined label
should already be aware of this possibility and may want to see the raw
value), but could also be very confusing. Also, I wouldn't want to
apply a capable() check on every getxattr() of the SELinux attribute.
For now, I'll just update the patch to introduce and use this variant
interface in the inode_init_security case so that we correctly handle
fscreate and re-post with those changes.
>
> > I assume we do NOT want to use this variant interface when getting
> > contexts to display in audit messages, as we want the audit messages to
> > correspond to the actual denial and to yield proper policy if turned
> > into an allow rule.
>
> Correct.
>
> > Likewise, are there any other cases where we want to use the reverse
> > interface (security_context_to_sid_force) beyond just setxattr and
> > fscreate to permit userspace to set undefined contexts on anything else?
>
> Not that I can think of.
>
>
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 12:45 ` Stephen Smalley
2008-05-07 13:45 ` James Morris
@ 2008-05-07 15:17 ` Eric Paris
2008-05-07 15:23 ` Stephen Smalley
1 sibling, 1 reply; 25+ messages in thread
From: Eric Paris @ 2008-05-07 15:17 UTC (permalink / raw)
To: Stephen Smalley; +Cc: James Morris, selinux, Daniel J Walsh
> I assume we do NOT want to use this variant interface when getting
> contexts to display in audit messages, as we want the audit messages to
> correspond to the actual denial and to yield proper policy if turned
> into an allow rule.
Is there any way we could get them both displayed if there is a
denial? Might be interesting to know both that the denial was
actually unlabeled_t object but also what the 'incorrect' label
was.....
-Eric
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 15:17 ` [PATCH v4] " Eric Paris
@ 2008-05-07 15:23 ` Stephen Smalley
2008-05-07 15:29 ` Eric Paris
2008-05-07 17:04 ` Daniel J Walsh
0 siblings, 2 replies; 25+ messages in thread
From: Stephen Smalley @ 2008-05-07 15:23 UTC (permalink / raw)
To: Eric Paris; +Cc: James Morris, selinux, Daniel J Walsh
On Wed, 2008-05-07 at 11:17 -0400, Eric Paris wrote:
> > I assume we do NOT want to use this variant interface when getting
> > contexts to display in audit messages, as we want the audit messages to
> > correspond to the actual denial and to yield proper policy if turned
> > into an allow rule.
>
> Is there any way we could get them both displayed if there is a
> denial? Might be interesting to know both that the denial was
> actually unlabeled_t object but also what the 'incorrect' label
> was.....
Easy to do kernel-side, but requires a new avc audit field that won't
cause any complaints by audit userland or tools like audit2allow.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 15:23 ` Stephen Smalley
@ 2008-05-07 15:29 ` Eric Paris
2008-05-07 17:04 ` Daniel J Walsh
1 sibling, 0 replies; 25+ messages in thread
From: Eric Paris @ 2008-05-07 15:29 UTC (permalink / raw)
To: Stephen Smalley, linux-audit; +Cc: James Morris, selinux
On Wed, May 7, 2008 at 11:23 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote:
>
>
> On Wed, 2008-05-07 at 11:17 -0400, Eric Paris wrote:
> > > I assume we do NOT want to use this variant interface when getting
> > > contexts to display in audit messages, as we want the audit messages to
> > > correspond to the actual denial and to yield proper policy if turned
> > > into an allow rule.
> >
> > Is there any way we could get them both displayed if there is a
> > denial? Might be interesting to know both that the denial was
> > actually unlabeled_t object but also what the 'incorrect' label
> > was.....
>
> Easy to do kernel-side, but requires a new avc audit field that won't
> cause any complaints by audit userland or tools like audit2allow.
Well, I'm not concerned about audit userland, if they can't handle
arbitrary users or the audit subsystem that's an audit failure. As to
audit2allow I'm clueless but I guess i could take a look if others
think it is an interesting piece of knowledge...
-Eric
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
@ 2008-05-07 15:29 ` Eric Paris
0 siblings, 0 replies; 25+ messages in thread
From: Eric Paris @ 2008-05-07 15:29 UTC (permalink / raw)
To: Stephen Smalley, linux-audit; +Cc: James Morris, selinux, Daniel J Walsh
On Wed, May 7, 2008 at 11:23 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote:
>
>
> On Wed, 2008-05-07 at 11:17 -0400, Eric Paris wrote:
> > > I assume we do NOT want to use this variant interface when getting
> > > contexts to display in audit messages, as we want the audit messages to
> > > correspond to the actual denial and to yield proper policy if turned
> > > into an allow rule.
> >
> > Is there any way we could get them both displayed if there is a
> > denial? Might be interesting to know both that the denial was
> > actually unlabeled_t object but also what the 'incorrect' label
> > was.....
>
> Easy to do kernel-side, but requires a new avc audit field that won't
> cause any complaints by audit userland or tools like audit2allow.
Well, I'm not concerned about audit userland, if they can't handle
arbitrary users or the audit subsystem that's an audit failure. As to
audit2allow I'm clueless but I guess i could take a look if others
think it is an interesting piece of knowledge...
-Eric
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 15:29 ` Eric Paris
@ 2008-05-07 16:48 ` Steve Grubb
-1 siblings, 0 replies; 25+ messages in thread
From: Steve Grubb @ 2008-05-07 16:48 UTC (permalink / raw)
To: linux-audit; +Cc: Eric Paris, James Morris, selinux
On Wednesday 07 May 2008 11:29:36 Eric Paris wrote:
> On Wed, May 7, 2008 at 11:23 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> > On Wed, 2008-05-07 at 11:17 -0400, Eric Paris wrote:
> > > > I assume we do NOT want to use this variant interface when getting
> > > > contexts to display in audit messages, as we want the audit
> > > > messages to correspond to the actual denial and to yield proper
> > > > policy if turned into an allow rule.
> > >
> > > Is there any way we could get them both displayed if there is a
> > > denial? Might be interesting to know both that the denial was
> > > actually unlabeled_t object but also what the 'incorrect' label
> > > was.....
> >
> > Easy to do kernel-side, but requires a new avc audit field that won't
> > cause any complaints by audit userland or tools like audit2allow.
What would be the proposed name of this new field? Would it hold just a
context string? FWIW, audit user land doesn't really care except that we
don't have name collisions on fields.
-Steve
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
@ 2008-05-07 16:48 ` Steve Grubb
0 siblings, 0 replies; 25+ messages in thread
From: Steve Grubb @ 2008-05-07 16:48 UTC (permalink / raw)
To: linux-audit; +Cc: Eric Paris, Stephen Smalley, James Morris, selinux
On Wednesday 07 May 2008 11:29:36 Eric Paris wrote:
> On Wed, May 7, 2008 at 11:23 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> > On Wed, 2008-05-07 at 11:17 -0400, Eric Paris wrote:
> > > > I assume we do NOT want to use this variant interface when getting
> > > > contexts to display in audit messages, as we want the audit
> > > > messages to correspond to the actual denial and to yield proper
> > > > policy if turned into an allow rule.
> > >
> > > Is there any way we could get them both displayed if there is a
> > > denial? Might be interesting to know both that the denial was
> > > actually unlabeled_t object but also what the 'incorrect' label
> > > was.....
> >
> > Easy to do kernel-side, but requires a new avc audit field that won't
> > cause any complaints by audit userland or tools like audit2allow.
What would be the proposed name of this new field? Would it hold just a
context string? FWIW, audit user land doesn't really care except that we
don't have name collisions on fields.
-Steve
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v5] selinux: support deferred mapping of contexts
2008-05-07 15:12 ` Stephen Smalley
@ 2008-05-07 17:03 ` Stephen Smalley
2008-05-07 17:14 ` Stephen Smalley
0 siblings, 1 reply; 25+ messages in thread
From: Stephen Smalley @ 2008-05-07 17:03 UTC (permalink / raw)
To: James Morris; +Cc: selinux, Eric Paris, Daniel J Walsh
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:unlabeled_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>
---
This version of the patch solves the problem for fscreate by introducing support for obtaining
the raw context value for use by selinux_inode_init_security(). The example sequence above
has been updated and tested to confirm correct operation for both setxattr() and fscreate usage
by exercising both chcon and mkdir -Z. I believe that this patch is now ready for inclusion
in -mm and Fedora rawhide kernels for F10. If we want to add support for other aspects like
including raw context values in audit messages, conditionally returning them via getxattr for
privileged processes, etc. I think we'll do it as separate follow-on patches.
security/selinux/hooks.c | 20 ++
security/selinux/include/security.h | 5
security/selinux/ss/context.h | 27 +++
security/selinux/ss/mls.c | 11 -
security/selinux/ss/mls.h | 3
security/selinux/ss/services.c | 245 +++++++++++++++++++++++++-----------
security/selinux/ss/sidtab.c | 58 ++------
security/selinux/ss/sidtab.h | 7 -
8 files changed, 248 insertions(+), 128 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1c864c0..59c6e98 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -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;
@@ -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;
@@ -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;
}
@@ -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;
}
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ad30ac4..7c54300 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -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);
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index b9a6f7f..658c2bd 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -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)
@@ -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) &&
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 8b1706b..a6ca058 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -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,
@@ -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;
@@ -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;
@@ -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;
@@ -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);
}
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 0fdf625..1276715 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -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,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index dcc2e1c..b86ac9d 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -616,6 +616,14 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
*scontext = NULL;
*scontext_len = 0;
+ if (context->len) {
+ *scontext_len = context->len;
+ *scontext = kstrdup(context->str, GFP_ATOMIC);
+ if (!(*scontext))
+ return -ENOMEM;
+ return 0;
+ }
+
/* Compute the size of the context. */
*scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
*scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
@@ -655,17 +663,8 @@ const char *security_get_initial_sid_context(u32 sid)
return initial_sid_to_string[sid];
}
-/**
- * security_sid_to_context - Obtain a context for a given SID.
- * @sid: security identifier, SID
- * @scontext: security context
- * @scontext_len: length in bytes
- *
- * Write the string representation of the context associated with @sid
- * into a dynamically allocated string of the correct size. Set @scontext
- * to point to this string and set @scontext_len to the length of the string.
- */
-int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+static int security_sid_to_context_core(u32 sid, char **scontext,
+ u32 *scontext_len, int force)
{
struct context *context;
int rc = 0;
@@ -693,7 +692,10 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
goto out;
}
POLICY_RDLOCK;
- context = sidtab_search(&sidtab, sid);
+ if (force)
+ context = sidtab_search_force(&sidtab, sid);
+ else
+ context = sidtab_search(&sidtab, sid);
if (!context) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, sid);
@@ -708,36 +710,44 @@ out:
}
-static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
- u32 *sid, u32 def_sid, gfp_t gfp_flags)
+/**
+ * security_sid_to_context - Obtain a context for a given SID.
+ * @sid: security identifier, SID
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ *
+ * Write the string representation of the context associated with @sid
+ * into a dynamically allocated string of the correct size. Set @scontext
+ * to point to this string and set @scontext_len to the length of the string.
+ */
+int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
{
- char *scontext2;
- struct context context;
+ return security_sid_to_context_core(sid, scontext, scontext_len, 0);
+}
+
+int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len)
+{
+ return security_sid_to_context_core(sid, scontext, scontext_len, 1);
+}
+
+static int string_to_context_struct(struct policydb *pol,
+ struct sidtab *sidtabp,
+ const char *scontext,
+ u32 scontext_len,
+ struct context *ctx,
+ u32 def_sid,
+ gfp_t gfp_flags)
+{
+ char *scontext2 = NULL;
struct role_datum *role;
struct type_datum *typdatum;
struct user_datum *usrdatum;
char *scontextp, *p, oldc;
int rc = 0;
- if (!ss_initialized) {
- int i;
+ context_init(ctx);
- for (i = 1; i < SECINITSID_NUM; i++) {
- if (!strcmp(initial_sid_to_string[i], scontext)) {
- *sid = i;
- goto out;
- }
- }
- *sid = SECINITSID_KERNEL;
- goto out;
- }
- *sid = SECSID_NULL;
-
- /* Copy the string so that we can modify the copy as we parse it.
- The string should already by null terminated, but we append a
- null suffix to the copy to avoid problems with the existing
- attr package, which doesn't view the null terminator as part
- of the attribute value. */
+ /* Copy the string so that we can modify the copy as we parse it. */
scontext2 = kmalloc(scontext_len+1, gfp_flags);
if (!scontext2) {
rc = -ENOMEM;
@@ -746,11 +756,6 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
memcpy(scontext2, scontext, scontext_len);
scontext2[scontext_len] = 0;
- context_init(&context);
- *sid = SECSID_NULL;
-
- POLICY_RDLOCK;
-
/* Parse the security context. */
rc = -EINVAL;
@@ -762,15 +767,15 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
p++;
if (*p == 0)
- goto out_unlock;
+ goto out;
*p++ = 0;
- usrdatum = hashtab_search(policydb.p_users.table, scontextp);
+ usrdatum = hashtab_search(pol->p_users.table, scontextp);
if (!usrdatum)
- goto out_unlock;
+ goto out;
- context.user = usrdatum->value;
+ ctx->user = usrdatum->value;
/* Extract role. */
scontextp = p;
@@ -778,14 +783,14 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
p++;
if (*p == 0)
- goto out_unlock;
+ goto out;
*p++ = 0;
- role = hashtab_search(policydb.p_roles.table, scontextp);
+ role = hashtab_search(pol->p_roles.table, scontextp);
if (!role)
- goto out_unlock;
- context.role = role->value;
+ goto out;
+ ctx->role = role->value;
/* Extract type. */
scontextp = p;
@@ -794,33 +799,74 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
oldc = *p;
*p++ = 0;
- typdatum = hashtab_search(policydb.p_types.table, scontextp);
+ typdatum = hashtab_search(pol->p_types.table, scontextp);
if (!typdatum)
- goto out_unlock;
+ goto out;
- context.type = typdatum->value;
+ ctx->type = typdatum->value;
- rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
+ rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
if (rc)
- goto out_unlock;
+ goto out;
if ((p - scontext2) < scontext_len) {
rc = -EINVAL;
- goto out_unlock;
+ goto out;
}
/* Check the validity of the new context. */
- if (!policydb_context_isvalid(&policydb, &context)) {
+ if (!policydb_context_isvalid(pol, ctx)) {
rc = -EINVAL;
- goto out_unlock;
+ context_destroy(ctx);
+ goto out;
}
- /* Obtain the new sid. */
- rc = sidtab_context_to_sid(&sidtab, &context, sid);
-out_unlock:
- POLICY_RDUNLOCK;
- context_destroy(&context);
+ rc = 0;
+out:
kfree(scontext2);
+ return rc;
+}
+
+static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
+ u32 *sid, u32 def_sid, gfp_t gfp_flags,
+ int force)
+{
+ struct context context;
+ int rc = 0;
+
+ if (!ss_initialized) {
+ int i;
+
+ for (i = 1; i < SECINITSID_NUM; i++) {
+ if (!strcmp(initial_sid_to_string[i], scontext)) {
+ *sid = i;
+ goto out;
+ }
+ }
+ *sid = SECINITSID_KERNEL;
+ goto out;
+ }
+ *sid = SECSID_NULL;
+
+ POLICY_RDLOCK;
+ rc = string_to_context_struct(&policydb, &sidtab,
+ scontext, scontext_len,
+ &context, def_sid, gfp_flags);
+ if (rc == -EINVAL && force) {
+ context.str = kmalloc(scontext_len+1, gfp_flags);
+ if (!context.str) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memcpy(context.str, scontext, scontext_len);
+ context.str[scontext_len] = 0;
+ context.len = scontext_len;
+ } else if (rc)
+ goto out;
+ rc = sidtab_context_to_sid(&sidtab, &context, sid);
+ if (rc)
+ context_destroy(&context);
out:
+ POLICY_RDUNLOCK;
return rc;
}
@@ -838,7 +884,7 @@ out:
int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, SECSID_NULL, GFP_KERNEL);
+ sid, SECSID_NULL, GFP_KERNEL, 0);
}
/**
@@ -855,6 +901,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
* The default SID is passed to the MLS layer to be used to allow
* kernel labeling of the MLS field if the MLS field is not present
* (for upgrading to MLS without full relabel).
+ * Implicitly forces adding of the context even if it cannot be mapped yet.
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
@@ -862,7 +909,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, def_sid, gfp_flags);
+ sid, def_sid, gfp_flags, 1);
+}
+
+int security_context_to_sid_force(const char *scontext, u32 scontext_len,
+ u32 *sid)
+{
+ return security_context_to_sid_core(scontext, scontext_len,
+ sid, SECSID_NULL, GFP_KERNEL, 1);
}
static int compute_sid_handle_invalid_context(
@@ -1246,9 +1300,12 @@ static inline int convert_context_handle_invalid_context(struct context *context
char *s;
u32 len;
- context_struct_to_string(context, &s, &len);
- printk(KERN_ERR "SELinux: context %s is invalid\n", s);
- kfree(s);
+ if (!context_struct_to_string(context, &s, &len)) {
+ printk(KERN_WARNING
+ "SELinux: Context %s would be invalid if enforcing\n",
+ s);
+ kfree(s);
+ }
}
return rc;
}
@@ -1280,6 +1337,32 @@ static int convert_context(u32 key,
args = p;
+ if (c->str) {
+ struct context ctx;
+ rc = string_to_context_struct(args->newp, NULL, c->str,
+ c->len, &ctx, SECSID_NULL,
+ GFP_KERNEL);
+ if (!rc) {
+ printk(KERN_INFO
+ "SELinux: Context %s became valid (mapped).\n",
+ c->str);
+ /* Replace string with mapped representation. */
+ kfree(c->str);
+ memcpy(c, &ctx, sizeof(*c));
+ goto out;
+ } else if (rc == -EINVAL) {
+ /* Retain string representation for later mapping. */
+ rc = 0;
+ goto out;
+ } else {
+ /* Other error condition, e.g. ENOMEM. */
+ printk(KERN_ERR
+ "SELinux: Unable to map context %s, rc = %d.\n",
+ c->str, -rc);
+ goto out;
+ }
+ }
+
rc = context_cpy(&oldc, c);
if (rc)
goto out;
@@ -1319,13 +1402,21 @@ static int convert_context(u32 key,
}
context_destroy(&oldc);
+ rc = 0;
out:
return rc;
bad:
- context_struct_to_string(&oldc, &s, &len);
+ /* Map old representation to string and save it. */
+ if (context_struct_to_string(&oldc, &s, &len))
+ return -ENOMEM;
context_destroy(&oldc);
- printk(KERN_ERR "SELinux: invalidating context %s\n", s);
- kfree(s);
+ context_destroy(c);
+ c->str = s;
+ c->len = len;
+ printk(KERN_INFO
+ "SELinux: Context %s became invalid (unmapped).\n",
+ c->str);
+ rc = 0;
goto out;
}
@@ -1406,7 +1497,11 @@ int security_load_policy(void *data, size_t len)
return -EINVAL;
}
- sidtab_init(&newsidtab);
+ if (sidtab_init(&newsidtab)) {
+ LOAD_UNLOCK;
+ policydb_destroy(&newpolicydb);
+ return -ENOMEM;
+ }
/* Verify that the kernel defined classes are correct. */
if (validate_classes(&newpolicydb)) {
@@ -1429,11 +1524,15 @@ int security_load_policy(void *data, size_t len)
goto err;
}
- /* Convert the internal representations of contexts
- in the new SID table and remove invalid SIDs. */
+ /*
+ * Convert the internal representations of contexts
+ * in the new SID table.
+ */
args.oldp = &policydb;
args.newp = &newpolicydb;
- sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
+ rc = sidtab_map(&newsidtab, convert_context, &args);
+ if (rc)
+ goto err;
/* Save the old policydb and SID table to free later. */
memcpy(&oldpolicydb, &policydb, sizeof policydb);
@@ -1673,6 +1772,8 @@ int security_get_user_sids(u32 fromsid,
POLICY_RDLOCK;
+ context_init(&usercon);
+
fromcon = sidtab_search(&sidtab, fromsid);
if (!fromcon) {
rc = -EINVAL;
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 4a516ff..ba35416 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -86,7 +86,7 @@ out:
return rc;
}
-struct context *sidtab_search(struct sidtab *s, u32 sid)
+static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
{
int hvalue;
struct sidtab_node *cur;
@@ -99,7 +99,10 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
while (cur != NULL && sid > cur->sid)
cur = cur->next;
- if (cur == NULL || sid != cur->sid) {
+ if (force && cur && sid == cur->sid && cur->context.len)
+ return &cur->context;
+
+ if (cur == NULL || sid != cur->sid || cur->context.len) {
/* Remap invalid SIDs to the unlabeled SID. */
sid = SECINITSID_UNLABELED;
hvalue = SIDTAB_HASH(sid);
@@ -113,6 +116,16 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
return &cur->context;
}
+struct context *sidtab_search(struct sidtab *s, u32 sid)
+{
+ return sidtab_search_core(s, sid, 0);
+}
+
+struct context *sidtab_search_force(struct sidtab *s, u32 sid)
+{
+ return sidtab_search_core(s, sid, 1);
+}
+
int sidtab_map(struct sidtab *s,
int (*apply) (u32 sid,
struct context *context,
@@ -138,43 +151,6 @@ out:
return rc;
}
-void sidtab_map_remove_on_error(struct sidtab *s,
- int (*apply) (u32 sid,
- struct context *context,
- void *args),
- void *args)
-{
- int i, ret;
- struct sidtab_node *last, *cur, *temp;
-
- if (!s)
- return;
-
- for (i = 0; i < SIDTAB_SIZE; i++) {
- last = NULL;
- cur = s->htable[i];
- while (cur != NULL) {
- ret = apply(cur->sid, &cur->context, args);
- if (ret) {
- if (last)
- last->next = cur->next;
- else
- s->htable[i] = cur->next;
- temp = cur;
- cur = cur->next;
- context_destroy(&temp->context);
- kfree(temp);
- s->nel--;
- } else {
- last = cur;
- cur = cur->next;
- }
- }
- }
-
- return;
-}
-
static inline u32 sidtab_search_context(struct sidtab *s,
struct context *context)
{
@@ -215,6 +191,10 @@ int sidtab_context_to_sid(struct sidtab *s,
goto unlock_out;
}
sid = s->next_sid++;
+ if (context->len)
+ printk(KERN_INFO
+ "SELinux: Context %s is not valid (left unmapped).\n",
+ context->str);
ret = sidtab_insert(s, sid, context);
if (ret)
s->next_sid--;
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index 2fe9dfa..64ea5b1 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -32,6 +32,7 @@ struct sidtab {
int sidtab_init(struct sidtab *s);
int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
struct context *sidtab_search(struct sidtab *s, u32 sid);
+struct context *sidtab_search_force(struct sidtab *s, u32 sid);
int sidtab_map(struct sidtab *s,
int (*apply) (u32 sid,
@@ -39,12 +40,6 @@ int sidtab_map(struct sidtab *s,
void *args),
void *args);
-void sidtab_map_remove_on_error(struct sidtab *s,
- int (*apply) (u32 sid,
- struct context *context,
- void *args),
- void *args);
-
int sidtab_context_to_sid(struct sidtab *s,
struct context *context,
u32 *sid);
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 15:23 ` Stephen Smalley
2008-05-07 15:29 ` Eric Paris
@ 2008-05-07 17:04 ` Daniel J Walsh
1 sibling, 0 replies; 25+ messages in thread
From: Daniel J Walsh @ 2008-05-07 17:04 UTC (permalink / raw)
To: Stephen Smalley; +Cc: Eric Paris, James Morris, selinux
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Stephen Smalley wrote:
> On Wed, 2008-05-07 at 11:17 -0400, Eric Paris wrote:
>>> I assume we do NOT want to use this variant interface when getting
>>> contexts to display in audit messages, as we want the audit messages to
>>> correspond to the actual denial and to yield proper policy if turned
>>> into an allow rule.
>> Is there any way we could get them both displayed if there is a
>> denial? Might be interesting to know both that the denial was
>> actually unlabeled_t object but also what the 'incorrect' label
>> was.....
>
> Easy to do kernel-side, but requires a new avc audit field that won't
> cause any complaints by audit userland or tools like audit2allow.
>
Audit2allow would just ignore it. It is searching for name value pairs
and drops ones it does not understand.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org
iEYEARECAAYFAkgh4TYACgkQrlYvE4MpobPmeQCgqqWyHaFBDiQCjjTj5nTxP3V1
RKoAn0QUac3ZVxhe2vhw0nIWvOscnAGB
=+jxw
-----END PGP SIGNATURE-----
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v5] selinux: support deferred mapping of contexts
2008-05-07 17:03 ` [PATCH v5] " Stephen Smalley
@ 2008-05-07 17:14 ` Stephen Smalley
2008-05-08 0:08 ` James Morris
0 siblings, 1 reply; 25+ messages in thread
From: Stephen Smalley @ 2008-05-07 17:14 UTC (permalink / raw)
To: James Morris; +Cc: selinux, Eric Paris, Daniel J Walsh
On Wed, 2008-05-07 at 13:03 -0400, Stephen Smalley wrote:
> 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:unlabeled_t baz
Ahem. The above mismatch between foo_exec_t on bar and unlabeled_t on
baz was just a cut-and-paste error, and is correct (i.e. both
foo_exec_t) in the actual output from running the above commands. So
feel free to edit it in the patch description that gets committed.
> # 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>
>
> ---
>
> This version of the patch solves the problem for fscreate by introducing support for obtaining
> the raw context value for use by selinux_inode_init_security(). The example sequence above
> has been updated and tested to confirm correct operation for both setxattr() and fscreate usage
> by exercising both chcon and mkdir -Z. I believe that this patch is now ready for inclusion
> in -mm and Fedora rawhide kernels for F10. If we want to add support for other aspects like
> including raw context values in audit messages, conditionally returning them via getxattr for
> privileged processes, etc. I think we'll do it as separate follow-on patches.
>
> security/selinux/hooks.c | 20 ++
> security/selinux/include/security.h | 5
> security/selinux/ss/context.h | 27 +++
> security/selinux/ss/mls.c | 11 -
> security/selinux/ss/mls.h | 3
> security/selinux/ss/services.c | 245 +++++++++++++++++++++++++-----------
> security/selinux/ss/sidtab.c | 58 ++------
> security/selinux/ss/sidtab.h | 7 -
> 8 files changed, 248 insertions(+), 128 deletions(-)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 1c864c0..59c6e98 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -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;
> @@ -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;
>
> @@ -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;
> }
>
> @@ -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;
> }
> diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
> index ad30ac4..7c54300 100644
> --- a/security/selinux/include/security.h
> +++ b/security/selinux/include/security.h
> @@ -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);
>
> diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
> index b9a6f7f..658c2bd 100644
> --- a/security/selinux/ss/context.h
> +++ b/security/selinux/ss/context.h
> @@ -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)
> @@ -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) &&
> diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
> index 8b1706b..a6ca058 100644
> --- a/security/selinux/ss/mls.c
> +++ b/security/selinux/ss/mls.c
> @@ -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,
> @@ -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;
> @@ -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;
> @@ -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;
> @@ -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);
> }
> diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
> index 0fdf625..1276715 100644
> --- a/security/selinux/ss/mls.h
> +++ b/security/selinux/ss/mls.h
> @@ -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,
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index dcc2e1c..b86ac9d 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -616,6 +616,14 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
> *scontext = NULL;
> *scontext_len = 0;
>
> + if (context->len) {
> + *scontext_len = context->len;
> + *scontext = kstrdup(context->str, GFP_ATOMIC);
> + if (!(*scontext))
> + return -ENOMEM;
> + return 0;
> + }
> +
> /* Compute the size of the context. */
> *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
> *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
> @@ -655,17 +663,8 @@ const char *security_get_initial_sid_context(u32 sid)
> return initial_sid_to_string[sid];
> }
>
> -/**
> - * security_sid_to_context - Obtain a context for a given SID.
> - * @sid: security identifier, SID
> - * @scontext: security context
> - * @scontext_len: length in bytes
> - *
> - * Write the string representation of the context associated with @sid
> - * into a dynamically allocated string of the correct size. Set @scontext
> - * to point to this string and set @scontext_len to the length of the string.
> - */
> -int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
> +static int security_sid_to_context_core(u32 sid, char **scontext,
> + u32 *scontext_len, int force)
> {
> struct context *context;
> int rc = 0;
> @@ -693,7 +692,10 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
> goto out;
> }
> POLICY_RDLOCK;
> - context = sidtab_search(&sidtab, sid);
> + if (force)
> + context = sidtab_search_force(&sidtab, sid);
> + else
> + context = sidtab_search(&sidtab, sid);
> if (!context) {
> printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
> __func__, sid);
> @@ -708,36 +710,44 @@ out:
>
> }
>
> -static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
> - u32 *sid, u32 def_sid, gfp_t gfp_flags)
> +/**
> + * security_sid_to_context - Obtain a context for a given SID.
> + * @sid: security identifier, SID
> + * @scontext: security context
> + * @scontext_len: length in bytes
> + *
> + * Write the string representation of the context associated with @sid
> + * into a dynamically allocated string of the correct size. Set @scontext
> + * to point to this string and set @scontext_len to the length of the string.
> + */
> +int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
> {
> - char *scontext2;
> - struct context context;
> + return security_sid_to_context_core(sid, scontext, scontext_len, 0);
> +}
> +
> +int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len)
> +{
> + return security_sid_to_context_core(sid, scontext, scontext_len, 1);
> +}
> +
> +static int string_to_context_struct(struct policydb *pol,
> + struct sidtab *sidtabp,
> + const char *scontext,
> + u32 scontext_len,
> + struct context *ctx,
> + u32 def_sid,
> + gfp_t gfp_flags)
> +{
> + char *scontext2 = NULL;
> struct role_datum *role;
> struct type_datum *typdatum;
> struct user_datum *usrdatum;
> char *scontextp, *p, oldc;
> int rc = 0;
>
> - if (!ss_initialized) {
> - int i;
> + context_init(ctx);
>
> - for (i = 1; i < SECINITSID_NUM; i++) {
> - if (!strcmp(initial_sid_to_string[i], scontext)) {
> - *sid = i;
> - goto out;
> - }
> - }
> - *sid = SECINITSID_KERNEL;
> - goto out;
> - }
> - *sid = SECSID_NULL;
> -
> - /* Copy the string so that we can modify the copy as we parse it.
> - The string should already by null terminated, but we append a
> - null suffix to the copy to avoid problems with the existing
> - attr package, which doesn't view the null terminator as part
> - of the attribute value. */
> + /* Copy the string so that we can modify the copy as we parse it. */
> scontext2 = kmalloc(scontext_len+1, gfp_flags);
> if (!scontext2) {
> rc = -ENOMEM;
> @@ -746,11 +756,6 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
> memcpy(scontext2, scontext, scontext_len);
> scontext2[scontext_len] = 0;
>
> - context_init(&context);
> - *sid = SECSID_NULL;
> -
> - POLICY_RDLOCK;
> -
> /* Parse the security context. */
>
> rc = -EINVAL;
> @@ -762,15 +767,15 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
> p++;
>
> if (*p == 0)
> - goto out_unlock;
> + goto out;
>
> *p++ = 0;
>
> - usrdatum = hashtab_search(policydb.p_users.table, scontextp);
> + usrdatum = hashtab_search(pol->p_users.table, scontextp);
> if (!usrdatum)
> - goto out_unlock;
> + goto out;
>
> - context.user = usrdatum->value;
> + ctx->user = usrdatum->value;
>
> /* Extract role. */
> scontextp = p;
> @@ -778,14 +783,14 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
> p++;
>
> if (*p == 0)
> - goto out_unlock;
> + goto out;
>
> *p++ = 0;
>
> - role = hashtab_search(policydb.p_roles.table, scontextp);
> + role = hashtab_search(pol->p_roles.table, scontextp);
> if (!role)
> - goto out_unlock;
> - context.role = role->value;
> + goto out;
> + ctx->role = role->value;
>
> /* Extract type. */
> scontextp = p;
> @@ -794,33 +799,74 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
> oldc = *p;
> *p++ = 0;
>
> - typdatum = hashtab_search(policydb.p_types.table, scontextp);
> + typdatum = hashtab_search(pol->p_types.table, scontextp);
> if (!typdatum)
> - goto out_unlock;
> + goto out;
>
> - context.type = typdatum->value;
> + ctx->type = typdatum->value;
>
> - rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
> + rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
> if (rc)
> - goto out_unlock;
> + goto out;
>
> if ((p - scontext2) < scontext_len) {
> rc = -EINVAL;
> - goto out_unlock;
> + goto out;
> }
>
> /* Check the validity of the new context. */
> - if (!policydb_context_isvalid(&policydb, &context)) {
> + if (!policydb_context_isvalid(pol, ctx)) {
> rc = -EINVAL;
> - goto out_unlock;
> + context_destroy(ctx);
> + goto out;
> }
> - /* Obtain the new sid. */
> - rc = sidtab_context_to_sid(&sidtab, &context, sid);
> -out_unlock:
> - POLICY_RDUNLOCK;
> - context_destroy(&context);
> + rc = 0;
> +out:
> kfree(scontext2);
> + return rc;
> +}
> +
> +static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
> + u32 *sid, u32 def_sid, gfp_t gfp_flags,
> + int force)
> +{
> + struct context context;
> + int rc = 0;
> +
> + if (!ss_initialized) {
> + int i;
> +
> + for (i = 1; i < SECINITSID_NUM; i++) {
> + if (!strcmp(initial_sid_to_string[i], scontext)) {
> + *sid = i;
> + goto out;
> + }
> + }
> + *sid = SECINITSID_KERNEL;
> + goto out;
> + }
> + *sid = SECSID_NULL;
> +
> + POLICY_RDLOCK;
> + rc = string_to_context_struct(&policydb, &sidtab,
> + scontext, scontext_len,
> + &context, def_sid, gfp_flags);
> + if (rc == -EINVAL && force) {
> + context.str = kmalloc(scontext_len+1, gfp_flags);
> + if (!context.str) {
> + rc = -ENOMEM;
> + goto out;
> + }
> + memcpy(context.str, scontext, scontext_len);
> + context.str[scontext_len] = 0;
> + context.len = scontext_len;
> + } else if (rc)
> + goto out;
> + rc = sidtab_context_to_sid(&sidtab, &context, sid);
> + if (rc)
> + context_destroy(&context);
> out:
> + POLICY_RDUNLOCK;
> return rc;
> }
>
> @@ -838,7 +884,7 @@ out:
> int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
> {
> return security_context_to_sid_core(scontext, scontext_len,
> - sid, SECSID_NULL, GFP_KERNEL);
> + sid, SECSID_NULL, GFP_KERNEL, 0);
> }
>
> /**
> @@ -855,6 +901,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
> * The default SID is passed to the MLS layer to be used to allow
> * kernel labeling of the MLS field if the MLS field is not present
> * (for upgrading to MLS without full relabel).
> + * Implicitly forces adding of the context even if it cannot be mapped yet.
> * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
> * memory is available, or 0 on success.
> */
> @@ -862,7 +909,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len,
> u32 *sid, u32 def_sid, gfp_t gfp_flags)
> {
> return security_context_to_sid_core(scontext, scontext_len,
> - sid, def_sid, gfp_flags);
> + sid, def_sid, gfp_flags, 1);
> +}
> +
> +int security_context_to_sid_force(const char *scontext, u32 scontext_len,
> + u32 *sid)
> +{
> + return security_context_to_sid_core(scontext, scontext_len,
> + sid, SECSID_NULL, GFP_KERNEL, 1);
> }
>
> static int compute_sid_handle_invalid_context(
> @@ -1246,9 +1300,12 @@ static inline int convert_context_handle_invalid_context(struct context *context
> char *s;
> u32 len;
>
> - context_struct_to_string(context, &s, &len);
> - printk(KERN_ERR "SELinux: context %s is invalid\n", s);
> - kfree(s);
> + if (!context_struct_to_string(context, &s, &len)) {
> + printk(KERN_WARNING
> + "SELinux: Context %s would be invalid if enforcing\n",
> + s);
> + kfree(s);
> + }
> }
> return rc;
> }
> @@ -1280,6 +1337,32 @@ static int convert_context(u32 key,
>
> args = p;
>
> + if (c->str) {
> + struct context ctx;
> + rc = string_to_context_struct(args->newp, NULL, c->str,
> + c->len, &ctx, SECSID_NULL,
> + GFP_KERNEL);
> + if (!rc) {
> + printk(KERN_INFO
> + "SELinux: Context %s became valid (mapped).\n",
> + c->str);
> + /* Replace string with mapped representation. */
> + kfree(c->str);
> + memcpy(c, &ctx, sizeof(*c));
> + goto out;
> + } else if (rc == -EINVAL) {
> + /* Retain string representation for later mapping. */
> + rc = 0;
> + goto out;
> + } else {
> + /* Other error condition, e.g. ENOMEM. */
> + printk(KERN_ERR
> + "SELinux: Unable to map context %s, rc = %d.\n",
> + c->str, -rc);
> + goto out;
> + }
> + }
> +
> rc = context_cpy(&oldc, c);
> if (rc)
> goto out;
> @@ -1319,13 +1402,21 @@ static int convert_context(u32 key,
> }
>
> context_destroy(&oldc);
> + rc = 0;
> out:
> return rc;
> bad:
> - context_struct_to_string(&oldc, &s, &len);
> + /* Map old representation to string and save it. */
> + if (context_struct_to_string(&oldc, &s, &len))
> + return -ENOMEM;
> context_destroy(&oldc);
> - printk(KERN_ERR "SELinux: invalidating context %s\n", s);
> - kfree(s);
> + context_destroy(c);
> + c->str = s;
> + c->len = len;
> + printk(KERN_INFO
> + "SELinux: Context %s became invalid (unmapped).\n",
> + c->str);
> + rc = 0;
> goto out;
> }
>
> @@ -1406,7 +1497,11 @@ int security_load_policy(void *data, size_t len)
> return -EINVAL;
> }
>
> - sidtab_init(&newsidtab);
> + if (sidtab_init(&newsidtab)) {
> + LOAD_UNLOCK;
> + policydb_destroy(&newpolicydb);
> + return -ENOMEM;
> + }
>
> /* Verify that the kernel defined classes are correct. */
> if (validate_classes(&newpolicydb)) {
> @@ -1429,11 +1524,15 @@ int security_load_policy(void *data, size_t len)
> goto err;
> }
>
> - /* Convert the internal representations of contexts
> - in the new SID table and remove invalid SIDs. */
> + /*
> + * Convert the internal representations of contexts
> + * in the new SID table.
> + */
> args.oldp = &policydb;
> args.newp = &newpolicydb;
> - sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
> + rc = sidtab_map(&newsidtab, convert_context, &args);
> + if (rc)
> + goto err;
>
> /* Save the old policydb and SID table to free later. */
> memcpy(&oldpolicydb, &policydb, sizeof policydb);
> @@ -1673,6 +1772,8 @@ int security_get_user_sids(u32 fromsid,
>
> POLICY_RDLOCK;
>
> + context_init(&usercon);
> +
> fromcon = sidtab_search(&sidtab, fromsid);
> if (!fromcon) {
> rc = -EINVAL;
> diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
> index 4a516ff..ba35416 100644
> --- a/security/selinux/ss/sidtab.c
> +++ b/security/selinux/ss/sidtab.c
> @@ -86,7 +86,7 @@ out:
> return rc;
> }
>
> -struct context *sidtab_search(struct sidtab *s, u32 sid)
> +static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
> {
> int hvalue;
> struct sidtab_node *cur;
> @@ -99,7 +99,10 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
> while (cur != NULL && sid > cur->sid)
> cur = cur->next;
>
> - if (cur == NULL || sid != cur->sid) {
> + if (force && cur && sid == cur->sid && cur->context.len)
> + return &cur->context;
> +
> + if (cur == NULL || sid != cur->sid || cur->context.len) {
> /* Remap invalid SIDs to the unlabeled SID. */
> sid = SECINITSID_UNLABELED;
> hvalue = SIDTAB_HASH(sid);
> @@ -113,6 +116,16 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
> return &cur->context;
> }
>
> +struct context *sidtab_search(struct sidtab *s, u32 sid)
> +{
> + return sidtab_search_core(s, sid, 0);
> +}
> +
> +struct context *sidtab_search_force(struct sidtab *s, u32 sid)
> +{
> + return sidtab_search_core(s, sid, 1);
> +}
> +
> int sidtab_map(struct sidtab *s,
> int (*apply) (u32 sid,
> struct context *context,
> @@ -138,43 +151,6 @@ out:
> return rc;
> }
>
> -void sidtab_map_remove_on_error(struct sidtab *s,
> - int (*apply) (u32 sid,
> - struct context *context,
> - void *args),
> - void *args)
> -{
> - int i, ret;
> - struct sidtab_node *last, *cur, *temp;
> -
> - if (!s)
> - return;
> -
> - for (i = 0; i < SIDTAB_SIZE; i++) {
> - last = NULL;
> - cur = s->htable[i];
> - while (cur != NULL) {
> - ret = apply(cur->sid, &cur->context, args);
> - if (ret) {
> - if (last)
> - last->next = cur->next;
> - else
> - s->htable[i] = cur->next;
> - temp = cur;
> - cur = cur->next;
> - context_destroy(&temp->context);
> - kfree(temp);
> - s->nel--;
> - } else {
> - last = cur;
> - cur = cur->next;
> - }
> - }
> - }
> -
> - return;
> -}
> -
> static inline u32 sidtab_search_context(struct sidtab *s,
> struct context *context)
> {
> @@ -215,6 +191,10 @@ int sidtab_context_to_sid(struct sidtab *s,
> goto unlock_out;
> }
> sid = s->next_sid++;
> + if (context->len)
> + printk(KERN_INFO
> + "SELinux: Context %s is not valid (left unmapped).\n",
> + context->str);
> ret = sidtab_insert(s, sid, context);
> if (ret)
> s->next_sid--;
> diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
> index 2fe9dfa..64ea5b1 100644
> --- a/security/selinux/ss/sidtab.h
> +++ b/security/selinux/ss/sidtab.h
> @@ -32,6 +32,7 @@ struct sidtab {
> int sidtab_init(struct sidtab *s);
> int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
> struct context *sidtab_search(struct sidtab *s, u32 sid);
> +struct context *sidtab_search_force(struct sidtab *s, u32 sid);
>
> int sidtab_map(struct sidtab *s,
> int (*apply) (u32 sid,
> @@ -39,12 +40,6 @@ int sidtab_map(struct sidtab *s,
> void *args),
> void *args);
>
> -void sidtab_map_remove_on_error(struct sidtab *s,
> - int (*apply) (u32 sid,
> - struct context *context,
> - void *args),
> - void *args);
> -
> int sidtab_context_to_sid(struct sidtab *s,
> struct context *context,
> u32 *sid);
>
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 16:48 ` Steve Grubb
@ 2008-05-07 17:20 ` Stephen Smalley
-1 siblings, 0 replies; 25+ messages in thread
From: Stephen Smalley @ 2008-05-07 17:20 UTC (permalink / raw)
To: Steve Grubb; +Cc: Eric Paris, linux-audit, James Morris, selinux
On Wed, 2008-05-07 at 12:48 -0400, Steve Grubb wrote:
> On Wednesday 07 May 2008 11:29:36 Eric Paris wrote:
> > On Wed, May 7, 2008 at 11:23 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> > > On Wed, 2008-05-07 at 11:17 -0400, Eric Paris wrote:
> > > > > I assume we do NOT want to use this variant interface when getting
> > > > > contexts to display in audit messages, as we want the audit
> > > > > messages to correspond to the actual denial and to yield proper
> > > > > policy if turned into an allow rule.
> > > >
> > > > Is there any way we could get them both displayed if there is a
> > > > denial? Might be interesting to know both that the denial was
> > > > actually unlabeled_t object but also what the 'incorrect' label
> > > > was.....
> > >
> > > Easy to do kernel-side, but requires a new avc audit field that won't
> > > cause any complaints by audit userland or tools like audit2allow.
>
> What would be the proposed name of this new field? Would it hold just a
> context string? FWIW, audit user land doesn't really care except that we
> don't have name collisions on fields.
If we did this (not part of my current patch, but can be done as a
follow-on), then we'd need to define two new fields, one to correspond
to the real/raw context string corresponding to the scontext and one to
correspond to the real/raw context string corresponding to the tcontext.
And they would only be present if the scontext and/or tcontext happened
to be invalid under current policy. Maybe "rscontext" and "rtcontext"
if we don't think that will confuse existing userspace
(audit2allow/sepolgen, setroubleshoot, seaudit, ...).
--
Stephen Smalley
National Security Agency
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
@ 2008-05-07 17:20 ` Stephen Smalley
0 siblings, 0 replies; 25+ messages in thread
From: Stephen Smalley @ 2008-05-07 17:20 UTC (permalink / raw)
To: Steve Grubb; +Cc: linux-audit, Eric Paris, James Morris, selinux
On Wed, 2008-05-07 at 12:48 -0400, Steve Grubb wrote:
> On Wednesday 07 May 2008 11:29:36 Eric Paris wrote:
> > On Wed, May 7, 2008 at 11:23 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> > > On Wed, 2008-05-07 at 11:17 -0400, Eric Paris wrote:
> > > > > I assume we do NOT want to use this variant interface when getting
> > > > > contexts to display in audit messages, as we want the audit
> > > > > messages to correspond to the actual denial and to yield proper
> > > > > policy if turned into an allow rule.
> > > >
> > > > Is there any way we could get them both displayed if there is a
> > > > denial? Might be interesting to know both that the denial was
> > > > actually unlabeled_t object but also what the 'incorrect' label
> > > > was.....
> > >
> > > Easy to do kernel-side, but requires a new avc audit field that won't
> > > cause any complaints by audit userland or tools like audit2allow.
>
> What would be the proposed name of this new field? Would it hold just a
> context string? FWIW, audit user land doesn't really care except that we
> don't have name collisions on fields.
If we did this (not part of my current patch, but can be done as a
follow-on), then we'd need to define two new fields, one to correspond
to the real/raw context string corresponding to the scontext and one to
correspond to the real/raw context string corresponding to the tcontext.
And they would only be present if the scontext and/or tcontext happened
to be invalid under current policy. Maybe "rscontext" and "rtcontext"
if we don't think that will confuse existing userspace
(audit2allow/sepolgen, setroubleshoot, seaudit, ...).
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 17:20 ` Stephen Smalley
@ 2008-05-07 18:45 ` Steve Grubb
-1 siblings, 0 replies; 25+ messages in thread
From: Steve Grubb @ 2008-05-07 18:45 UTC (permalink / raw)
To: Stephen Smalley; +Cc: Eric Paris, linux-audit, James Morris, selinux
On Wednesday 07 May 2008 13:20:42 Stephen Smalley wrote:
> then we'd need to define two new fields, one to correspond
> to the real/raw context string corresponding to the scontext and one to
> correspond to the real/raw context string corresponding to the tcontext.
> And they would only be present if the scontext and/or tcontext happened
> to be invalid under current policy. Maybe "rscontext" and "rtcontext"
> if we don't think that will confuse existing userspace
Sounds good to me. I don't think either names you mentioned are taken.
-Steve
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
@ 2008-05-07 18:45 ` Steve Grubb
0 siblings, 0 replies; 25+ messages in thread
From: Steve Grubb @ 2008-05-07 18:45 UTC (permalink / raw)
To: Stephen Smalley; +Cc: linux-audit, Eric Paris, James Morris, selinux
On Wednesday 07 May 2008 13:20:42 Stephen Smalley wrote:
> then we'd need to define two new fields, one to correspond
> to the real/raw context string corresponding to the scontext and one to
> correspond to the real/raw context string corresponding to the tcontext.
> And they would only be present if the scontext and/or tcontext happened
> to be invalid under current policy. Maybe "rscontext" and "rtcontext"
> if we don't think that will confuse existing userspace
Sounds good to me. I don't think either names you mentioned are taken.
-Steve
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v5] selinux: support deferred mapping of contexts
2008-05-07 17:14 ` Stephen Smalley
@ 2008-05-08 0:08 ` James Morris
0 siblings, 0 replies; 25+ messages in thread
From: James Morris @ 2008-05-08 0:08 UTC (permalink / raw)
To: Stephen Smalley; +Cc: selinux, Eric Paris, Daniel J Walsh
On Wed, 7 May 2008, Stephen Smalley wrote:
> > This version of the patch solves the problem for fscreate by introducing support for obtaining
> > the raw context value for use by selinux_inode_init_security(). The example sequence above
> > has been updated and tested to confirm correct operation for both setxattr() and fscreate usage
> > by exercising both chcon and mkdir -Z. I believe that this patch is now ready for inclusion
> > in -mm and Fedora rawhide kernels for F10. If we want to add support for other aspects like
> > including raw context values in audit messages, conditionally returning them via getxattr for
> > privileged processes, etc. I think we'll do it as separate follow-on patches.
Applied to
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6.git#for-akpm
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
2008-05-07 18:45 ` Steve Grubb
@ 2008-05-08 15:10 ` Stephen Smalley
-1 siblings, 0 replies; 25+ messages in thread
From: Stephen Smalley @ 2008-05-08 15:10 UTC (permalink / raw)
To: Steve Grubb; +Cc: Eric Paris, linux-audit, James Morris, selinux
On Wed, 2008-05-07 at 14:45 -0400, Steve Grubb wrote:
> On Wednesday 07 May 2008 13:20:42 Stephen Smalley wrote:
> > then we'd need to define two new fields, one to correspond
> > to the real/raw context string corresponding to the scontext and one to
> > correspond to the real/raw context string corresponding to the tcontext.
> > And they would only be present if the scontext and/or tcontext happened
> > to be invalid under current policy. Maybe "rscontext" and "rtcontext"
> > if we don't think that will confuse existing userspace
>
> Sounds good to me. I don't think either names you mentioned are taken.
I created a trivial patch to do this, not the way I would do it for
real, just to see what impact if any it has on existing userland. This
generated audit messages like this:
# scontext is not defined by current policy, show rscontext=
type=AVC msg=audit(1210258514.347:48): avc: denied { associate } for pid=3352 comm="chcon" name="bar" dev=dm-1 ino=7210044 scontext=system_u:object_r:unlabeled_t:s0 rscontext=unconfined_u:object_r:foo_exec_t:s0 tcontext=system_u:object_r:fs_t:s0 tclass=filesystem
# tcontext is not defined by current policy, show rtcontext=
type=AVC msg=audit(1210258720.269:56): avc: denied { read } for pid=3415 comm="cat" name="bar" dev=dm-1 ino=7210044 scontext=user_u:user_r:user_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 rtcontext=unconfined_u:object_r:foo_exec_t:s0 tclass=file
audit2allow seemed to handle this fine by ignoring the extra fields.
setroubleshoot appeared to ignore/reject the messages altogether, as it
didn't report them.
seaudit complained about malformed audit.log.
The patch is below, but note that I am not asking for this patch to be
merged - it was just the quick and easy way to experiment with adding
this information. To do it for real, I would create an extended form of
security_sid_to_context_force() that gives back both context strings in
a single call, with the rcontext left NULL if the context was valid
under policy.
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 114b4b4..995d42f 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -199,23 +199,35 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
{
int rc;
- char *scontext;
- u32 scontext_len;
+ char *context, *rcontext;
+ u32 context_len;
- rc = security_sid_to_context(ssid, &scontext, &scontext_len);
+ rc = security_sid_to_context(ssid, &context, &context_len);
if (rc)
audit_log_format(ab, "ssid=%d", ssid);
else {
- audit_log_format(ab, "scontext=%s", scontext);
- kfree(scontext);
+ audit_log_format(ab, "scontext=%s", context);
+ rc = security_sid_to_context_force(ssid, &rcontext, &context_len);
+ if (!rc) {
+ if (strcmp(context, rcontext))
+ audit_log_format(ab, " rscontext=%s", rcontext);
+ kfree(rcontext);
+ }
+ kfree(context);
}
- rc = security_sid_to_context(tsid, &scontext, &scontext_len);
+ rc = security_sid_to_context(tsid, &context, &context_len);
if (rc)
audit_log_format(ab, " tsid=%d", tsid);
else {
- audit_log_format(ab, " tcontext=%s", scontext);
- kfree(scontext);
+ audit_log_format(ab, " tcontext=%s", context);
+ rc = security_sid_to_context_force(tsid, &rcontext, &context_len);
+ if (!rc) {
+ if (strcmp(context, rcontext))
+ audit_log_format(ab, " rtcontext=%s", rcontext);
+ kfree(rcontext);
+ }
+ kfree(context);
}
BUG_ON(tclass >= ARRAY_SIZE(class_to_string) || !class_to_string[tclass]);
--
Stephen Smalley
National Security Agency
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v4] selinux: support deferred mapping of contexts
@ 2008-05-08 15:10 ` Stephen Smalley
0 siblings, 0 replies; 25+ messages in thread
From: Stephen Smalley @ 2008-05-08 15:10 UTC (permalink / raw)
To: Steve Grubb; +Cc: linux-audit, Eric Paris, James Morris, selinux
On Wed, 2008-05-07 at 14:45 -0400, Steve Grubb wrote:
> On Wednesday 07 May 2008 13:20:42 Stephen Smalley wrote:
> > then we'd need to define two new fields, one to correspond
> > to the real/raw context string corresponding to the scontext and one to
> > correspond to the real/raw context string corresponding to the tcontext.
> > And they would only be present if the scontext and/or tcontext happened
> > to be invalid under current policy. Maybe "rscontext" and "rtcontext"
> > if we don't think that will confuse existing userspace
>
> Sounds good to me. I don't think either names you mentioned are taken.
I created a trivial patch to do this, not the way I would do it for
real, just to see what impact if any it has on existing userland. This
generated audit messages like this:
# scontext is not defined by current policy, show rscontext=
type=AVC msg=audit(1210258514.347:48): avc: denied { associate } for pid=3352 comm="chcon" name="bar" dev=dm-1 ino=7210044 scontext=system_u:object_r:unlabeled_t:s0 rscontext=unconfined_u:object_r:foo_exec_t:s0 tcontext=system_u:object_r:fs_t:s0 tclass=filesystem
# tcontext is not defined by current policy, show rtcontext=
type=AVC msg=audit(1210258720.269:56): avc: denied { read } for pid=3415 comm="cat" name="bar" dev=dm-1 ino=7210044 scontext=user_u:user_r:user_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 rtcontext=unconfined_u:object_r:foo_exec_t:s0 tclass=file
audit2allow seemed to handle this fine by ignoring the extra fields.
setroubleshoot appeared to ignore/reject the messages altogether, as it
didn't report them.
seaudit complained about malformed audit.log.
The patch is below, but note that I am not asking for this patch to be
merged - it was just the quick and easy way to experiment with adding
this information. To do it for real, I would create an extended form of
security_sid_to_context_force() that gives back both context strings in
a single call, with the rcontext left NULL if the context was valid
under policy.
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 114b4b4..995d42f 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -199,23 +199,35 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
{
int rc;
- char *scontext;
- u32 scontext_len;
+ char *context, *rcontext;
+ u32 context_len;
- rc = security_sid_to_context(ssid, &scontext, &scontext_len);
+ rc = security_sid_to_context(ssid, &context, &context_len);
if (rc)
audit_log_format(ab, "ssid=%d", ssid);
else {
- audit_log_format(ab, "scontext=%s", scontext);
- kfree(scontext);
+ audit_log_format(ab, "scontext=%s", context);
+ rc = security_sid_to_context_force(ssid, &rcontext, &context_len);
+ if (!rc) {
+ if (strcmp(context, rcontext))
+ audit_log_format(ab, " rscontext=%s", rcontext);
+ kfree(rcontext);
+ }
+ kfree(context);
}
- rc = security_sid_to_context(tsid, &scontext, &scontext_len);
+ rc = security_sid_to_context(tsid, &context, &context_len);
if (rc)
audit_log_format(ab, " tsid=%d", tsid);
else {
- audit_log_format(ab, " tcontext=%s", scontext);
- kfree(scontext);
+ audit_log_format(ab, " tcontext=%s", context);
+ rc = security_sid_to_context_force(tsid, &rcontext, &context_len);
+ if (!rc) {
+ if (strcmp(context, rcontext))
+ audit_log_format(ab, " rtcontext=%s", rcontext);
+ kfree(rcontext);
+ }
+ kfree(context);
}
BUG_ON(tclass >= ARRAY_SIZE(class_to_string) || !class_to_string[tclass]);
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply related [flat|nested] 25+ messages in thread
end of thread, other threads:[~2008-05-08 15:10 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-05 15:43 [PATCH v3] selinux: support deferred mapping of contexts Stephen Smalley
2008-05-05 17:49 ` Stephen Smalley
2008-05-05 23:31 ` James Morris
2008-05-06 15:40 ` [PATCH v4] " Stephen Smalley
2008-05-06 20:17 ` Stephen Smalley
2008-05-06 22:31 ` James Morris
2008-05-07 12:45 ` Stephen Smalley
2008-05-07 13:45 ` James Morris
2008-05-07 15:12 ` Stephen Smalley
2008-05-07 17:03 ` [PATCH v5] " Stephen Smalley
2008-05-07 17:14 ` Stephen Smalley
2008-05-08 0:08 ` James Morris
2008-05-07 15:17 ` [PATCH v4] " Eric Paris
2008-05-07 15:23 ` Stephen Smalley
2008-05-07 15:29 ` Eric Paris
2008-05-07 15:29 ` Eric Paris
2008-05-07 16:48 ` Steve Grubb
2008-05-07 16:48 ` Steve Grubb
2008-05-07 17:20 ` Stephen Smalley
2008-05-07 17:20 ` Stephen Smalley
2008-05-07 18:45 ` Steve Grubb
2008-05-07 18:45 ` Steve Grubb
2008-05-08 15:10 ` Stephen Smalley
2008-05-08 15:10 ` Stephen Smalley
2008-05-07 17:04 ` Daniel J Walsh
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.