* [PATCH 13/58] LSM: Use lsm_export in security_audit_rule_match
From: Casey Schaufler @ 2019-05-31 23:31 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert security_audit_rule_match to use the lsm_export structure
instead of a u32 secid. There is some scaffolding involved that
will be removed when the related data is updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/security.h | 46 +++++++++++++++++++++++++--
kernel/auditfilter.c | 4 ++-
kernel/auditsc.c | 13 +++++---
security/integrity/ima/ima_policy.c | 7 +++--
security/security.c | 48 ++---------------------------
5 files changed, 63 insertions(+), 55 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index fb19f41d630b..ea2c6c4e88db 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -93,6 +93,45 @@ static inline void lsm_export_init(struct lsm_export *l)
memset(l, 0, sizeof(*l));
}
+/**
+ * lsm_export_secid - pull the useful secid out of a lsm_export
+ * @data: the containing data structure
+ * @secid: where to put the one that matters.
+ *
+ * Shim that will disappear when all lsm_export conversions are done.
+ */
+static inline void lsm_export_secid(struct lsm_export *data, u32 *secid)
+{
+ switch (data->flags) {
+ case LSM_EXPORT_NONE:
+ *secid = 0;
+ break;
+ case LSM_EXPORT_SELINUX:
+ *secid = data->selinux;
+ break;
+ case LSM_EXPORT_SMACK:
+ *secid = data->smack;
+ break;
+ case LSM_EXPORT_APPARMOR:
+ *secid = data->apparmor;
+ break;
+ default:
+ pr_warn("%s flags=0x%u - not a valid set\n", __func__,
+ data->flags);
+ *secid = 0;
+ break;
+ }
+}
+
+static inline void lsm_export_to_all(struct lsm_export *data, u32 secid)
+{
+ data->selinux = secid;
+ data->smack = secid;
+ data->apparmor = secid;
+ data->flags = LSM_EXPORT_SELINUX | LSM_EXPORT_SMACK |
+ LSM_EXPORT_APPARMOR;
+}
+
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
int cap, unsigned int opts);
@@ -1712,7 +1751,8 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
#ifdef CONFIG_SECURITY
int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
int security_audit_rule_known(struct audit_krule *krule);
-int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
+int security_audit_rule_match(struct lsm_export *l, u32 field, u32 op,
+ void *lsmrule);
void security_audit_rule_free(void *lsmrule);
#else
@@ -1728,8 +1768,8 @@ static inline int security_audit_rule_known(struct audit_krule *krule)
return 0;
}
-static inline int security_audit_rule_match(u32 secid, u32 field, u32 op,
- void *lsmrule)
+static inline int security_audit_rule_match(struct lsm_export *l, u32 field,
+ u32 op, void *lsmrule)
{
return 0;
}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 63f8b3f26fab..15771102919d 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1324,6 +1324,7 @@ int audit_filter(int msgtype, unsigned int listtype)
struct audit_field *f = &e->rule.fields[i];
pid_t pid;
u32 sid;
+ struct lsm_export le;
switch (f->type) {
case AUDIT_PID:
@@ -1354,7 +1355,8 @@ int audit_filter(int msgtype, unsigned int listtype)
case AUDIT_SUBJ_CLR:
if (f->lsm_rule) {
security_task_getsecid(current, &sid);
- result = security_audit_rule_match(sid,
+ lsm_export_to_all(&le, sid);
+ result = security_audit_rule_match(&le,
f->type, f->op, f->lsm_rule);
}
break;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d1eab1d4a930..822ba35e4e64 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -445,6 +445,7 @@ static int audit_filter_rules(struct task_struct *tsk,
const struct cred *cred;
int i, need_sid = 1;
u32 sid;
+ struct lsm_export le;
unsigned int sessionid;
cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
@@ -630,7 +631,8 @@ static int audit_filter_rules(struct task_struct *tsk,
security_task_getsecid(tsk, &sid);
need_sid = 0;
}
- result = security_audit_rule_match(sid, f->type,
+ lsm_export_to_all(&le, sid);
+ result = security_audit_rule_match(&le, f->type,
f->op,
f->lsm_rule);
}
@@ -645,15 +647,17 @@ static int audit_filter_rules(struct task_struct *tsk,
if (f->lsm_rule) {
/* Find files that match */
if (name) {
+ lsm_export_to_all(&le, name->osid);
result = security_audit_rule_match(
- name->osid,
+ &le,
f->type,
f->op,
f->lsm_rule);
} else if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
+ lsm_export_to_all(&le, n->osid);
if (security_audit_rule_match(
- n->osid,
+ &le,
f->type,
f->op,
f->lsm_rule)) {
@@ -665,7 +669,8 @@ static int audit_filter_rules(struct task_struct *tsk,
/* Find ipc objects that match */
if (!ctx || ctx->type != AUDIT_IPC)
break;
- if (security_audit_rule_match(ctx->ipc.osid,
+ lsm_export_to_all(&le, ctx->ipc.osid);
+ if (security_audit_rule_match(&le,
f->type, f->op,
f->lsm_rule))
++result;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index e0cc323f948f..090ef8ceb116 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -327,6 +327,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
for (i = 0; i < MAX_LSM_RULES; i++) {
int rc = 0;
u32 osid;
+ struct lsm_export le;
int retried = 0;
if (!rule->lsm[i].rule)
@@ -337,7 +338,8 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
case LSM_OBJ_ROLE:
case LSM_OBJ_TYPE:
security_inode_getsecid(inode, &osid);
- rc = security_filter_rule_match(osid,
+ lsm_export_to_all(&le, osid);
+ rc = security_filter_rule_match(&le,
rule->lsm[i].type,
Audit_equal,
rule->lsm[i].rule);
@@ -345,7 +347,8 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
case LSM_SUBJ_USER:
case LSM_SUBJ_ROLE:
case LSM_SUBJ_TYPE:
- rc = security_filter_rule_match(secid,
+ lsm_export_to_all(&le, secid);
+ rc = security_filter_rule_match(&le,
rule->lsm[i].type,
Audit_equal,
rule->lsm[i].rule);
diff --git a/security/security.c b/security/security.c
index 1645ebe06715..1e819ecf26ff 100644
--- a/security/security.c
+++ b/security/security.c
@@ -712,45 +712,6 @@ int lsm_superblock_alloc(struct super_block *sb)
RC; \
})
-/**
- * lsm_export_secid - pull the useful secid out of a lsm_export
- * @data: the containing data structure
- * @secid: where to put the one that matters.
- *
- * Shim that will disappear when all lsm_export conversions are done.
- */
-static inline void lsm_export_secid(struct lsm_export *data, u32 *secid)
-{
- switch (data->flags) {
- case LSM_EXPORT_NONE:
- *secid = 0;
- break;
- case LSM_EXPORT_SELINUX:
- *secid = data->selinux;
- break;
- case LSM_EXPORT_SMACK:
- *secid = data->smack;
- break;
- case LSM_EXPORT_APPARMOR:
- *secid = data->apparmor;
- break;
- default:
- pr_warn("%s flags=0x%u - not a valid set\n", __func__,
- data->flags);
- *secid = 0;
- break;
- }
-}
-
-static inline void lsm_export_to_all(struct lsm_export *data, u32 secid)
-{
- data->selinux = secid;
- data->smack = secid;
- data->apparmor = secid;
- data->flags = LSM_EXPORT_SELINUX | LSM_EXPORT_SMACK |
- LSM_EXPORT_APPARMOR;
-}
-
/* Security operations */
int security_binder_set_context_mgr(struct task_struct *mgr)
@@ -2482,14 +2443,11 @@ void security_audit_rule_free(void *lsmrule)
call_void_hook(audit_rule_free, lsmrule);
}
-int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
+int security_audit_rule_match(struct lsm_export *l, u32 field, u32 op,
+ void *lsmrule)
{
- int rc;
- struct lsm_export data = { .flags = LSM_EXPORT_NONE };
- rc = call_int_hook(audit_rule_match, 0, &data, field, op, lsmrule);
- lsm_export_secid(&data, &secid);
- return rc;
+ return call_int_hook(audit_rule_match, 0, l, field, op, lsmrule);
}
#endif /* CONFIG_AUDIT */
--
2.19.1
^ permalink raw reply related
* [RFC PATCH 2/9] x86/sgx: Do not naturally align MAP_FIXED address
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
SGX enclaves have an associated Enclave Linear Range (ELRANGE) that is
tracked and enforced by the CPU using a base+mask approach, similar to
how hardware range registers such as the variable MTRRs. As a result,
the ELRANGE must be naturally sized and aligned.
To reduce boilerplate code that would be needed in every userspace
enclave loader, the SGX driver naturally aligns the mmap() address and
also requires the range to be naturally sized. Unfortunately, SGX fails
to grant a waiver to the MAP_FIXED case, e.g. incorrectly rejects mmap()
if userspace is attempting to map a small slice of an existing enclave.
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
arch/x86/kernel/cpu/sgx/driver/main.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kernel/cpu/sgx/driver/main.c b/arch/x86/kernel/cpu/sgx/driver/main.c
index afe844aa81d6..129d356aff30 100644
--- a/arch/x86/kernel/cpu/sgx/driver/main.c
+++ b/arch/x86/kernel/cpu/sgx/driver/main.c
@@ -79,7 +79,13 @@ static unsigned long sgx_get_unmapped_area(struct file *file,
unsigned long pgoff,
unsigned long flags)
{
- if (len < 2 * PAGE_SIZE || len & (len - 1) || flags & MAP_PRIVATE)
+ if (flags & MAP_PRIVATE)
+ return -EINVAL;
+
+ if (flags & MAP_FIXED)
+ return addr;
+
+ if (len < 2 * PAGE_SIZE || len & (len - 1))
return -EINVAL;
addr = current->mm->get_unmapped_area(file, addr, 2 * len, pgoff,
--
2.21.0
^ permalink raw reply related
* [RFC PATCH 0/9] security: x86/sgx: SGX vs. LSM
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
This series is the result of a rather absurd amount of discussion over
how to get SGX to play nice with LSM policies, without having to resort
to evil shenanigans or put undue burden on userspace. The discussion
definitely wandered into completely insane territory at times, but I
think/hope we ended up with something reasonable.
The basic gist of the approach is to require userspace to declare what
protections are maximally allowed for any given page, e.g. add a flags
field for loading enclave pages that takes ALLOW_{READ,WRITE,EXEC}. LSMs
can then adjust the allowed protections, e.g. clear ALLOW_EXEC to prevent
ever mapping the page with PROT_EXEC. SGX enforces the allowed perms
via a new mprotect() vm_ops hook, e.g. like regular mprotect() uses
MAY_{READ,WRITE,EXEC}.
ALLOW_EXEC is used to deny hings like loading an enclave from a noexec
file system or from a file without EXECUTE permissions, e.g. without
the ALLOW_EXEC concept, on SGX2 hardware (regardless of kernel support)
userspace could EADD from a noexec file using read-only permissions,
and later use mprotect() and ENCLU[EMODPE] to gain execute permissions.
ALLOW_WRITE is used in conjuction with ALLOW_EXEC to enforce SELinux's
EXECMOD (or EXECMEM).
This is very much an RFC series. It's only compile tested, likely has
obvious bugs, the SELinux patch could be completely harebrained, etc...
My goal at this point is to get feedback at a macro level, e.g. is the
core concept viable/acceptable, are there objection to hooking
mprotect(), etc...
Andy and Cedric, hopefully this aligns with your general expectations
based on our last discussion.
Lastly, I added a patch to allow userspace to add multiple pages in a
single ioctl(). It's obviously not directly related to the security
stuff, but the idea tangentially came up during earlier discussions and
it's something I think the UAPI should provide (it's a tiny change).
Since I was modifying the UAPI anyways, I threw it in.
Sean Christopherson (9):
x86/sgx: Remove unused local variable in sgx_encl_release()
x86/sgx: Do not naturally align MAP_FIXED address
x86/sgx: Allow userspace to add multiple pages in single ioctl()
mm: Introduce vm_ops->mprotect()
x86/sgx: Restrict mapping without an enclave page to PROT_NONE
x86/sgx: Require userspace to provide allowed prots to ADD_PAGES
x86/sgx: Enforce noexec filesystem restriction for enclaves
LSM: x86/sgx: Introduce ->enclave_load() hook for Intel SGX
security/selinux: Add enclave_load() implementation
arch/x86/include/uapi/asm/sgx.h | 30 ++++--
arch/x86/kernel/cpu/sgx/driver/ioctl.c | 143 +++++++++++++++++--------
arch/x86/kernel/cpu/sgx/driver/main.c | 13 ++-
arch/x86/kernel/cpu/sgx/encl.c | 31 +++++-
arch/x86/kernel/cpu/sgx/encl.h | 4 +
include/linux/lsm_hooks.h | 16 +++
include/linux/mm.h | 2 +
include/linux/security.h | 2 +
mm/mprotect.c | 15 ++-
security/security.c | 8 ++
security/selinux/hooks.c | 85 +++++++++++++++
11 files changed, 290 insertions(+), 59 deletions(-)
--
2.21.0
^ permalink raw reply
* [PATCH 12/58] LSM: Use lsm_export in the secctx_to_secid hooks
From: Casey Schaufler @ 2019-05-31 23:31 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert the secctx_to_secid hooks to use the lsm_export
structure instead of a u32 secid. There is some scaffolding
involved that will be removed when security_secctx_to_secid()
is updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 7 ++++---
security/apparmor/include/secid.h | 3 ++-
security/apparmor/secid.c | 9 +++++----
security/security.c | 8 ++++++--
security/selinux/hooks.c | 12 +++++++++---
security/smack/smack_lsm.c | 7 ++++---
6 files changed, 30 insertions(+), 16 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 433d98dcb928..0837c214cc17 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1324,8 +1324,8 @@
* context.
* @seclen pointer which contains the length of the data
* @secctx_to_secid:
- * Convert security context to secid.
- * @secid contains the pointer to the generated security ID.
+ * Convert security context to exported lsm data.
+ * @l contains the pointer to the generated security data.
* @secdata contains the security context.
*
* @release_secctx:
@@ -1666,7 +1666,8 @@ union security_list_options {
int (*ismaclabel)(const char *name);
int (*secid_to_secctx)(struct lsm_export *l, char **secdata,
u32 *seclen);
- int (*secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid);
+ int (*secctx_to_secid)(const char *secdata, u32 seclen,
+ struct lsm_export *l);
void (*release_secctx)(char *secdata, u32 seclen);
void (*inode_invalidate_secctx)(struct inode *inode);
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
index 03369183f512..5381eff03d4f 100644
--- a/security/apparmor/include/secid.h
+++ b/security/apparmor/include/secid.h
@@ -27,7 +27,8 @@ struct aa_label;
struct aa_label *aa_secid_to_label(struct lsm_export *l);
int apparmor_secid_to_secctx(struct lsm_export *l, char **secdata, u32 *seclen);
-int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
+int apparmor_secctx_to_secid(const char *secdata, u32 seclen,
+ struct lsm_export *l);
void apparmor_release_secctx(char *secdata, u32 seclen);
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index ab4dc165e43e..69d98a89db75 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -75,9 +75,9 @@ struct aa_label *aa_secid_to_label(struct lsm_export *l)
return label;
}
-static inline void aa_import_secid(struct lsm_export *l, u32 secid)
+static inline void aa_export_secid(struct lsm_export *l, u32 secid)
{
- l->flags = LSM_EXPORT_APPARMOR;
+ l->flags |= LSM_EXPORT_APPARMOR;
l->apparmor = secid;
}
@@ -111,7 +111,8 @@ int apparmor_secid_to_secctx(struct lsm_export *l, char **secdata, u32 *seclen)
return 0;
}
-int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
+int apparmor_secctx_to_secid(const char *secdata, u32 seclen,
+ struct lsm_export *l)
{
struct aa_label *label;
@@ -119,7 +120,7 @@ int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
seclen, GFP_KERNEL, false, false);
if (IS_ERR(label))
return PTR_ERR(label);
- *secid = label->secid;
+ aa_export_secid(l, label->secid);
return 0;
}
diff --git a/security/security.c b/security/security.c
index adf4cb768665..1645ebe06715 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2012,8 +2012,12 @@ EXPORT_SYMBOL(security_secid_to_secctx);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
- *secid = 0;
- return call_int_hook(secctx_to_secid, 0, secdata, seclen, secid);
+ struct lsm_export data = { .flags = LSM_EXPORT_NONE };
+ int rc;
+
+ rc = call_int_hook(secctx_to_secid, 0, secdata, seclen, &data);
+ lsm_export_secid(&data, secid);
+ return rc;
}
EXPORT_SYMBOL(security_secctx_to_secid);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 16d902158e8a..7dd333f133db 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6311,10 +6311,16 @@ static int selinux_secid_to_secctx(struct lsm_export *l, char **secdata,
secdata, seclen);
}
-static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
+static int selinux_secctx_to_secid(const char *secdata, u32 seclen,
+ struct lsm_export *l)
{
- return security_context_to_sid(&selinux_state, secdata, seclen,
- secid, GFP_KERNEL);
+ u32 secid;
+ int rc;
+
+ rc = security_context_to_sid(&selinux_state, secdata, seclen,
+ &secid, GFP_KERNEL);
+ selinux_export_secid(l, secid);
+ return rc;
}
static void selinux_release_secctx(char *secdata, u32 seclen)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 809af981f14c..ecd636e5c75c 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4456,14 +4456,15 @@ static int smack_secid_to_secctx(struct lsm_export *l, char **secdata,
*
* Exists for audit and networking code.
*/
-static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
+static int smack_secctx_to_secid(const char *secdata, u32 seclen,
+ struct lsm_export *l)
{
struct smack_known *skp = smk_find_entry(secdata);
if (skp)
- *secid = skp->smk_secid;
+ smack_export_secid(l, skp->smk_secid);
else
- *secid = 0;
+ smack_export_secid(l, 0);
return 0;
}
--
2.19.1
^ permalink raw reply related
* [RFC PATCH 3/9] x86/sgx: Allow userspace to add multiple pages in single ioctl()
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
...to improve performance when building enclaves by reducing the number
of user<->system transitions. Rather than provide arbitrary batching,
e.g. with per-page SECINFO and mrmask, take advantage of the fact that
any sane enclave will have large swaths of pages with identical
properties, e.g. code vs. data sections.
For simplicity and stability in the initial implementation, loop over
the existing add page flow instead of taking a more agressive approach,
which would require tracking transitions between VMAs and holding
mmap_sem for an extended duration.
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
arch/x86/include/uapi/asm/sgx.h | 21 ++---
arch/x86/kernel/cpu/sgx/driver/ioctl.c | 104 +++++++++++++++----------
2 files changed, 74 insertions(+), 51 deletions(-)
diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
index 9ed690a38c70..4a12d6abbcb7 100644
--- a/arch/x86/include/uapi/asm/sgx.h
+++ b/arch/x86/include/uapi/asm/sgx.h
@@ -12,8 +12,8 @@
#define SGX_IOC_ENCLAVE_CREATE \
_IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create)
-#define SGX_IOC_ENCLAVE_ADD_PAGE \
- _IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page)
+#define SGX_IOC_ENCLAVE_ADD_PAGES \
+ _IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_pages)
#define SGX_IOC_ENCLAVE_INIT \
_IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init)
#define SGX_IOC_ENCLAVE_SET_ATTRIBUTE \
@@ -32,21 +32,22 @@ struct sgx_enclave_create {
};
/**
- * struct sgx_enclave_add_page - parameter structure for the
- * %SGX_IOC_ENCLAVE_ADD_PAGE ioctl
- * @addr: address within the ELRANGE
- * @src: address for the page data
- * @secinfo: address for the SECINFO data
- * @mrmask: bitmask for the measured 256 byte chunks
+ * struct sgx_enclave_add_pages - parameter structure for the
+ * %SGX_IOC_ENCLAVE_ADD_PAGES ioctl
+ * @addr: start address within the ELRANGE
+ * @src: start address for the pages' data
+ * @secinfo: address for the SECINFO data (common to all pages)
+ * @nr_pages: number of pages (must be virtually contiguous)
+ * @mrmask: bitmask for the measured 256 byte chunks (common to all pages)
*/
-struct sgx_enclave_add_page {
+struct sgx_enclave_add_pages {
__u64 addr;
__u64 src;
__u64 secinfo;
+ __u32 nr_pages;
__u16 mrmask;
} __attribute__((__packed__));
-
/**
* struct sgx_enclave_init - parameter structure for the
* %SGX_IOC_ENCLAVE_INIT ioctl
diff --git a/arch/x86/kernel/cpu/sgx/driver/ioctl.c b/arch/x86/kernel/cpu/sgx/driver/ioctl.c
index a27ec26a9350..6acfcbdeca9a 100644
--- a/arch/x86/kernel/cpu/sgx/driver/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/driver/ioctl.c
@@ -487,10 +487,9 @@ static int sgx_validate_tcs(struct sgx_encl *encl, struct sgx_tcs *tcs)
return 0;
}
-static int __sgx_encl_add_page(struct sgx_encl *encl,
+static int sgx_encl_queue_page(struct sgx_encl *encl,
struct sgx_encl_page *encl_page,
- void *data,
- struct sgx_secinfo *secinfo,
+ void *data, struct sgx_secinfo *secinfo,
unsigned int mrmask)
{
unsigned long page_index = sgx_encl_get_index(encl, encl_page);
@@ -529,9 +528,9 @@ static int __sgx_encl_add_page(struct sgx_encl *encl,
return 0;
}
-static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
- void *data, struct sgx_secinfo *secinfo,
- unsigned int mrmask)
+static int __sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
+ void *data, struct sgx_secinfo *secinfo,
+ unsigned int mrmask)
{
u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK;
struct sgx_encl_page *encl_page;
@@ -563,7 +562,7 @@ static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
goto out;
}
- ret = __sgx_encl_add_page(encl, encl_page, data, secinfo, mrmask);
+ ret = sgx_encl_queue_page(encl, encl_page, data, secinfo, mrmask);
if (ret) {
radix_tree_delete(&encl_page->encl->page_tree,
PFN_DOWN(encl_page->desc));
@@ -575,56 +574,79 @@ static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
return ret;
}
-/**
- * sgx_ioc_enclave_add_page - handler for %SGX_IOC_ENCLAVE_ADD_PAGE
- *
- * @filep: open file to /dev/sgx
- * @cmd: the command value
- * @arg: pointer to an &sgx_enclave_add_page instance
- *
- * Add a page to an uninitialized enclave (EADD), and optionally extend the
- * enclave's measurement with the contents of the page (EEXTEND). EADD and
- * EEXTEND are done asynchronously via worker threads. A successful
- * sgx_ioc_enclave_add_page() only indicates the page has been added to the
- * work queue, it does not guarantee adding the page to the enclave will
- * succeed.
- *
- * Return:
- * 0 on success,
- * -errno otherwise
- */
-static long sgx_ioc_enclave_add_page(struct file *filep, unsigned int cmd,
- unsigned long arg)
+static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
+ unsigned long src, struct sgx_secinfo *secinfo,
+ unsigned int mrmask)
{
- struct sgx_enclave_add_page *addp = (void *)arg;
- struct sgx_encl *encl = filep->private_data;
- struct sgx_secinfo secinfo;
struct page *data_page;
void *data;
int ret;
- if (copy_from_user(&secinfo, (void __user *)addp->secinfo,
- sizeof(secinfo)))
- return -EFAULT;
-
data_page = alloc_page(GFP_HIGHUSER);
if (!data_page)
return -ENOMEM;
data = kmap(data_page);
- if (copy_from_user((void *)data, (void __user *)addp->src, PAGE_SIZE)) {
+ if (copy_from_user((void *)data, (void __user *)src, PAGE_SIZE)) {
ret = -EFAULT;
goto out;
}
- ret = sgx_encl_add_page(encl, addp->addr, data, &secinfo, addp->mrmask);
- if (ret)
- goto out;
-
+ ret = __sgx_encl_add_page(encl, addr, data, secinfo, mrmask);
out:
kunmap(data_page);
__free_page(data_page);
+
+ return ret;
+}
+
+/**
+ * sgx_ioc_enclave_add_pages - handler for %SGX_IOC_ENCLAVE_ADD_PAGES
+ *
+ * @filep: open file to /dev/sgx
+ * @cmd: the command value
+ * @arg: pointer to an &sgx_enclave_add_page instance
+ *
+ * Add a range of pages to an uninitialized enclave (EADD), and optionally
+ * extend the enclave's measurement with the contents of the page (EEXTEND).
+ * The range of pages must be virtually contiguous. The SECINFO and
+ * measurement maskare applied to all pages, i.e. pages with different
+ * properties must be added in separate calls.
+ *
+ * EADD and EEXTEND are done asynchronously via worker threads. A successful
+ * sgx_ioc_enclave_add_page() only indicates the pages have been added to the
+ * work queue, it does not guarantee adding the pages to the enclave will
+ * succeed.
+ *
+ * Return:
+ * 0 on success,
+ * -errno otherwise
+ */
+static long sgx_ioc_enclave_add_pages(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sgx_enclave_add_pages *addp = (void *)arg;
+ struct sgx_encl *encl = filep->private_data;
+ struct sgx_secinfo secinfo;
+ unsigned int i;
+ int ret;
+
+ if (copy_from_user(&secinfo, (void __user *)addp->secinfo,
+ sizeof(secinfo)))
+ return -EFAULT;
+
+ for (i = 0, ret = 0; i < addp->nr_pages && !ret; i++) {
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ if (need_resched())
+ cond_resched();
+
+ ret = sgx_encl_add_page(encl, addp->addr + i*PAGE_SIZE,
+ addp->src + i*PAGE_SIZE,
+ &secinfo, addp->mrmask);
+ }
return ret;
}
@@ -823,8 +845,8 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
case SGX_IOC_ENCLAVE_CREATE:
handler = sgx_ioc_enclave_create;
break;
- case SGX_IOC_ENCLAVE_ADD_PAGE:
- handler = sgx_ioc_enclave_add_page;
+ case SGX_IOC_ENCLAVE_ADD_PAGES:
+ handler = sgx_ioc_enclave_add_pages;
break;
case SGX_IOC_ENCLAVE_INIT:
handler = sgx_ioc_enclave_init;
--
2.21.0
^ permalink raw reply related
* [PATCH 10/58] LSM: Use lsm_export in the audit_rule_match hooks
From: Casey Schaufler @ 2019-05-31 23:31 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert the audit_rule_match hooks to use the lsm_export
structure instead of a u32 secid. There is quite a bit of scaffolding
involved that will be removed when security_audit_rule_match()
is updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 5 +++--
security/apparmor/audit.c | 4 ++--
security/apparmor/include/audit.h | 2 +-
security/apparmor/include/secid.h | 2 +-
security/apparmor/secid.c | 17 +++++++++++++++--
security/security.c | 7 ++++++-
security/selinux/hooks.c | 17 -----------------
security/selinux/include/audit.h | 5 +++--
security/selinux/include/objsec.h | 17 +++++++++++++++++
security/selinux/ss/services.c | 6 +++++-
security/smack/smack_lsm.c | 7 +++++--
11 files changed, 58 insertions(+), 31 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index bcc628cffe6a..01296e4ce474 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1354,7 +1354,7 @@
* @audit_rule_match:
* Determine if given @secid matches a rule previously approved
* by @audit_rule_known.
- * @secid contains the security id in question.
+ * @l points to the security data in question.
* @field contains the field which relates to current LSM.
* @op contains the operator that will be used for matching.
* @lrule points to the audit rule that will be checked against.
@@ -1778,7 +1778,8 @@ union security_list_options {
int (*audit_rule_init)(u32 field, u32 op, char *rulestr,
void **lsmrule);
int (*audit_rule_known)(struct audit_krule *krule);
- int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule);
+ int (*audit_rule_match)(struct lsm_export *l, u32 field, u32 op,
+ void *lsmrule);
void (*audit_rule_free)(void *lsmrule);
#endif /* CONFIG_AUDIT */
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 5a8b9cded4f2..bea59bfad332 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -225,13 +225,13 @@ int aa_audit_rule_known(struct audit_krule *rule)
return 0;
}
-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
+int aa_audit_rule_match(struct lsm_export *l, u32 field, u32 op, void *vrule)
{
struct aa_audit_rule *rule = vrule;
struct aa_label *label;
int found = 0;
- label = aa_secid_to_label(sid);
+ label = aa_secid_to_label(l);
if (!label)
return -ENOENT;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index ee559bc2acb8..372ba4fada9c 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -192,6 +192,6 @@ static inline int complain_error(int error)
void aa_audit_rule_free(void *vrule);
int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
int aa_audit_rule_known(struct audit_krule *rule);
-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
+int aa_audit_rule_match(struct lsm_export *l, u32 field, u32 op, void *vrule);
#endif /* __AA_AUDIT_H */
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
index fa2062711b63..c283c620efe3 100644
--- a/security/apparmor/include/secid.h
+++ b/security/apparmor/include/secid.h
@@ -25,7 +25,7 @@ struct aa_label;
/* secid value that matches any other secid */
#define AA_SECID_WILDCARD 1
-struct aa_label *aa_secid_to_label(u32 secid);
+struct aa_label *aa_secid_to_label(struct lsm_export *l);
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void apparmor_release_secctx(char *secdata, u32 seclen);
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 05373d9a3d6a..1546c45a2a18 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -61,9 +61,12 @@ void aa_secid_update(u32 secid, struct aa_label *label)
*
* see label for inverse aa_label_to_secid
*/
-struct aa_label *aa_secid_to_label(u32 secid)
+struct aa_label *aa_secid_to_label(struct lsm_export *l)
{
struct aa_label *label;
+ u32 secid;
+
+ secid = (l->flags & LSM_EXPORT_APPARMOR) ? l->apparmor : 0;
rcu_read_lock();
label = idr_find(&aa_secids, secid);
@@ -72,12 +75,22 @@ struct aa_label *aa_secid_to_label(u32 secid)
return label;
}
+static inline void aa_import_secid(struct lsm_export *l, u32 secid)
+{
+ l->flags = LSM_EXPORT_APPARMOR;
+ l->apparmor = secid;
+}
+
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
/* TODO: cache secctx and ref count so we don't have to recreate */
- struct aa_label *label = aa_secid_to_label(secid);
+ struct lsm_export data;
+ struct aa_label *label;
int len;
+ aa_import_secid(&data, secid);
+ label = aa_secid_to_label(&data);
+
AA_BUG(!seclen);
if (!label)
diff --git a/security/security.c b/security/security.c
index 2f1355d10e0d..60dd064c0531 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2477,7 +2477,12 @@ void security_audit_rule_free(void *lsmrule)
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
{
- return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
+ int rc;
+ struct lsm_export data = { .flags = LSM_EXPORT_NONE };
+
+ rc = call_int_hook(audit_rule_match, 0, &data, field, op, lsmrule);
+ lsm_export_secid(&data, &secid);
+ return rc;
}
#endif /* CONFIG_AUDIT */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9db12f6b1221..bfd0f1f5979f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -213,23 +213,6 @@ static void cred_init_security(void)
tsec->osid = tsec->sid = SECINITSID_KERNEL;
}
-/*
- * Set the SELinux secid in an lsm_export structure
- */
-static inline void selinux_export_secid(struct lsm_export *l, u32 secid)
-{
- l->selinux = secid;
- l->flags |= LSM_EXPORT_SELINUX;
-}
-
-static inline void selinux_import_secid(struct lsm_export *l, u32 *secid)
-{
- if (l->flags & LSM_EXPORT_SELINUX)
- *secid = l->selinux;
- else
- *secid = SECSID_NULL;
-}
-
/*
* get the security ID of a set of credentials
*/
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 682e2b5de2a4..92dd5ab15fb2 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -39,7 +39,7 @@ void selinux_audit_rule_free(void *rule);
/**
* selinux_audit_rule_match - determine if a context ID matches a rule.
- * @sid: the context ID to check
+ * @l: points to the context ID to check
* @field: the field this rule refers to
* @op: the operater the rule uses
* @rule: pointer to the audit rule to check against
@@ -47,7 +47,8 @@ void selinux_audit_rule_free(void *rule);
* Returns 1 if the context id matches the rule, 0 if it does not, and
* -errno on failure.
*/
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
+int selinux_audit_rule_match(struct lsm_export *l, u32 field, u32 op,
+ void *rule);
/**
* selinux_audit_rule_known - check to see if rule contains selinux fields.
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 3b78aa4ee98f..59a3b1cd5ba9 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -50,6 +50,23 @@ static inline u32 current_sid(void)
return tsec->sid;
}
+/*
+ * Set the SELinux secid in an lsm_export structure
+ */
+static inline void selinux_export_secid(struct lsm_export *l, u32 secid)
+{
+ l->selinux = secid;
+ l->flags |= LSM_EXPORT_SELINUX;
+}
+
+static inline void selinux_import_secid(struct lsm_export *l, u32 *secid)
+{
+ if (l->flags & LSM_EXPORT_SELINUX)
+ *secid = l->selinux;
+ else
+ *secid = SECSID_NULL;
+}
+
enum label_initialized {
LABEL_INVALID, /* invalid or not initialized */
LABEL_INITIALIZED, /* initialized */
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index e3f5d6aece66..626b877363fb 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3395,13 +3395,15 @@ int selinux_audit_rule_known(struct audit_krule *rule)
return 0;
}
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
+int selinux_audit_rule_match(struct lsm_export *l, u32 field, u32 op,
+ void *vrule)
{
struct selinux_state *state = &selinux_state;
struct context *ctxt;
struct mls_level *level;
struct selinux_audit_rule *rule = vrule;
int match = 0;
+ u32 sid;
if (unlikely(!rule)) {
WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
@@ -3415,6 +3417,8 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
goto out;
}
+ selinux_import_secid(l, &sid);
+
ctxt = sidtab_search(state->ss->sidtab, sid);
if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3e3724bbd6ea..a3776501965d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4369,7 +4369,7 @@ static int smack_audit_rule_known(struct audit_krule *krule)
/**
* smack_audit_rule_match - Audit given object ?
- * @secid: security id for identifying the object to test
+ * @l: security id for identifying the object to test
* @field: audit rule flags given from user-space
* @op: required testing operator
* @vrule: smack internal rule presentation
@@ -4377,10 +4377,12 @@ static int smack_audit_rule_known(struct audit_krule *krule)
* The core Audit hook. It's used to take the decision of
* whether to audit or not to audit a given object.
*/
-static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
+static int smack_audit_rule_match(struct lsm_export *l, u32 field, u32 op,
+ void *vrule)
{
struct smack_known *skp;
char *rule = vrule;
+ u32 secid;
if (unlikely(!rule)) {
WARN_ONCE(1, "Smack: missing rule\n");
@@ -4390,6 +4392,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
return 0;
+ smack_import_secid(l, &secid);
skp = smack_from_secid(secid);
/*
--
2.19.1
^ permalink raw reply related
* [PATCH 11/58] LSM: Use lsm_export in the secid_to_secctx hooks
From: Casey Schaufler @ 2019-05-31 23:31 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert the secid_to_secctx hooks to use the lsm_export
structure instead of a u32 secid. There is some scaffolding
involved that will be removed when security_secid_to_secctx()
is updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 5 +++--
security/apparmor/include/secid.h | 2 +-
security/apparmor/secid.c | 6 ++----
security/security.c | 5 ++++-
security/selinux/hooks.c | 6 +++++-
security/smack/smack_lsm.c | 9 +++++++--
6 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 01296e4ce474..433d98dcb928 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1319,7 +1319,7 @@
* This does mean that the length could change between calls to check the
* length and the next call which actually allocates and returns the
* secdata.
- * @secid contains the security ID.
+ * @l points to the security information.
* @secdata contains the pointer that stores the converted security
* context.
* @seclen pointer which contains the length of the data
@@ -1664,7 +1664,8 @@ union security_list_options {
int (*getprocattr)(struct task_struct *p, char *name, char **value);
int (*setprocattr)(const char *name, void *value, size_t size);
int (*ismaclabel)(const char *name);
- int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen);
+ int (*secid_to_secctx)(struct lsm_export *l, char **secdata,
+ u32 *seclen);
int (*secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid);
void (*release_secctx)(char *secdata, u32 seclen);
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
index c283c620efe3..03369183f512 100644
--- a/security/apparmor/include/secid.h
+++ b/security/apparmor/include/secid.h
@@ -26,7 +26,7 @@ struct aa_label;
#define AA_SECID_WILDCARD 1
struct aa_label *aa_secid_to_label(struct lsm_export *l);
-int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
+int apparmor_secid_to_secctx(struct lsm_export *l, char **secdata, u32 *seclen);
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void apparmor_release_secctx(char *secdata, u32 seclen);
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 1546c45a2a18..ab4dc165e43e 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -81,15 +81,13 @@ static inline void aa_import_secid(struct lsm_export *l, u32 secid)
l->apparmor = secid;
}
-int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+int apparmor_secid_to_secctx(struct lsm_export *l, char **secdata, u32 *seclen)
{
/* TODO: cache secctx and ref count so we don't have to recreate */
- struct lsm_export data;
struct aa_label *label;
int len;
- aa_import_secid(&data, secid);
- label = aa_secid_to_label(&data);
+ label = aa_secid_to_label(l);
AA_BUG(!seclen);
diff --git a/security/security.c b/security/security.c
index 60dd064c0531..adf4cb768665 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2002,7 +2002,10 @@ EXPORT_SYMBOL(security_ismaclabel);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
- return call_int_hook(secid_to_secctx, -EOPNOTSUPP, secid, secdata,
+ struct lsm_export data;
+
+ lsm_export_to_all(&data, secid);
+ return call_int_hook(secid_to_secctx, -EOPNOTSUPP, &data, secdata,
seclen);
}
EXPORT_SYMBOL(security_secid_to_secctx);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index bfd0f1f5979f..16d902158e8a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6301,8 +6301,12 @@ static int selinux_ismaclabel(const char *name)
return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
}
-static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+static int selinux_secid_to_secctx(struct lsm_export *l, char **secdata,
+ u32 *seclen)
{
+ u32 secid;
+
+ selinux_import_secid(l, &secid);
return security_sid_to_context(&selinux_state, secid,
secdata, seclen);
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a3776501965d..809af981f14c 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4433,9 +4433,14 @@ static int smack_ismaclabel(const char *name)
*
* Exists for networking code.
*/
-static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+static int smack_secid_to_secctx(struct lsm_export *l, char **secdata,
+ u32 *seclen)
{
- struct smack_known *skp = smack_from_secid(secid);
+ struct smack_known *skp;
+ u32 secid;
+
+ smack_import_secid(l, &secid);
+ skp = smack_from_secid(secid);
if (secdata)
*secdata = skp->smk_known;
--
2.19.1
^ permalink raw reply related
* [RFC PATCH 6/9] x86/sgx: Require userspace to provide allowed prots to ADD_PAGES
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
...to support (the equivalent) of existing Linux Security Module
functionality.
Because SGX manually manages EPC memory, all enclave VMAs are backed by
the same vm_file, i.e. /dev/sgx/enclave, so that SGX can implement the
necessary hooks to move pages in/out of the EPC. And because EPC pages
for any given enclave are fundamentally shared between processes, i.e.
CoW semantics are not possible with EPC pages, /dev/sgx/enclave must
always be MAP_SHARED. Lastly, all real world enclaves will need read,
write and execute permissions to EPC pages. As a result, SGX does not
play nice with existing LSM behavior as it is impossible to apply
policies to enclaves with any reasonable granularity, e.g. an LSM can
deny access to EPC altogether, but can't deny potentially dangerous
behavior such as mapping pages RW->RW or RWX.
To give LSMs enough information to implement their policies without
having to resort to ugly things, e.g. holding a reference to the vm_file
of each enclave page, require userspace to explicitly state the allowed
protections for each page (region), i.e. take ALLOW_{READ,WRITE,EXEC}
in the ADD_PAGES ioctl.
The ALLOW_* flags will be passed to LSMs so that they can make informed
decisions when the enclave is being built, i.e. when the source vm_file
is available. For example, SELinux's EXECMOD permission can be
required if an enclave is requesting both ALLOW_WRITE and ALLOW_EXEC.
Update the mmap()/mprotect() hooks to enforce the ALLOW_* protections,
a la the standard VM_MAY{READ,WRITE,EXEC} flags.
The ALLOW_EXEC flag also has a second (important) use in that it can
be used to prevent loading an enclave from a noexec file system, on
SGX2 hardware (regardless of kernel support for SGX2), userspace could
EADD from a noexec path using read-only permissions and later mprotect()
and ENCLU[EMODPE] the page to gain execute permissions. By requiring
ALLOW_EXEC up front, SGX will be able to enforce noexec paths when
building the enclave.
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
arch/x86/include/uapi/asm/sgx.h | 9 ++++++++-
arch/x86/kernel/cpu/sgx/driver/ioctl.c | 23 +++++++++++++++++------
arch/x86/kernel/cpu/sgx/encl.c | 2 +-
arch/x86/kernel/cpu/sgx/encl.h | 1 +
4 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
index 4a12d6abbcb7..4489e92fa0dc 100644
--- a/arch/x86/include/uapi/asm/sgx.h
+++ b/arch/x86/include/uapi/asm/sgx.h
@@ -31,6 +31,11 @@ struct sgx_enclave_create {
__u64 src;
};
+/* Supported flags for struct sgx_enclave_add_pages. */
+#define SGX_ALLOW_READ VM_READ
+#define SGX_ALLOW_WRITE VM_WRITE
+#define SGX_ALLOW_EXEC VM_EXEC
+
/**
* struct sgx_enclave_add_pages - parameter structure for the
* %SGX_IOC_ENCLAVE_ADD_PAGES ioctl
@@ -39,6 +44,7 @@ struct sgx_enclave_create {
* @secinfo: address for the SECINFO data (common to all pages)
* @nr_pages: number of pages (must be virtually contiguous)
* @mrmask: bitmask for the measured 256 byte chunks (common to all pages)
+ * @flags: flags, e.g. SGX_ALLOW_{READ,WRITE,EXEC} (common to all pages)
*/
struct sgx_enclave_add_pages {
__u64 addr;
@@ -46,7 +52,8 @@ struct sgx_enclave_add_pages {
__u64 secinfo;
__u32 nr_pages;
__u16 mrmask;
-} __attribute__((__packed__));
+ __u16 flags;
+};
/**
* struct sgx_enclave_init - parameter structure for the
diff --git a/arch/x86/kernel/cpu/sgx/driver/ioctl.c b/arch/x86/kernel/cpu/sgx/driver/ioctl.c
index 6acfcbdeca9a..c30acd3fbbdd 100644
--- a/arch/x86/kernel/cpu/sgx/driver/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/driver/ioctl.c
@@ -235,7 +235,8 @@ static int sgx_validate_secs(const struct sgx_secs *secs,
}
static struct sgx_encl_page *sgx_encl_page_alloc(struct sgx_encl *encl,
- unsigned long addr)
+ unsigned long addr,
+ unsigned long allowed_prot)
{
struct sgx_encl_page *encl_page;
int ret;
@@ -247,6 +248,7 @@ static struct sgx_encl_page *sgx_encl_page_alloc(struct sgx_encl *encl,
return ERR_PTR(-ENOMEM);
encl_page->desc = addr;
encl_page->encl = encl;
+ encl_page->allowed_prot = allowed_prot;
ret = radix_tree_insert(&encl->page_tree, PFN_DOWN(encl_page->desc),
encl_page);
if (ret) {
@@ -530,7 +532,7 @@ static int sgx_encl_queue_page(struct sgx_encl *encl,
static int __sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
void *data, struct sgx_secinfo *secinfo,
- unsigned int mrmask)
+ unsigned int mrmask, unsigned long allowed_prot)
{
u64 page_type = secinfo->flags & SGX_SECINFO_PAGE_TYPE_MASK;
struct sgx_encl_page *encl_page;
@@ -556,7 +558,7 @@ static int __sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
goto out;
}
- encl_page = sgx_encl_page_alloc(encl, addr);
+ encl_page = sgx_encl_page_alloc(encl, addr, allowed_prot);
if (IS_ERR(encl_page)) {
ret = PTR_ERR(encl_page);
goto out;
@@ -576,12 +578,20 @@ static int __sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
unsigned long src, struct sgx_secinfo *secinfo,
- unsigned int mrmask)
+ unsigned int mrmask, unsigned int flags)
{
+ unsigned long prot = secinfo->flags & (VM_READ | VM_WRITE | VM_EXEC);
+ unsigned long allowed_prot = flags & (VM_READ | VM_WRITE | VM_EXEC);
struct page *data_page;
void *data;
int ret;
+ BUILD_BUG_ON(SGX_SECINFO_R != VM_READ || SGX_SECINFO_W != VM_WRITE ||
+ SGX_SECINFO_X != VM_EXEC);
+
+ if (prot & ~allowed_prot)
+ return -EACCES;
+
data_page = alloc_page(GFP_HIGHUSER);
if (!data_page)
return -ENOMEM;
@@ -593,7 +603,8 @@ static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
goto out;
}
- ret = __sgx_encl_add_page(encl, addr, data, secinfo, mrmask);
+ ret = __sgx_encl_add_page(encl, addr, data, secinfo, mrmask,
+ allowed_prot);
out:
kunmap(data_page);
__free_page(data_page);
@@ -645,7 +656,7 @@ static long sgx_ioc_enclave_add_pages(struct file *filep, unsigned int cmd,
ret = sgx_encl_add_page(encl, addp->addr + i*PAGE_SIZE,
addp->src + i*PAGE_SIZE,
- &secinfo, addp->mrmask);
+ &secinfo, addp->mrmask, addp->flags);
}
return ret;
}
diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c
index 955d4f430adc..e5847571a265 100644
--- a/arch/x86/kernel/cpu/sgx/encl.c
+++ b/arch/x86/kernel/cpu/sgx/encl.c
@@ -249,7 +249,7 @@ int sgx_map_allowed(struct sgx_encl *encl, unsigned long start,
for (addr = start; addr < end; addr += PAGE_SIZE) {
page = radix_tree_lookup(&encl->page_tree, addr >> PAGE_SHIFT);
- if (!page)
+ if (!page || (prot & ~page->allowed_prot))
return -EACCES;
}
diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h
index 6e310e3b3fff..7cca076a4987 100644
--- a/arch/x86/kernel/cpu/sgx/encl.h
+++ b/arch/x86/kernel/cpu/sgx/encl.h
@@ -41,6 +41,7 @@ enum sgx_encl_page_desc {
struct sgx_encl_page {
unsigned long desc;
+ unsigned long allowed_prot;
struct sgx_epc_page *epc_page;
struct sgx_va_page *va_page;
struct sgx_encl *encl;
--
2.21.0
^ permalink raw reply related
* [RFC PATCH 7/9] x86/sgx: Enforce noexec filesystem restriction for enclaves
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
Do not allow an enclave page to be mapped with PROT_EXEC if the source
page is backed by a file on a noexec file system.
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
arch/x86/kernel/cpu/sgx/driver/ioctl.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/cpu/sgx/driver/ioctl.c b/arch/x86/kernel/cpu/sgx/driver/ioctl.c
index c30acd3fbbdd..5f71be7cbb01 100644
--- a/arch/x86/kernel/cpu/sgx/driver/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/driver/ioctl.c
@@ -576,6 +576,27 @@ static int __sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
return ret;
}
+static int sgx_encl_page_protect(unsigned long src, unsigned long prot,
+ unsigned long *allowed_prot)
+{
+ struct vm_area_struct *vma;
+
+ if (!(*allowed_prot & VM_EXEC))
+ goto do_check;
+
+ down_read(¤t->mm->mmap_sem);
+ vma = find_vma(current->mm, src);
+ if (!vma || (vma->vm_file && path_noexec(&vma->vm_file->f_path)))
+ *allowed_prot &= ~VM_EXEC;
+ up_read(¤t->mm->mmap_sem);
+
+do_check:
+ if (prot & ~*allowed_prot)
+ return -EACCES;
+
+ return 0;
+}
+
static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
unsigned long src, struct sgx_secinfo *secinfo,
unsigned int mrmask, unsigned int flags)
@@ -589,8 +610,9 @@ static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
BUILD_BUG_ON(SGX_SECINFO_R != VM_READ || SGX_SECINFO_W != VM_WRITE ||
SGX_SECINFO_X != VM_EXEC);
- if (prot & ~allowed_prot)
- return -EACCES;
+ ret = sgx_encl_page_protect(src, prot, &allowed_prot);
+ if (ret)
+ return ret;
data_page = alloc_page(GFP_HIGHUSER);
if (!data_page)
--
2.21.0
^ permalink raw reply related
* [RFC PATCH 5/9] x86/sgx: Restrict mapping without an enclave page to PROT_NONE
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
To support LSM integration, SGX will require userspace to explicitly
specify the allowed protections for each page. The allowed protections
will be supplied to and modified by LSMs (based on their policies).
To prevent userspace from circumventing the allowed protections, do not
allow PROT_{READ,WRITE,EXEC} mappings to an enclave without an
associated enclave page (which will track the allowed protections).
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
arch/x86/kernel/cpu/sgx/driver/main.c | 5 +++++
arch/x86/kernel/cpu/sgx/encl.c | 30 +++++++++++++++++++++++++++
arch/x86/kernel/cpu/sgx/encl.h | 3 +++
3 files changed, 38 insertions(+)
diff --git a/arch/x86/kernel/cpu/sgx/driver/main.c b/arch/x86/kernel/cpu/sgx/driver/main.c
index 129d356aff30..65a87c2fdf02 100644
--- a/arch/x86/kernel/cpu/sgx/driver/main.c
+++ b/arch/x86/kernel/cpu/sgx/driver/main.c
@@ -63,6 +63,11 @@ static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
static int sgx_mmap(struct file *file, struct vm_area_struct *vma)
{
struct sgx_encl *encl = file->private_data;
+ int ret;
+
+ ret = sgx_map_allowed(encl, vma->vm_start, vma->vm_end, vma->vm_flags);
+ if (ret)
+ return ret;
vma->vm_ops = &sgx_vm_ops;
vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c
index f23ea0fbaa47..955d4f430adc 100644
--- a/arch/x86/kernel/cpu/sgx/encl.c
+++ b/arch/x86/kernel/cpu/sgx/encl.c
@@ -235,6 +235,35 @@ static void sgx_vma_close(struct vm_area_struct *vma)
kref_put(&encl->refcount, sgx_encl_release);
}
+int sgx_map_allowed(struct sgx_encl *encl, unsigned long start,
+ unsigned long end, unsigned long prot)
+{
+ struct sgx_encl_page *page;
+ unsigned long addr;
+
+ prot &= (VM_READ | VM_WRITE | VM_EXEC);
+ if (!prot || !encl)
+ return 0;
+
+ mutex_lock(&encl->lock);
+
+ for (addr = start; addr < end; addr += PAGE_SIZE) {
+ page = radix_tree_lookup(&encl->page_tree, addr >> PAGE_SHIFT);
+ if (!page)
+ return -EACCES;
+ }
+
+ mutex_unlock(&encl->lock);
+
+ return 0;
+}
+
+static int sgx_vma_mprotect(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, unsigned long prot)
+{
+ return sgx_map_allowed(vma->vm_private_data, start, end, prot);
+}
+
static unsigned int sgx_vma_fault(struct vm_fault *vmf)
{
unsigned long addr = (unsigned long)vmf->address;
@@ -372,6 +401,7 @@ static int sgx_vma_access(struct vm_area_struct *vma, unsigned long addr,
const struct vm_operations_struct sgx_vm_ops = {
.close = sgx_vma_close,
.open = sgx_vma_open,
+ .mprotect = sgx_vma_mprotect,
.fault = sgx_vma_fault,
.access = sgx_vma_access,
};
diff --git a/arch/x86/kernel/cpu/sgx/encl.h b/arch/x86/kernel/cpu/sgx/encl.h
index c557f0374d74..6e310e3b3fff 100644
--- a/arch/x86/kernel/cpu/sgx/encl.h
+++ b/arch/x86/kernel/cpu/sgx/encl.h
@@ -106,6 +106,9 @@ static inline unsigned long sgx_pcmd_offset(pgoff_t page_index)
sizeof(struct sgx_pcmd);
}
+int sgx_map_allowed(struct sgx_encl *encl, unsigned long start,
+ unsigned long end, unsigned long prot);
+
enum sgx_encl_mm_iter {
SGX_ENCL_MM_ITER_DONE = 0,
SGX_ENCL_MM_ITER_NEXT = 1,
--
2.21.0
^ permalink raw reply related
* [RFC PATCH 9/9] security/selinux: Add enclave_load() implementation
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
The goal of selinux_enclave_load() is to provide a facsimile of the
existing selinux_file_mprotect() and file_map_prot_check() policies,
but tailored to the unique properties of SGX.
For example, an enclave page is technically backed by a MAP_SHARED file,
but the "file" is essentially shared memory that is never persisted
anywhere and also requires execute permissions (for some pages).
The basic concept is to require appropriate execute permissions on the
source of the enclave for pages that are requesting PROT_EXEC, e.g. if
an enclave page is being loaded from a regular file, require
FILE__EXECUTE and/or FILE__EXECMOND, and if it's coming from an
anonymous/private mapping, require PROCESS__EXECMEM since the process
is essentially executing from the mapping, albeit in a roundabout way.
Note, FILE__READ and FILE__WRITE are intentionally not required even if
the source page is backed by a regular file. Writes to the enclave page
are contained to the EPC, i.e. never hit the original file, and read
permissions have already been vetted (or the VMA doesn't have PROT_READ,
in which case loading the page into the enclave will fail).
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
security/selinux/hooks.c | 85 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3ec702cf46ca..f436a055dda7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6726,6 +6726,87 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
}
#endif
+#ifdef CONFIG_INTEL_SGX
+int selinux_enclave_load(struct vm_area_struct *vma, unsigned long prot,
+ unsigned long *allowed_prot)
+{
+ const struct cred *cred = current_cred();
+ u32 sid = cred_sid(cred);
+ int rc;
+
+ /* SGX is supported only in 64-bit kernels. */
+ WARN_ON_ONCE(!default_noexec);
+
+ /*
+ * SGX is responsible for checking @prot vs @allowed_prot, and SELinux
+ * only cares about execute related permissions for enclaves.
+ */
+ if (!(*allowed_prot & PROT_EXEC))
+ return 0;
+
+ /*
+ * Loading an executable enclave page from a VMA that is not executable
+ * itself requires EXECUTE permissions on the source file, or if there
+ * is no regular source file, EXECMEM since the page is being loaded
+ * from a non-executable anonymous mapping.
+ */
+ if (!(vma->vm_flags & VM_EXEC)) {
+ if (vma->vm_file && !IS_PRIVATE(file_inode(vma->vm_file)))
+ rc = file_has_perm(cred, vma->vm_file, FILE__EXECUTE);
+ else
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS,
+ PROCESS__EXECMEM, NULL);
+
+ /*
+ * Reject the load if the enclave *needs* the page to be
+ * executable, otherwise prevent it from becoming executable.
+ */
+ if (rc) {
+ if (prot & PROT_EXEC)
+ return rc;
+
+ *allowed_prot &= ~PROT_EXEC;
+ }
+ }
+
+ /*
+ * An enclave page that may do RW->RX or W+X requires EXECMOD (backed
+ * by a regular file) or EXECMEM (loaded from an anonymous mapping).
+ * Note, this hybrid EXECMOD and EXECMEM behavior is intentional and
+ * reflects the nature of enclaves and the EPC, e.g. EPC is effectively
+ * a non-persistent shared file, but each enclave is a private domain
+ * within that shared file, so delegate to the source of the enclave.
+ */
+ if ((*allowed_prot & PROT_EXEC) && (*allowed_prot & PROT_WRITE)) {
+ if (vma->vm_file && !IS_PRIVATE(file_inode(vma->vm_file)))
+ rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
+ else
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS,
+ PROCESS__EXECMEM, NULL);
+ /*
+ * Clear ALLOW_EXEC instead of ALLOWED_WRITE if permissions are
+ * lacking and @prot has neither PROT_WRITE or PROT_EXEC. If
+ * userspace wanted RX they would have requested RX, and due to
+ * lack of permissions they can never get RW->RX, i.e. the only
+ * useful transition is R->RW.
+ */
+ if (rc) {
+ if ((prot & PROT_EXEC) && (prot & PROT_WRITE))
+ return rc;
+
+ if (prot & PROT_EXEC)
+ *allowed_prot &= ~PROT_WRITE;
+ else
+ *allowed_prot &= ~PROT_EXEC;
+ }
+ }
+
+ return 0;
+}
+#endif
+
struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
.lbs_cred = sizeof(struct task_security_struct),
.lbs_file = sizeof(struct file_security_struct),
@@ -6968,6 +7049,10 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
#endif
+
+#ifdef CONFIG_INTEL_SGX
+ LSM_HOOK_INIT(enclave_load, selinux_enclave_load),
+#endif
};
static __init int selinux_init(void)
--
2.21.0
^ permalink raw reply related
* [PATCH 06/58] LSM: Use lsm_export in the cred_getsecid hooks
From: Casey Schaufler @ 2019-05-31 23:30 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert the cred_getsecid hooks to use the lsm_export
structure instead of a u32 secid. There is some scaffolding
involved that will be removed when security_cred_getsecid()
is updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 5 +++--
security/security.c | 6 ++++--
security/selinux/hooks.c | 4 ++--
security/smack/smack_lsm.c | 4 ++--
4 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 09573c55e535..0f9d4174bb6e 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -572,7 +572,8 @@
* Transfer data from original creds to new creds
* @cred_getsecid:
* Retrieve the security identifier of the cred structure @c
- * @c contains the credentials, secid will be placed into @secid.
+ * @c contains the credentials
+ * @l contains a pointer to the location where result will be saved.
* In case of failure, @secid will be set to zero.
* @kernel_act_as:
* Set the credentials for a kernel service to act as (subjective context).
@@ -1596,7 +1597,7 @@ union security_list_options {
int (*cred_prepare)(struct cred *new, const struct cred *old,
gfp_t gfp);
void (*cred_transfer)(struct cred *new, const struct cred *old);
- void (*cred_getsecid)(const struct cred *c, u32 *secid);
+ void (*cred_getsecid)(const struct cred *c, struct lsm_export *l);
int (*kernel_act_as)(struct cred *new, u32 secid);
int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
int (*kernel_module_request)(char *kmod_name);
diff --git a/security/security.c b/security/security.c
index a1f28a5e582b..ca485a777ca1 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1638,8 +1638,10 @@ void security_transfer_creds(struct cred *new, const struct cred *old)
void security_cred_getsecid(const struct cred *c, u32 *secid)
{
- *secid = 0;
- call_void_hook(cred_getsecid, c, secid);
+ struct lsm_export data = { .flags = LSM_EXPORT_NONE };
+
+ call_void_hook(cred_getsecid, c, &data);
+ lsm_export_secid(&data, secid);
}
EXPORT_SYMBOL(security_cred_getsecid);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0e31be22d9bb..f97dd414ac8d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3764,9 +3764,9 @@ static void selinux_cred_transfer(struct cred *new, const struct cred *old)
*tsec = *old_tsec;
}
-static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
+static void selinux_cred_getsecid(const struct cred *c, struct lsm_export *l)
{
- *secid = cred_sid(c);
+ selinux_export_secid(l, cred_sid(c));
}
/*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 5e345122ccb1..15579bdd7244 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1980,13 +1980,13 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
*
* Sets the secid to contain a u32 version of the smack label.
*/
-static void smack_cred_getsecid(const struct cred *cred, u32 *secid)
+static void smack_cred_getsecid(const struct cred *cred, struct lsm_export *l)
{
struct smack_known *skp;
rcu_read_lock();
skp = smk_of_task(smack_cred(cred));
- *secid = skp->smk_secid;
+ smack_export_secid(l, skp->smk_secid);
rcu_read_unlock();
}
--
2.19.1
^ permalink raw reply related
* [PATCH 07/58] LSM: Use lsm_export in the ipc_getsecid and task_getsecid hooks
From: Casey Schaufler @ 2019-05-31 23:30 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert the cred_getsecid and task_getsecid hooks to use the
lsm_export structure instead of a u32 secid. There is some
scaffolding involved that will be removed when
security_ipc_getsecid() and security_task_getsecid() are
updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 8 ++++----
security/apparmor/lsm.c | 12 ++++++++++--
security/security.c | 12 ++++++++----
security/selinux/hooks.c | 10 ++++++----
security/smack/smack_lsm.c | 8 ++++----
5 files changed, 32 insertions(+), 18 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 0f9d4174bb6e..62783a923136 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -638,7 +638,7 @@
* Return 0 if permission is granted.
* @task_getsecid:
* Retrieve the security identifier of the process @p.
- * @p contains the task_struct for the process and place is into @secid.
+ * @p contains the task_struct for the process and place is into @l.
* In case of failure, @secid will be set to zero.
*
* @task_setnice:
@@ -1094,7 +1094,7 @@
* @ipc_getsecid:
* Get the secid associated with the ipc object.
* @ipcp contains the kernel IPC permission structure.
- * @secid contains a pointer to the location where result will be saved.
+ * @l contains a pointer to the location where result will be saved.
* In case of failure, @secid will be set to zero.
*
* Security hooks for individual messages held in System V IPC message queues
@@ -1610,7 +1610,7 @@ union security_list_options {
int (*task_setpgid)(struct task_struct *p, pid_t pgid);
int (*task_getpgid)(struct task_struct *p);
int (*task_getsid)(struct task_struct *p);
- void (*task_getsecid)(struct task_struct *p, u32 *secid);
+ void (*task_getsecid)(struct task_struct *p, struct lsm_export *l);
int (*task_setnice)(struct task_struct *p, int nice);
int (*task_setioprio)(struct task_struct *p, int ioprio);
int (*task_getioprio)(struct task_struct *p);
@@ -1628,7 +1628,7 @@ union security_list_options {
void (*task_to_inode)(struct task_struct *p, struct inode *inode);
int (*ipc_permission)(struct kern_ipc_perm *ipcp, short flag);
- void (*ipc_getsecid)(struct kern_ipc_perm *ipcp, u32 *secid);
+ void (*ipc_getsecid)(struct kern_ipc_perm *ipcp, struct lsm_export *l);
int (*msg_msg_alloc_security)(struct msg_msg *msg);
void (*msg_msg_free_security)(struct msg_msg *msg);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 2716e7731279..706e5ae09170 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -49,6 +49,14 @@ int apparmor_initialized;
DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
+/*
+ * Set the AppArmor secid in an lsm_export structure
+ */
+static inline void apparmor_export_secid(struct lsm_export *l, u32 secid)
+{
+ l->apparmor = secid;
+ l->flags |= LSM_EXPORT_APPARMOR;
+}
/*
* LSM hook functions
@@ -710,10 +718,10 @@ static void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
return;
}
-static void apparmor_task_getsecid(struct task_struct *p, u32 *secid)
+static void apparmor_task_getsecid(struct task_struct *p, struct lsm_export *l)
{
struct aa_label *label = aa_get_task_label(p);
- *secid = label->secid;
+ apparmor_export_secid(l, label->secid);
aa_put_label(label);
}
diff --git a/security/security.c b/security/security.c
index ca485a777ca1..802557ff6f60 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1722,8 +1722,10 @@ int security_task_getsid(struct task_struct *p)
void security_task_getsecid(struct task_struct *p, u32 *secid)
{
- *secid = 0;
- call_void_hook(task_getsecid, p, secid);
+ struct lsm_export data = { .flags = LSM_EXPORT_NONE };
+
+ call_void_hook(task_getsecid, p, &data);
+ lsm_export_secid(&data, secid);
}
EXPORT_SYMBOL(security_task_getsecid);
@@ -1805,8 +1807,10 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
{
- *secid = 0;
- call_void_hook(ipc_getsecid, ipcp, secid);
+ struct lsm_export data = { .flags = LSM_EXPORT_NONE };
+
+ call_void_hook(ipc_getsecid, ipcp, &data);
+ lsm_export_secid(&data, secid);
}
int security_msg_msg_alloc(struct msg_msg *msg)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f97dd414ac8d..c82108793fb5 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3911,9 +3911,9 @@ static int selinux_task_getsid(struct task_struct *p)
PROCESS__GETSESSION, NULL);
}
-static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
+static void selinux_task_getsecid(struct task_struct *p, struct lsm_export *l)
{
- *secid = task_sid(p);
+ selinux_export_secid(l, task_sid(p));
}
static int selinux_task_setnice(struct task_struct *p, int nice)
@@ -6094,10 +6094,12 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
return ipc_has_perm(ipcp, av);
}
-static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp,
+ struct lsm_export *l)
{
struct ipc_security_struct *isec = selinux_ipc(ipcp);
- *secid = isec->sid;
+
+ selinux_export_secid(l, isec->sid);
}
static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 15579bdd7244..13ac3045a388 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2087,11 +2087,11 @@ static int smack_task_getsid(struct task_struct *p)
*
* Sets the secid to contain a u32 version of the smack label.
*/
-static void smack_task_getsecid(struct task_struct *p, u32 *secid)
+static void smack_task_getsecid(struct task_struct *p, struct lsm_export *l)
{
struct smack_known *skp = smk_of_task_struct(p);
- *secid = skp->smk_secid;
+ smack_export_secid(l, skp->smk_secid);
}
/**
@@ -3231,12 +3231,12 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
* @ipp: the object permissions
* @secid: where result will be saved
*/
-static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
+static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, struct lsm_export *l)
{
struct smack_known **blob = smack_ipc(ipp);
struct smack_known *iskp = *blob;
- *secid = iskp->smk_secid;
+ smack_export_secid(l, iskp->smk_secid);
}
/**
--
2.19.1
^ permalink raw reply related
* [PATCH 09/58] LSM: Use lsm_export in the getpeersec_dgram hooks
From: Casey Schaufler @ 2019-05-31 23:31 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert the getpeersec_dgram hooks to use the lsm_export
structure instead of a u32 secid. There is some scaffolding
involved that will be removed when security_getpeersec_dgram()
is updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 5 +++--
security/apparmor/lsm.c | 3 ++-
security/security.c | 13 ++++++++++---
security/selinux/hooks.c | 6 ++++--
security/smack/smack_lsm.c | 5 +++--
5 files changed, 22 insertions(+), 10 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 800040050032..bcc628cffe6a 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -881,7 +881,7 @@
* ancillary message type.
* @sock contains the peer socket. May be NULL.
* @skb is the sk_buff for the packet being queried. May be NULL.
- * @secid pointer to store the secid of the packet.
+ * @l is a pointer to a buffer in which to copy the security data
* Return 0 on success, error on failure.
* @sk_alloc_security:
* Allocate and attach a security structure to the sk->sk_security field,
@@ -1702,7 +1702,8 @@ union security_list_options {
char __user *optval,
int __user *optlen, unsigned len);
int (*socket_getpeersec_dgram)(struct socket *sock,
- struct sk_buff *skb, u32 *secid);
+ struct sk_buff *skb,
+ struct lsm_export *l);
int (*sk_alloc_security)(struct sock *sk, int family, gfp_t priority);
void (*sk_free_security)(struct sock *sk);
void (*sk_clone_security)(const struct sock *sk, struct sock *newsk);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 706e5ae09170..24b638bd4305 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1096,7 +1096,8 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
* Sets the netlabel socket state on sk from parent
*/
static int apparmor_socket_getpeersec_dgram(struct socket *sock,
- struct sk_buff *skb, u32 *secid)
+ struct sk_buff *skb,
+ struct lsm_export *l)
{
/* TODO: requires secid support */
diff --git a/security/security.c b/security/security.c
index 3a766755b722..2f1355d10e0d 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2145,10 +2145,17 @@ int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
optval, optlen, len);
}
-int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
+ u32 *secid)
{
- return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock,
- skb, secid);
+ int rc;
+ struct lsm_export data = { .flags = LSM_EXPORT_NONE };
+
+ rc = call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock, skb,
+ &data);
+
+ lsm_export_secid(&data, secid);
+ return rc;
}
EXPORT_SYMBOL(security_socket_getpeersec_dgram);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b88a51b6ca41..9db12f6b1221 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4949,7 +4949,9 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
return err;
}
-static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+static int selinux_socket_getpeersec_dgram(struct socket *sock,
+ struct sk_buff *skb,
+ struct lsm_export *l)
{
u32 peer_secid = SECSID_NULL;
u16 family;
@@ -4971,7 +4973,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
selinux_skb_peerlbl_sid(skb, family, &peer_secid);
out:
- *secid = peer_secid;
+ selinux_export_secid(l, peer_secid);
if (peer_secid == SECSID_NULL)
return -EINVAL;
return 0;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3b77a0324c3d..3e3724bbd6ea 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3973,7 +3973,8 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
* Sets the netlabel socket state on sk from parent
*/
static int smack_socket_getpeersec_dgram(struct socket *sock,
- struct sk_buff *skb, u32 *secid)
+ struct sk_buff *skb,
+ struct lsm_export *l)
{
struct netlbl_lsm_secattr secattr;
@@ -4024,7 +4025,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
#endif
break;
}
- *secid = s;
+ smack_export_secid(l, s);
if (s == 0)
return -EINVAL;
return 0;
--
2.19.1
^ permalink raw reply related
* [PATCH 08/58] LSM: Use lsm_export in the kernel_ask_as hooks
From: Casey Schaufler @ 2019-05-31 23:30 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert the kernel_ask_as hooks to use the lsm_export
structure instead of a u32 secid. There is some scaffolding
involved that will be removed when security_kernel_ask_as()
is updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 4 ++--
security/security.c | 15 ++++++++++++++-
security/selinux/hooks.c | 17 ++++++++++++++---
security/smack/smack_lsm.c | 12 +++++++++++-
4 files changed, 41 insertions(+), 7 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 62783a923136..800040050032 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -578,7 +578,7 @@
* @kernel_act_as:
* Set the credentials for a kernel service to act as (subjective context).
* @new points to the credentials to be modified.
- * @secid specifies the security ID to be set
+ * @l specifies the security data to be set
* The current task must be the one that nominated @secid.
* Return 0 if successful.
* @kernel_create_files_as:
@@ -1598,7 +1598,7 @@ union security_list_options {
gfp_t gfp);
void (*cred_transfer)(struct cred *new, const struct cred *old);
void (*cred_getsecid)(const struct cred *c, struct lsm_export *l);
- int (*kernel_act_as)(struct cred *new, u32 secid);
+ int (*kernel_act_as)(struct cred *new, struct lsm_export *l);
int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
int (*kernel_module_request)(char *kmod_name);
int (*kernel_load_data)(enum kernel_load_data_id id);
diff --git a/security/security.c b/security/security.c
index 802557ff6f60..3a766755b722 100644
--- a/security/security.c
+++ b/security/security.c
@@ -742,6 +742,15 @@ static inline void lsm_export_secid(struct lsm_export *data, u32 *secid)
}
}
+static inline void lsm_export_to_all(struct lsm_export *data, u32 secid)
+{
+ data->selinux = secid;
+ data->smack = secid;
+ data->apparmor = secid;
+ data->flags = LSM_EXPORT_SELINUX | LSM_EXPORT_SMACK |
+ LSM_EXPORT_APPARMOR;
+}
+
/* Security operations */
int security_binder_set_context_mgr(struct task_struct *mgr)
@@ -1647,7 +1656,11 @@ EXPORT_SYMBOL(security_cred_getsecid);
int security_kernel_act_as(struct cred *new, u32 secid)
{
- return call_int_hook(kernel_act_as, 0, new, secid);
+ struct lsm_export data = { .flags = LSM_EXPORT_NONE };
+
+ lsm_export_to_all(&data, secid);
+
+ return call_int_hook(kernel_act_as, 0, new, &data);
}
int security_kernel_create_files_as(struct cred *new, struct inode *inode)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c82108793fb5..b88a51b6ca41 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -222,6 +222,14 @@ static inline void selinux_export_secid(struct lsm_export *l, u32 secid)
l->flags |= LSM_EXPORT_SELINUX;
}
+static inline void selinux_import_secid(struct lsm_export *l, u32 *secid)
+{
+ if (l->flags & LSM_EXPORT_SELINUX)
+ *secid = l->selinux;
+ else
+ *secid = SECSID_NULL;
+}
+
/*
* get the security ID of a set of credentials
*/
@@ -3773,19 +3781,22 @@ static void selinux_cred_getsecid(const struct cred *c, struct lsm_export *l)
* set the security data for a kernel service
* - all the creation contexts are set to unlabelled
*/
-static int selinux_kernel_act_as(struct cred *new, u32 secid)
+static int selinux_kernel_act_as(struct cred *new, struct lsm_export *l)
{
struct task_security_struct *tsec = selinux_cred(new);
+ u32 nsid;
u32 sid = current_sid();
int ret;
+ selinux_import_secid(l, &nsid);
+
ret = avc_has_perm(&selinux_state,
- sid, secid,
+ sid, nsid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__USE_AS_OVERRIDE,
NULL);
if (ret == 0) {
- tsec->sid = secid;
+ tsec->sid = nsid;
tsec->create_sid = 0;
tsec->keycreate_sid = 0;
tsec->sockcreate_sid = 0;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 13ac3045a388..3b77a0324c3d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -475,6 +475,14 @@ static inline void smack_export_secid(struct lsm_export *l, u32 secid)
l->flags |= LSM_EXPORT_SMACK;
}
+static inline void smack_import_secid(struct lsm_export *l, u32 *secid)
+{
+ if (l->flags & LSM_EXPORT_SMACK)
+ *secid = l->smack;
+ else
+ *secid = 0;
+}
+
/*
* LSM hooks.
* We he, that is fun!
@@ -1997,10 +2005,12 @@ static void smack_cred_getsecid(const struct cred *cred, struct lsm_export *l)
*
* Set the security data for a kernel service.
*/
-static int smack_kernel_act_as(struct cred *new, u32 secid)
+static int smack_kernel_act_as(struct cred *new, struct lsm_export *l)
{
+ u32 secid;
struct task_smack *new_tsp = smack_cred(new);
+ smack_import_secid(l, &secid);
new_tsp->smk_task = smack_from_secid(secid);
return 0;
}
--
2.19.1
^ permalink raw reply related
* [RFC PATCH 8/9] LSM: x86/sgx: Introduce ->enclave_load() hook for Intel SGX
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
enclave_load() is roughly analogous to the existing file_mprotect().
Due to the nature of SGX and its Enclave Page Cache (EPC), all enclave
VMAs are backed by a single file, i.e. /dev/sgx/enclave, that must be
MAP_SHARED. Furthermore, all enclaves need read, write and execute
VMAs. As a result, file_mprotect() does not provide any meaningful
security for enclaves since an LSM can only deny/grant access to the
EPC as a whole.
security_enclave_load() is called when SGX is first loading an enclave
page, i.e. copying a page from normal memory into the EPC. The notable
difference from file_mprotect() is the allowed_prot parameter, which
is essentially an SGX-specific version of a VMA's MAY_{READ,WRITE,EXEC}
flags. The purpose of allowed_prot is to enable checks such as
SELinux's FILE__EXECMOD permission without having to track and update
VMAs across multiple mm structs, i.e. SGX can ensure userspace doesn't
overstep its bounds simply by restricting an enclave VMA's protections
by vetting what is maximally allowed during build time.
An alternative to the allowed_prot approach would be to use an enclave's
SIGSTRUCT (a smallish structure that can uniquely identify an enclave)
as a proxy for the enclave. For example, SGX could take and hold a
reference to the file containing the SIGSTRUCT (if it's in a file) and
call security_enclave_load() during mprotect(). While the SIGSTRUCT
approach would provide better precision, the actual value added was
deemed to be negligible. On the other hand, pinning a file for the
lifetime of the enclave is ugly, and essentially caching LSM policies
in each page's allowed_prot avoids having to make an extra LSM upcall
during mprotect().
Note, extensive discussion yielded no sane alternative to some form of
SGX specific LSM hook[1].
[1] https://lkml.kernel.org/r/CALCETrXf8mSK45h7sTK5Wf+pXLVn=Bjsc_RLpgO-h-qdzBRo5Q@mail.gmail.com
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
arch/x86/kernel/cpu/sgx/driver/ioctl.c | 14 +++++++++-----
include/linux/lsm_hooks.h | 16 ++++++++++++++++
include/linux/security.h | 2 ++
security/security.c | 8 ++++++++
4 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/arch/x86/kernel/cpu/sgx/driver/ioctl.c b/arch/x86/kernel/cpu/sgx/driver/ioctl.c
index 5f71be7cbb01..260417ecbcff 100644
--- a/arch/x86/kernel/cpu/sgx/driver/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/driver/ioctl.c
@@ -8,6 +8,7 @@
#include <linux/highmem.h>
#include <linux/ratelimit.h>
#include <linux/sched/signal.h>
+#include <linux/security.h>
#include <linux/shmem_fs.h>
#include <linux/slab.h>
#include <linux/suspend.h>
@@ -580,21 +581,24 @@ static int sgx_encl_page_protect(unsigned long src, unsigned long prot,
unsigned long *allowed_prot)
{
struct vm_area_struct *vma;
+ int ret = 0;
- if (!(*allowed_prot & VM_EXEC))
+ if (!(*allowed_prot & VM_EXEC) && !IS_ENABLED(CONFIG_SECURITY))
goto do_check;
down_read(¤t->mm->mmap_sem);
vma = find_vma(current->mm, src);
if (!vma || (vma->vm_file && path_noexec(&vma->vm_file->f_path)))
*allowed_prot &= ~VM_EXEC;
+#ifdef CONFIG_SECURITY
+ ret = security_enclave_load(vma, prot, allowed_prot);
+#endif
up_read(¤t->mm->mmap_sem);
do_check:
- if (prot & ~*allowed_prot)
- return -EACCES;
-
- return 0;
+ if (!ret && (prot & ~*allowed_prot))
+ ret = -EACCES;
+ return ret;
}
static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long addr,
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 47f58cfb6a19..0562775424a0 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1446,6 +1446,14 @@
* @bpf_prog_free_security:
* Clean up the security information stored inside bpf prog.
*
+ * Security hooks for Intel SGX enclaves.
+ *
+ * @enclave_load:
+ * On success, returns 0 and optionally adjusts @allowed_prot
+ * @vma: the source memory region of the enclave page being loaded.
+ * @prot: the initial protection of the enclave page.
+ * @allowed_prot: the maximum protections of the enclave page.
+ * Return 0 if permission is granted.
*/
union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1807,6 +1815,11 @@ union security_list_options {
int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
#endif /* CONFIG_BPF_SYSCALL */
+
+#ifdef CONFIG_INTEL_SGX
+ int (*enclave_load)(struct vm_area_struct *vma, unsigned long prot,
+ unsigned long *allowed_prot);
+#endif /* CONFIG_INTEL_SGX */
};
struct security_hook_heads {
@@ -2046,6 +2059,9 @@ struct security_hook_heads {
struct hlist_head bpf_prog_alloc_security;
struct hlist_head bpf_prog_free_security;
#endif /* CONFIG_BPF_SYSCALL */
+#ifdef CONFIG_INTEL_SGX
+ struct hlist_head enclave_load;
+#endif /* CONFIG_INTEL_SGX */
} __randomize_layout;
/*
diff --git a/include/linux/security.h b/include/linux/security.h
index 659071c2e57c..2f7925eeef7e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -392,6 +392,8 @@ void security_inode_invalidate_secctx(struct inode *inode);
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
+int security_enclave_load(struct vm_area_struct *vma, unsigned long prot,
+ unsigned long *allowed_prot);
#else /* CONFIG_SECURITY */
static inline int call_lsm_notifier(enum lsm_event event, void *data)
diff --git a/security/security.c b/security/security.c
index 613a5c00e602..07ed6763571e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2359,3 +2359,11 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux)
call_void_hook(bpf_prog_free_security, aux);
}
#endif /* CONFIG_BPF_SYSCALL */
+
+#ifdef CONFIG_INTEL_SGX
+int security_enclave_load(struct vm_area_struct *vma, unsigned long prot,
+ unsigned long *allowed_prot)
+{
+ return call_int_hook(enclave_load, 0, vma, prot, allowed_prot);
+}
+#endif /* CONFIG_INTEL_SGX */
--
2.21.0
^ permalink raw reply related
* [RFC PATCH 4/9] mm: Introduce vm_ops->mprotect()
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
SGX will use the mprotect() hook to prevent userspace from circumventing
various security checks, i.e. Linux Security Modules.
Enclaves are built by copying data from normal memory into the Enclave
Page Cache (EPC). Due to the nature of SGX, the EPC is represented by a
single file that must be MAP_SHARED, i.e. mprotect() only ever sees a
single MAP_SHARED vm_file. Furthermore, all enclaves will need read,
write and execute pages in the EPC.
As a result, LSM policies cannot be meaningfully applied, e.g. an LSM
can deny access to the EPC as a whole, but can't deny PROT_EXEC on page
that originated in a non-EXECUTE file (which is long gone by the time
mprotect() is called).
By hooking mprotect(), SGX can make explicit LSM upcalls while an
enclave is being built, i.e. when the kernel has a handle to origin of
each enclave page, and enforce the result of the LSM policy whenever
userspace maps the enclave page in the future.
Alternatively, SGX could play games with MAY_{READ,WRITE,EXEC}, but
that approach is quite ugly, e.g. would require userspace to call an
SGX ioctl() prior to using mprotect() to extend a page's protections.
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
include/linux/mm.h | 2 ++
mm/mprotect.c | 15 +++++++++++----
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0e8834ac32b7..50a42364a885 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -458,6 +458,8 @@ struct vm_operations_struct {
void (*close)(struct vm_area_struct * area);
int (*split)(struct vm_area_struct * area, unsigned long addr);
int (*mremap)(struct vm_area_struct * area);
+ int (*mprotect)(struct vm_area_struct * area, unsigned long start,
+ unsigned long end, unsigned long prot);
vm_fault_t (*fault)(struct vm_fault *vmf);
vm_fault_t (*huge_fault)(struct vm_fault *vmf,
enum page_entry_size pe_size);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index bf38dfbbb4b4..e466ca5e4fe0 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -547,13 +547,20 @@ static int do_mprotect_pkey(unsigned long start, size_t len,
goto out;
}
- error = security_file_mprotect(vma, reqprot, prot);
- if (error)
- goto out;
-
tmp = vma->vm_end;
if (tmp > end)
tmp = end;
+
+ if (vma->vm_ops && vma->vm_ops->mprotect) {
+ error = vma->vm_ops->mprotect(vma, nstart, tmp, prot);
+ if (error)
+ goto out;
+ }
+
+ error = security_file_mprotect(vma, reqprot, prot);
+ if (error)
+ goto out;
+
error = mprotect_fixup(vma, &prev, nstart, tmp, newflags);
if (error)
goto out;
--
2.21.0
^ permalink raw reply related
* [RFC PATCH 1/9] x86/sgx: Remove unused local variable in sgx_encl_release()
From: Sean Christopherson @ 2019-05-31 23:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andy Lutomirski, Cedric Xing, Stephen Smalley, James Morris,
Serge E . Hallyn, LSM List, Paul Moore, Eric Paris, selinux,
Jethro Beekman, Dave Hansen, Thomas Gleixner, Linus Torvalds,
LKML, X86 ML, linux-sgx, Andrew Morton, nhorman, npmccallum,
Serge Ayoun, Shay Katz-zamir, Haitao Huang, Andy Shevchenko,
Kai Svahn, Borislav Petkov, Josh Triplett, Kai Huang,
David Rientjes, William Roberts, Philip Tricca
In-Reply-To: <20190531233159.30992-1-sean.j.christopherson@intel.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
arch/x86/kernel/cpu/sgx/encl.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c
index 7216bdf07bd0..f23ea0fbaa47 100644
--- a/arch/x86/kernel/cpu/sgx/encl.c
+++ b/arch/x86/kernel/cpu/sgx/encl.c
@@ -463,7 +463,6 @@ EXPORT_SYMBOL_GPL(sgx_encl_destroy);
void sgx_encl_release(struct kref *ref)
{
struct sgx_encl *encl = container_of(ref, struct sgx_encl, refcount);
- struct sgx_encl_mm *encl_mm;
if (encl->pm_notifier.notifier_call)
unregister_pm_notifier(&encl->pm_notifier);
--
2.21.0
^ permalink raw reply related
* [PATCH 05/58] LSM: Use lsm_export in the inode_getsecid hooks
From: Casey Schaufler @ 2019-05-31 23:30 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Convert the inode_getsecid hooks to use the lsm_export
structure instead of a u32 secid. There is some scaffolding
involved that will be removed when security_inode_getsecid()
is updated.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 4 ++--
include/linux/security.h | 5 +++++
security/security.c | 35 ++++++++++++++++++++++++++++++++++-
security/selinux/hooks.c | 21 ++++++++++++++++-----
security/smack/smack_lsm.c | 13 +++++++++++--
5 files changed, 68 insertions(+), 10 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 3fe39abccc8f..09573c55e535 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -425,7 +425,7 @@
* @inode_getsecid:
* Get the secid associated with the node.
* @inode contains a pointer to the inode.
- * @secid contains a pointer to the location where result will be saved.
+ * @data contains a pointer to the location where result will be saved.
* In case of failure, @secid will be set to zero.
* @inode_copy_up:
* A file is about to be copied up from lower layer to upper layer of
@@ -1566,7 +1566,7 @@ union security_list_options {
int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer,
size_t buffer_size);
- void (*inode_getsecid)(struct inode *inode, u32 *secid);
+ void (*inode_getsecid)(struct inode *inode, struct lsm_export *data);
int (*inode_copy_up)(struct dentry *src, struct cred **new);
int (*inode_copy_up_xattr)(const char *name);
diff --git a/include/linux/security.h b/include/linux/security.h
index 81f9f79f9a1e..fb19f41d630b 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -88,6 +88,11 @@ struct lsm_export {
#define LSM_EXPORT_SMACK 0x02
#define LSM_EXPORT_APPARMOR 0x04
+static inline void lsm_export_init(struct lsm_export *l)
+{
+ memset(l, 0, sizeof(*l));
+}
+
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
int cap, unsigned int opts);
diff --git a/security/security.c b/security/security.c
index d05f00a40e82..a1f28a5e582b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -712,6 +712,36 @@ int lsm_superblock_alloc(struct super_block *sb)
RC; \
})
+/**
+ * lsm_export_secid - pull the useful secid out of a lsm_export
+ * @data: the containing data structure
+ * @secid: where to put the one that matters.
+ *
+ * Shim that will disappear when all lsm_export conversions are done.
+ */
+static inline void lsm_export_secid(struct lsm_export *data, u32 *secid)
+{
+ switch (data->flags) {
+ case LSM_EXPORT_NONE:
+ *secid = 0;
+ break;
+ case LSM_EXPORT_SELINUX:
+ *secid = data->selinux;
+ break;
+ case LSM_EXPORT_SMACK:
+ *secid = data->smack;
+ break;
+ case LSM_EXPORT_APPARMOR:
+ *secid = data->apparmor;
+ break;
+ default:
+ pr_warn("%s flags=0x%u - not a valid set\n", __func__,
+ data->flags);
+ *secid = 0;
+ break;
+ }
+}
+
/* Security operations */
int security_binder_set_context_mgr(struct task_struct *mgr)
@@ -1389,7 +1419,10 @@ EXPORT_SYMBOL(security_inode_listsecurity);
void security_inode_getsecid(struct inode *inode, u32 *secid)
{
- call_void_hook(inode_getsecid, inode, secid);
+ struct lsm_export data = { .flags = LSM_EXPORT_NONE };
+
+ call_void_hook(inode_getsecid, inode, &data);
+ lsm_export_secid(&data, secid);
}
int security_inode_copy_up(struct dentry *src, struct cred **new)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ee840fecfebb..0e31be22d9bb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -213,6 +213,15 @@ static void cred_init_security(void)
tsec->osid = tsec->sid = SECINITSID_KERNEL;
}
+/*
+ * Set the SELinux secid in an lsm_export structure
+ */
+static inline void selinux_export_secid(struct lsm_export *l, u32 secid)
+{
+ l->selinux = secid;
+ l->flags |= LSM_EXPORT_SELINUX;
+}
+
/*
* get the security ID of a set of credentials
*/
@@ -3316,15 +3325,16 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
return len;
}
-static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
+static void selinux_inode_getsecid(struct inode *inode, struct lsm_export *l)
{
struct inode_security_struct *isec = inode_security_novalidate(inode);
- *secid = isec->sid;
+
+ selinux_export_secid(l, isec->sid);
}
static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
{
- u32 sid;
+ struct lsm_export l;
struct task_security_struct *tsec;
struct cred *new_creds = *new;
@@ -3336,8 +3346,9 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
tsec = selinux_cred(new_creds);
/* Get label from overlay inode and set it in create_sid */
- selinux_inode_getsecid(d_inode(src), &sid);
- tsec->create_sid = sid;
+ lsm_export_init(&l);
+ selinux_inode_getsecid(d_inode(src), &l);
+ tsec->create_sid = l.selinux;
*new = new_creds;
return 0;
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index e9560b078efe..5e345122ccb1 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -466,6 +466,15 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
return rc;
}
+/*
+ * Set the Smack secid in an lsm_export structure
+ */
+static inline void smack_export_secid(struct lsm_export *l, u32 secid)
+{
+ l->smack = secid;
+ l->flags |= LSM_EXPORT_SMACK;
+}
+
/*
* LSM hooks.
* We he, that is fun!
@@ -1481,11 +1490,11 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
* @inode: inode to extract the info from
* @secid: where result will be saved
*/
-static void smack_inode_getsecid(struct inode *inode, u32 *secid)
+static void smack_inode_getsecid(struct inode *inode, struct lsm_export *l)
{
struct smack_known *skp = smk_of_inode(inode);
- *secid = skp->smk_secid;
+ smack_export_secid(l, skp->smk_secid);
}
/*
--
2.19.1
^ permalink raw reply related
* [PATCH 04/58] LSM: Create an lsm_export data structure.
From: Casey Schaufler @ 2019-05-31 23:30 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
When more than one security module is exporting data to
audit and networking sub-systems a single 32 bit integer
is no longer sufficient to represent the data. Add a
structure to be used instead.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/security.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/include/linux/security.h b/include/linux/security.h
index 49f2685324b0..81f9f79f9a1e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -76,6 +76,18 @@ enum lsm_event {
LSM_POLICY_CHANGE,
};
+/* Data exported by the security modules */
+struct lsm_export {
+ u32 selinux;
+ u32 smack;
+ u32 apparmor;
+ u32 flags;
+};
+#define LSM_EXPORT_NONE 0x00
+#define LSM_EXPORT_SELINUX 0x01
+#define LSM_EXPORT_SMACK 0x02
+#define LSM_EXPORT_APPARMOR 0x04
+
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
int cap, unsigned int opts);
--
2.19.1
^ permalink raw reply related
* [PATCH 03/58] LSM: Infrastructure management of the key security blob
From: Casey Schaufler @ 2019-05-31 23:30 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
From: Casey Schaufler <cschaufler@schaufler-ca.com>
Move management of the key->security blob out of the
individual security modules and into the security
infrastructure. Instead of allocating the blobs from within
the modules the modules tell the infrastructure how much
space is required, and the space is allocated there.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 1 +
security/security.c | 40 ++++++++++++++++++++++++++++++-
security/selinux/hooks.c | 23 +++++-------------
security/selinux/include/objsec.h | 7 ++++++
security/smack/smack.h | 7 ++++++
security/smack/smack_lsm.c | 33 ++++++++++++-------------
6 files changed, 75 insertions(+), 36 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index b353482ea348..3fe39abccc8f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2050,6 +2050,7 @@ struct lsm_blob_sizes {
int lbs_sock;
int lbs_superblock;
int lbs_ipc;
+ int lbs_key;
int lbs_msg_msg;
int lbs_task;
};
diff --git a/security/security.c b/security/security.c
index e32b7180282e..d05f00a40e82 100644
--- a/security/security.c
+++ b/security/security.c
@@ -172,6 +172,9 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
blob_sizes.lbs_inode = sizeof(struct rcu_head);
lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+ lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
+#endif
lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
@@ -307,6 +310,9 @@ static void __init ordered_lsm_init(void)
init_debug("file blob size = %d\n", blob_sizes.lbs_file);
init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+ init_debug("key blob size = %d\n", blob_sizes.lbs_key);
+#endif /* CONFIG_KEYS */
init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
@@ -573,6 +579,29 @@ static int lsm_ipc_alloc(struct kern_ipc_perm *kip)
return 0;
}
+#ifdef CONFIG_KEYS
+/**
+ * lsm_key_alloc - allocate a composite key blob
+ * @key: the key that needs a blob
+ *
+ * Allocate the key blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_key_alloc(struct key *key)
+{
+ if (blob_sizes.lbs_key == 0) {
+ key->security = NULL;
+ return 0;
+ }
+
+ key->security = kzalloc(blob_sizes.lbs_key, GFP_KERNEL);
+ if (key->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+#endif /* CONFIG_KEYS */
+
/**
* lsm_msg_msg_alloc - allocate a composite msg_msg blob
* @mp: the msg_msg that needs a blob
@@ -2339,12 +2368,21 @@ EXPORT_SYMBOL(security_skb_classify_flow);
int security_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
- return call_int_hook(key_alloc, 0, key, cred, flags);
+ int rc = lsm_key_alloc(key);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(key_alloc, 0, key, cred, flags);
+ if (unlikely(rc))
+ security_key_free(key);
+ return rc;
}
void security_key_free(struct key *key)
{
call_void_hook(key_free, key);
+ kfree(key->security);
+ key->security = NULL;
}
int security_key_permission(key_ref_t key_ref,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f38a6f484613..ee840fecfebb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6353,11 +6353,7 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
unsigned long flags)
{
const struct task_security_struct *tsec;
- struct key_security_struct *ksec;
-
- ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
- if (!ksec)
- return -ENOMEM;
+ struct key_security_struct *ksec = selinux_key(k);
tsec = selinux_cred(cred);
if (tsec->keycreate_sid)
@@ -6365,18 +6361,9 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
else
ksec->sid = tsec->sid;
- k->security = ksec;
return 0;
}
-static void selinux_key_free(struct key *k)
-{
- struct key_security_struct *ksec = k->security;
-
- k->security = NULL;
- kfree(ksec);
-}
-
static int selinux_key_permission(key_ref_t key_ref,
const struct cred *cred,
unsigned perm)
@@ -6394,7 +6381,7 @@ static int selinux_key_permission(key_ref_t key_ref,
sid = cred_sid(cred);
key = key_ref_to_ptr(key_ref);
- ksec = key->security;
+ ksec = selinux_key(key);
return avc_has_perm(&selinux_state,
sid, ksec->sid, SECCLASS_KEY, perm, NULL);
@@ -6402,7 +6389,7 @@ static int selinux_key_permission(key_ref_t key_ref,
static int selinux_key_getsecurity(struct key *key, char **_buffer)
{
- struct key_security_struct *ksec = key->security;
+ struct key_security_struct *ksec = selinux_key(key);
char *context = NULL;
unsigned len;
int rc;
@@ -6627,6 +6614,9 @@ struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
.lbs_file = sizeof(struct file_security_struct),
.lbs_inode = sizeof(struct inode_security_struct),
.lbs_ipc = sizeof(struct ipc_security_struct),
+#ifdef CONFIG_KEYS
+ .lbs_key = sizeof(struct key_security_struct),
+#endif /* CONFIG_KEYS */
.lbs_msg_msg = sizeof(struct msg_security_struct),
.lbs_sock = sizeof(struct sk_security_struct),
.lbs_superblock = sizeof(struct superblock_security_struct),
@@ -6842,7 +6832,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
#ifdef CONFIG_KEYS
LSM_HOOK_INIT(key_alloc, selinux_key_alloc),
- LSM_HOOK_INIT(key_free, selinux_key_free),
LSM_HOOK_INIT(key_permission, selinux_key_permission),
LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
#endif
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 29f02b8f8f31..3b78aa4ee98f 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -194,6 +194,13 @@ static inline struct superblock_security_struct *selinux_superblock(
return superblock->s_security + selinux_blob_sizes.lbs_superblock;
}
+#ifdef CONFIG_KEYS
+static inline struct key_security_struct *selinux_key(const struct key *key)
+{
+ return key->security + selinux_blob_sizes.lbs_key;
+}
+#endif /* CONFIG_KEYS */
+
static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
{
return sock->sk_security + selinux_blob_sizes.lbs_sock;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 4ac4bf3310d7..7cc3a3382fee 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -386,6 +386,13 @@ static inline struct superblock_smack *smack_superblock(
return superblock->s_security + smack_blob_sizes.lbs_superblock;
}
+#ifdef CONFIG_KEYS
+static inline struct smack_known **smack_key(const struct key *key)
+{
+ return key->security + smack_blob_sizes.lbs_key;
+}
+#endif /* CONFIG_KEYS */
+
/*
* Is the directory transmuting?
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index fd69e1bd841b..e9560b078efe 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4179,23 +4179,13 @@ static void smack_inet_csk_clone(struct sock *sk,
static int smack_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
+ struct smack_known **blob = smack_key(key);
struct smack_known *skp = smk_of_task(smack_cred(cred));
- key->security = skp;
+ *blob = skp;
return 0;
}
-/**
- * smack_key_free - Clear the key security blob
- * @key: the object
- *
- * Clear the blob pointer
- */
-static void smack_key_free(struct key *key)
-{
- key->security = NULL;
-}
-
/**
* smack_key_permission - Smack access on a key
* @key_ref: gets to the object
@@ -4208,6 +4198,8 @@ static void smack_key_free(struct key *key)
static int smack_key_permission(key_ref_t key_ref,
const struct cred *cred, unsigned perm)
{
+ struct smack_known **blob;
+ struct smack_known *skp;
struct key *keyp;
struct smk_audit_info ad;
struct smack_known *tkp = smk_of_task(smack_cred(cred));
@@ -4227,7 +4219,9 @@ static int smack_key_permission(key_ref_t key_ref,
* If the key hasn't been initialized give it access so that
* it may do so.
*/
- if (keyp->security == NULL)
+ blob = smack_key(keyp);
+ skp = *blob;
+ if (skp == NULL)
return 0;
/*
* This should not occur
@@ -4247,8 +4241,8 @@ static int smack_key_permission(key_ref_t key_ref,
request |= MAY_READ;
if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
request |= MAY_WRITE;
- rc = smk_access(tkp, keyp->security, request, &ad);
- rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
+ rc = smk_access(tkp, skp, request, &ad);
+ rc = smk_bu_note("key access", tkp, skp, request, rc);
return rc;
}
@@ -4263,11 +4257,12 @@ static int smack_key_permission(key_ref_t key_ref,
*/
static int smack_key_getsecurity(struct key *key, char **_buffer)
{
- struct smack_known *skp = key->security;
+ struct smack_known **blob = smack_key(key);
+ struct smack_known *skp = *blob;
size_t length;
char *copy;
- if (key->security == NULL) {
+ if (skp == NULL) {
*_buffer = NULL;
return 0;
}
@@ -4550,6 +4545,9 @@ struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
.lbs_file = sizeof(struct smack_known *),
.lbs_inode = sizeof(struct inode_smack),
.lbs_ipc = sizeof(struct smack_known *),
+#ifdef CONFIG_KEYS
+ .lbs_key = sizeof(struct smack_known *),
+#endif /* CONFIG_KEYS */
.lbs_msg_msg = sizeof(struct smack_known *),
.lbs_sock = sizeof(struct socket_smack),
.lbs_superblock = sizeof(struct superblock_smack),
@@ -4671,7 +4669,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
/* key management security hooks */
#ifdef CONFIG_KEYS
LSM_HOOK_INIT(key_alloc, smack_key_alloc),
- LSM_HOOK_INIT(key_free, smack_key_free),
LSM_HOOK_INIT(key_permission, smack_key_permission),
LSM_HOOK_INIT(key_getsecurity, smack_key_getsecurity),
#endif /* CONFIG_KEYS */
--
2.19.1
^ permalink raw reply related
* [PATCH 01/58] LSM: Infrastructure management of the superblock
From: Casey Schaufler @ 2019-05-31 23:30 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531233149.715-1-casey@schaufler-ca.com>
Move management of the superblock->sb_security blob out
of the individual security modules and into the security
infrastructure. Instead of allocating the blobs from within
the modules the modules tell the infrastructure how much
space is required, and the space is allocated there.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 1 +
security/security.c | 46 ++++++++++++++++++++----
security/selinux/hooks.c | 58 ++++++++++++-------------------
security/selinux/include/objsec.h | 6 ++++
security/selinux/ss/services.c | 3 +-
security/smack/smack.h | 6 ++++
security/smack/smack_lsm.c | 35 +++++--------------
7 files changed, 85 insertions(+), 70 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index a240a3fc5fc4..f9222a04968d 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2047,6 +2047,7 @@ struct lsm_blob_sizes {
int lbs_cred;
int lbs_file;
int lbs_inode;
+ int lbs_superblock;
int lbs_ipc;
int lbs_msg_msg;
int lbs_task;
diff --git a/security/security.c b/security/security.c
index 23cbb1a295a3..550988a0f024 100644
--- a/security/security.c
+++ b/security/security.c
@@ -172,6 +172,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
}
@@ -300,12 +301,13 @@ static void __init ordered_lsm_init(void)
for (lsm = ordered_lsms; *lsm; lsm++)
prepare_lsm(*lsm);
- init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
- init_debug("file blob size = %d\n", blob_sizes.lbs_file);
- init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
- init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
- init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
- init_debug("task blob size = %d\n", blob_sizes.lbs_task);
+ init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
+ init_debug("file blob size = %d\n", blob_sizes.lbs_file);
+ init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
+ init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
+ init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
+ init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+ init_debug("task blob size = %d\n", blob_sizes.lbs_task);
/*
* Create any kmem_caches needed for blobs
@@ -603,6 +605,27 @@ static void __init lsm_early_task(struct task_struct *task)
panic("%s: Early task alloc failed.\n", __func__);
}
+/**
+ * lsm_superblock_alloc - allocate a composite superblock blob
+ * @sb: the superblock that needs a blob
+ *
+ * Allocate the superblock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_superblock_alloc(struct super_block *sb)
+{
+ if (blob_sizes.lbs_superblock == 0) {
+ sb->s_security = NULL;
+ return 0;
+ }
+
+ sb->s_security = kzalloc(blob_sizes.lbs_superblock, GFP_KERNEL);
+ if (sb->s_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
/*
* Hook list operation macros.
*
@@ -776,12 +799,21 @@ int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *
int security_sb_alloc(struct super_block *sb)
{
- return call_int_hook(sb_alloc_security, 0, sb);
+ int rc = lsm_superblock_alloc(sb);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(sb_alloc_security, 0, sb);
+ if (unlikely(rc))
+ security_sb_free(sb);
+ return rc;
}
void security_sb_free(struct super_block *sb)
{
call_void_hook(sb_free_security, sb);
+ kfree(sb->s_security);
+ sb->s_security = NULL;
}
void security_free_mnt_opts(void **mnt_opts)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1d0b37af2444..7478d8eda00a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -335,7 +335,7 @@ static void inode_free_security(struct inode *inode)
if (!isec)
return;
- sbsec = inode->i_sb->s_security;
+ sbsec = selinux_superblock(inode->i_sb);
/*
* As not all inode security structures are in a list, we check for
* empty list outside of the lock to make sure that we won't waste
@@ -366,11 +366,7 @@ static int file_alloc_security(struct file *file)
static int superblock_alloc_security(struct super_block *sb)
{
- struct superblock_security_struct *sbsec;
-
- sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
- if (!sbsec)
- return -ENOMEM;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
mutex_init(&sbsec->lock);
INIT_LIST_HEAD(&sbsec->isec_head);
@@ -379,18 +375,10 @@ static int superblock_alloc_security(struct super_block *sb)
sbsec->sid = SECINITSID_UNLABELED;
sbsec->def_sid = SECINITSID_FILE;
sbsec->mntpoint_sid = SECINITSID_UNLABELED;
- sb->s_security = sbsec;
return 0;
}
-static void superblock_free_security(struct super_block *sb)
-{
- struct superblock_security_struct *sbsec = sb->s_security;
- sb->s_security = NULL;
- kfree(sbsec);
-}
-
struct selinux_mnt_opts {
const char *fscontext, *context, *rootcontext, *defcontext;
};
@@ -507,7 +495,7 @@ static int selinux_is_genfs_special_handling(struct super_block *sb)
static int selinux_is_sblabel_mnt(struct super_block *sb)
{
- struct superblock_security_struct *sbsec = sb->s_security;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
/*
* IMPORTANT: Double-check logic in this function when adding a new
@@ -535,7 +523,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
static int sb_finish_set_opts(struct super_block *sb)
{
- struct superblock_security_struct *sbsec = sb->s_security;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
struct dentry *root = sb->s_root;
struct inode *root_inode = d_backing_inode(root);
int rc = 0;
@@ -648,7 +636,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
unsigned long *set_kern_flags)
{
const struct cred *cred = current_cred();
- struct superblock_security_struct *sbsec = sb->s_security;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
struct dentry *root = sbsec->sb->s_root;
struct selinux_mnt_opts *opts = mnt_opts;
struct inode_security_struct *root_isec;
@@ -881,8 +869,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
static int selinux_cmp_sb_context(const struct super_block *oldsb,
const struct super_block *newsb)
{
- struct superblock_security_struct *old = oldsb->s_security;
- struct superblock_security_struct *new = newsb->s_security;
+ struct superblock_security_struct *old = selinux_superblock(oldsb);
+ struct superblock_security_struct *new = selinux_superblock(newsb);
char oldflags = old->flags & SE_MNTMASK;
char newflags = new->flags & SE_MNTMASK;
@@ -914,8 +902,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
unsigned long *set_kern_flags)
{
int rc = 0;
- const struct superblock_security_struct *oldsbsec = oldsb->s_security;
- struct superblock_security_struct *newsbsec = newsb->s_security;
+ const struct superblock_security_struct *oldsbsec =
+ selinux_superblock(oldsb);
+ struct superblock_security_struct *newsbsec = selinux_superblock(newsb);
int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT);
int set_context = (oldsbsec->flags & CONTEXT_MNT);
@@ -1085,7 +1074,7 @@ static int show_sid(struct seq_file *m, u32 sid)
static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
{
- struct superblock_security_struct *sbsec = sb->s_security;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
int rc;
if (!(sbsec->flags & SE_SBINITIALIZED))
@@ -1377,7 +1366,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (isec->sclass == SECCLASS_FILE)
isec->sclass = inode_mode_to_security_class(inode->i_mode);
- sbsec = inode->i_sb->s_security;
+ sbsec = selinux_superblock(inode->i_sb);
if (!(sbsec->flags & SE_SBINITIALIZED)) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
@@ -1767,7 +1756,8 @@ selinux_determine_inode_label(const struct task_security_struct *tsec,
const struct qstr *name, u16 tclass,
u32 *_new_isid)
{
- const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
+ const struct superblock_security_struct *sbsec =
+ selinux_superblock(dir->i_sb);
if ((sbsec->flags & SE_SBINITIALIZED) &&
(sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) {
@@ -1798,7 +1788,7 @@ static int may_create(struct inode *dir,
int rc;
dsec = inode_security(dir);
- sbsec = dir->i_sb->s_security;
+ sbsec = selinux_superblock(dir->i_sb);
sid = tsec->sid;
@@ -1947,7 +1937,7 @@ static int superblock_has_perm(const struct cred *cred,
struct superblock_security_struct *sbsec;
u32 sid = cred_sid(cred);
- sbsec = sb->s_security;
+ sbsec = selinux_superblock(sb);
return avc_has_perm(&selinux_state,
sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
}
@@ -2578,11 +2568,6 @@ static int selinux_sb_alloc_security(struct super_block *sb)
return superblock_alloc_security(sb);
}
-static void selinux_sb_free_security(struct super_block *sb)
-{
- superblock_free_security(sb);
-}
-
static inline int opt_len(const char *s)
{
bool open_quote = false;
@@ -2653,7 +2638,7 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
{
struct selinux_mnt_opts *opts = mnt_opts;
- struct superblock_security_struct *sbsec = sb->s_security;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
u32 sid;
int rc;
@@ -2877,7 +2862,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
int rc;
char *context;
- sbsec = dir->i_sb->s_security;
+ sbsec = selinux_superblock(dir->i_sb);
newsid = tsec->create_sid;
@@ -3115,7 +3100,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
}
- sbsec = inode->i_sb->s_security;
+ sbsec = selinux_superblock(inode->i_sb);
if (!(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP;
@@ -3296,13 +3281,14 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
struct inode_security_struct *isec = inode_security_novalidate(inode);
- struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+ struct superblock_security_struct *sbsec;
u32 newsid;
int rc;
if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
+ sbsec = selinux_superblock(inode->i_sb);
if (!(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP;
@@ -6647,6 +6633,7 @@ struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
.lbs_inode = sizeof(struct inode_security_struct),
.lbs_ipc = sizeof(struct ipc_security_struct),
.lbs_msg_msg = sizeof(struct msg_security_struct),
+ .lbs_superblock = sizeof(struct superblock_security_struct),
};
static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
@@ -6675,7 +6662,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
- LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 231262d8eac9..d08d7e5d2f93 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -188,4 +188,10 @@ static inline struct ipc_security_struct *selinux_ipc(
return ipc->security + selinux_blob_sizes.lbs_ipc;
}
+static inline struct superblock_security_struct *selinux_superblock(
+ const struct super_block *superblock)
+{
+ return superblock->s_security + selinux_blob_sizes.lbs_superblock;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index ec62918521b1..e3f5d6aece66 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -50,6 +50,7 @@
#include <linux/audit.h>
#include <linux/mutex.h>
#include <linux/vmalloc.h>
+#include <linux/lsm_hooks.h>
#include <net/netlabel.h>
#include "flask.h"
@@ -2751,7 +2752,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
struct sidtab *sidtab;
int rc = 0;
struct ocontext *c;
- struct superblock_security_struct *sbsec = sb->s_security;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
const char *fstype = sb->s_type->name;
read_lock(&state->ss->policy_rwlock);
diff --git a/security/smack/smack.h b/security/smack/smack.h
index cf52af77d15e..caecbcba9942 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -375,6 +375,12 @@ static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
return ipc->security + smack_blob_sizes.lbs_ipc;
}
+static inline struct superblock_smack *smack_superblock(
+ const struct super_block *superblock)
+{
+ return superblock->s_security + smack_blob_sizes.lbs_superblock;
+}
+
/*
* Is the directory transmuting?
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 5c1613519d5a..807eff2ccce9 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -540,12 +540,7 @@ static int smack_syslog(int typefrom_file)
*/
static int smack_sb_alloc_security(struct super_block *sb)
{
- struct superblock_smack *sbsp;
-
- sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
-
- if (sbsp == NULL)
- return -ENOMEM;
+ struct superblock_smack *sbsp = smack_superblock(sb);
sbsp->smk_root = &smack_known_floor;
sbsp->smk_default = &smack_known_floor;
@@ -554,22 +549,10 @@ static int smack_sb_alloc_security(struct super_block *sb)
/*
* SMK_SB_INITIALIZED will be zero from kzalloc.
*/
- sb->s_security = sbsp;
return 0;
}
-/**
- * smack_sb_free_security - free a superblock blob
- * @sb: the superblock getting the blob
- *
- */
-static void smack_sb_free_security(struct super_block *sb)
-{
- kfree(sb->s_security);
- sb->s_security = NULL;
-}
-
struct smack_mnt_opts {
const char *fsdefault, *fsfloor, *fshat, *fsroot, *fstransmute;
};
@@ -781,7 +764,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
{
struct dentry *root = sb->s_root;
struct inode *inode = d_backing_inode(root);
- struct superblock_smack *sp = sb->s_security;
+ struct superblock_smack *sp = smack_superblock(sb);
struct inode_smack *isp;
struct smack_known *skp;
struct smack_mnt_opts *opts = mnt_opts;
@@ -880,7 +863,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
*/
static int smack_sb_statfs(struct dentry *dentry)
{
- struct superblock_smack *sbp = dentry->d_sb->s_security;
+ struct superblock_smack *sbp = smack_superblock(dentry->d_sb);
int rc;
struct smk_audit_info ad;
@@ -917,7 +900,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
return 0;
- sbsp = inode->i_sb->s_security;
+ sbsp = smack_superblock(inode->i_sb);
if ((sbsp->smk_flags & SMK_SB_UNTRUSTED) &&
isp->smk_task != sbsp->smk_root)
return 0;
@@ -1168,7 +1151,7 @@ static int smack_inode_rename(struct inode *old_inode,
*/
static int smack_inode_permission(struct inode *inode, int mask)
{
- struct superblock_smack *sbsp = inode->i_sb->s_security;
+ struct superblock_smack *sbsp = smack_superblock(inode->i_sb);
struct smk_audit_info ad;
int no_block = mask & MAY_NOT_BLOCK;
int rc;
@@ -1410,7 +1393,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
*/
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
struct super_block *sbp = dentry->d_sb;
- struct superblock_smack *sbsp = sbp->s_security;
+ struct superblock_smack *sbsp = smack_superblock(sbp);
isp->smk_inode = sbsp->smk_default;
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
@@ -1680,7 +1663,7 @@ static int smack_mmap_file(struct file *file,
isp = smack_inode(file_inode(file));
if (isp->smk_mmap == NULL)
return 0;
- sbsp = file_inode(file)->i_sb->s_security;
+ sbsp = smack_superblock(file_inode(file)->i_sb);
if (sbsp->smk_flags & SMK_SB_UNTRUSTED &&
isp->smk_mmap != sbsp->smk_root)
return -EACCES;
@@ -3288,7 +3271,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
goto unlockandout;
sbp = inode->i_sb;
- sbsp = sbp->s_security;
+ sbsp = smack_superblock(sbp);
/*
* We're going to use the superblock default label
* if there's no label on the file.
@@ -4575,6 +4558,7 @@ struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
.lbs_inode = sizeof(struct inode_smack),
.lbs_ipc = sizeof(struct smack_known *),
.lbs_msg_msg = sizeof(struct smack_known *),
+ .lbs_superblock = sizeof(struct superblock_smack),
};
static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
@@ -4586,7 +4570,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),
LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
- LSM_HOOK_INIT(sb_free_security, smack_sb_free_security),
LSM_HOOK_INIT(sb_free_mnt_opts, smack_free_mnt_opts),
LSM_HOOK_INIT(sb_eat_lsm_opts, smack_sb_eat_lsm_opts),
LSM_HOOK_INIT(sb_statfs, smack_sb_statfs),
--
2.19.1
^ permalink raw reply related
* [PATCH 00/58] LSM: Module stacking for AppArmor
From: Casey Schaufler @ 2019-05-31 23:30 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
This patchset provides the changes required for
the AppArmor security module to stack safely with any other.
A new process attribute identifies which security module
information should be reported by SO_PEERSEC and the
/proc/.../attr/current interface. This is provided by
/proc/.../attr/display. Writing the name of the security
module desired to this interface will set which LSM hooks
will be called for this information. The first security
module providing the hooks will be used by default.
The use of integer based security tokens (secids) is
generally (but not completely) replaced by a structure
lsm_export. The lsm_export structure can contain information
for each of the security modules that export information
outside the LSM layer.
The LSM interfaces that provide "secctx" text strings
have been changed to use a structure "lsm_context"
instead of a pointer/length pair. In some cases the
interfaces used a "char *" pointer and in others a
"void *". This was necessary to ensure that the correct
release mechanism for the text is used. It also makes
many of the interfaces cleaner.
https://github.com/cschaufler/lsm-stacking.git#stack-5.2-v1-apparmor
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
drivers/android/binder.c | 25 ++-
fs/kernfs/dir.c | 6 +-
fs/kernfs/inode.c | 31 ++-
fs/kernfs/kernfs-internal.h | 3 +-
fs/nfs/inode.c | 13 +-
fs/nfs/internal.h | 8 +-
fs/nfs/nfs4proc.c | 17 +-
fs/nfs/nfs4xdr.c | 16 +-
fs/nfsd/nfs4proc.c | 8 +-
fs/nfsd/nfs4xdr.c | 14 +-
fs/nfsd/vfs.c | 7 +-
fs/proc/base.c | 1 +
include/linux/cred.h | 3 +-
include/linux/lsm_hooks.h | 91 +++++----
include/linux/nfs4.h | 8 +-
include/linux/security.h | 133 +++++++++----
include/net/af_unix.h | 2 +-
include/net/netlabel.h | 10 +-
include/net/scm.h | 14 +-
kernel/audit.c | 43 ++--
kernel/audit.h | 9 +-
kernel/auditfilter.c | 6 +-
kernel/auditsc.c | 77 ++++----
kernel/cred.c | 15 +-
net/ipv4/cipso_ipv4.c | 13 +-
net/ipv4/ip_sockglue.c | 12 +-
net/netfilter/nf_conntrack_netlink.c | 29 ++-
net/netfilter/nf_conntrack_standalone.c | 16 +-
net/netfilter/nfnetlink_queue.c | 38 ++--
net/netfilter/nft_meta.c | 13 +-
net/netfilter/xt_SECMARK.c | 14 +-
net/netlabel/netlabel_kapi.c | 5 +-
net/netlabel/netlabel_unlabeled.c | 101 +++++-----
net/netlabel/netlabel_unlabeled.h | 2 +-
net/netlabel/netlabel_user.c | 13 +-
net/netlabel/netlabel_user.h | 2 +-
net/unix/af_unix.c | 6 +-
security/apparmor/audit.c | 4 +-
security/apparmor/include/audit.h | 2 +-
security/apparmor/include/net.h | 6 +-
security/apparmor/include/secid.h | 9 +-
security/apparmor/lsm.c | 64 +++---
security/apparmor/secid.c | 42 ++--
security/integrity/ima/ima.h | 14 +-
security/integrity/ima/ima_api.c | 9 +-
security/integrity/ima/ima_appraise.c | 6 +-
security/integrity/ima/ima_main.c | 34 ++--
security/integrity/ima/ima_policy.c | 19 +-
security/security.c | 338 +++++++++++++++++++++++++++-----
security/selinux/hooks.c | 259 ++++++++++++------------
security/selinux/include/audit.h | 5 +-
security/selinux/include/objsec.h | 42 +++-
security/selinux/netlabel.c | 25 +--
security/selinux/ss/services.c | 18 +-
security/smack/smack.h | 18 ++
security/smack/smack_lsm.c | 238 +++++++++++-----------
security/smack/smack_netfilter.c | 8 +-
security/smack/smackfs.c | 12 +-
58 files changed, 1217 insertions(+), 779 deletions(-)
^ permalink raw reply
* [PATCH 50/58] LSM: Add the release function to the lsm_context
From: Casey Schaufler @ 2019-05-31 23:10 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531231020.628-1-casey@schaufler-ca.com>
In order to ensure that the release function for a
lsm_context matches the LSM that allocated it an element
is added to the lsm_context structure to contain a
pointer to it. This function is called in security_release_secctx
instead of relying on a value in a hook list.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/lsm_hooks.h | 6 ------
include/linux/security.h | 1 +
security/apparmor/lsm.c | 1 -
security/apparmor/secid.c | 11 ++++++-----
security/security.c | 5 ++++-
security/selinux/hooks.c | 14 ++++++++------
security/smack/smack_lsm.c | 16 ++++++++--------
7 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 3a779a0f9e15..d1235a3cd8e9 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1326,10 +1326,6 @@
* @cp contains the security context.
* @l contains the pointer to the generated security data.
*
- * @release_secctx:
- * Release the security context.
- * @secdata contains the security context.
- *
* Security hooks for Audit
*
* @audit_rule_init:
@@ -1662,7 +1658,6 @@ union security_list_options {
int (*secid_to_secctx)(struct lsm_export *l, struct lsm_context *cp);
int (*secctx_to_secid)(const struct lsm_context *cp,
struct lsm_export *l);
- void (*release_secctx)(struct lsm_context *cp);
void (*inode_invalidate_secctx)(struct inode *inode);
int (*inode_notifysecctx)(struct inode *inode, struct lsm_context *cp);
@@ -1939,7 +1934,6 @@ struct security_hook_heads {
struct hlist_head ismaclabel;
struct hlist_head secid_to_secctx;
struct hlist_head secctx_to_secid;
- struct hlist_head release_secctx;
struct hlist_head inode_invalidate_secctx;
struct hlist_head inode_notifysecctx;
struct hlist_head inode_setsecctx;
diff --git a/include/linux/security.h b/include/linux/security.h
index 9a9de2bafa55..94c714310ab7 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -121,6 +121,7 @@ static inline bool lsm_export_equal(struct lsm_export *l, struct lsm_export *m)
struct lsm_context {
char *context;
u32 len;
+ void (*release)(struct lsm_context *cp); /* frees .context */
};
static inline void lsm_context_init(struct lsm_context *cp)
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 76c409737370..771b0ae24a5f 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1225,7 +1225,6 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid),
- LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),
};
/*
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 9dc17903a936..30fd4ad80948 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -81,6 +81,11 @@ static inline void aa_export_secid(struct lsm_export *l, u32 secid)
l->apparmor = secid;
}
+void apparmor_release_secctx(struct lsm_context *cp)
+{
+ kfree(cp->context);
+}
+
int apparmor_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp)
{
/* TODO: cache secctx and ref count so we don't have to recreate */
@@ -105,6 +110,7 @@ int apparmor_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp)
return -ENOMEM;
cp->len = len;
+ cp->release = apparmor_release_secctx;
return 0;
}
@@ -122,11 +128,6 @@ int apparmor_secctx_to_secid(const struct lsm_context *cp, struct lsm_export *l)
return 0;
}
-void apparmor_release_secctx(struct lsm_context *cp)
-{
- kfree(cp->context);
-}
-
/**
* aa_alloc_secid - allocate a new secid for a profile
* @label: the label to allocate a secid for
diff --git a/security/security.c b/security/security.c
index 6588172b3ec8..c8ce190dcdda 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1987,7 +1987,10 @@ EXPORT_SYMBOL(security_secctx_to_secid);
void security_release_secctx(struct lsm_context *cp)
{
- call_one_void_hook(release_secctx, cp);
+ if (WARN_ON(cp->release == NULL))
+ return;
+ cp->release(cp);
+ lsm_context_init(cp);
}
EXPORT_SYMBOL(security_release_secctx);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7bf73493d10d..0e347a26c3d8 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2812,6 +2812,11 @@ static void selinux_inode_free_security(struct inode *inode)
inode_free_security(inode);
}
+static void selinux_release_secctx(struct lsm_context *cp)
+{
+ kfree(cp->context);
+}
+
static int selinux_dentry_init_security(struct dentry *dentry, int mode,
const struct qstr *name,
struct lsm_context *cp)
@@ -2826,6 +2831,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
if (rc)
return rc;
+ cp->release = selinux_release_secctx;
return security_sid_to_context(&selinux_state, newsid, &cp->context,
&cp->len);
}
@@ -6306,6 +6312,7 @@ static int selinux_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp)
u32 secid;
selinux_import_secid(l, &secid);
+ cp->release = selinux_release_secctx;
if (l->flags & LSM_EXPORT_LENGTH)
return security_sid_to_context(&selinux_state, secid,
NULL, &cp->len);
@@ -6325,11 +6332,6 @@ static int selinux_secctx_to_secid(const struct lsm_context *cp,
return rc;
}
-static void selinux_release_secctx(struct lsm_context *cp)
-{
- kfree(cp->context);
-}
-
static void selinux_inode_invalidate_secctx(struct inode *inode)
{
struct inode_security_struct *isec = selinux_inode(inode);
@@ -6367,6 +6369,7 @@ static int selinux_inode_getsecctx(struct inode *inode, struct lsm_context *cp)
if (len < 0)
return len;
cp->len = len;
+ cp->release = selinux_release_secctx;
return 0;
}
#ifdef CONFIG_KEYS
@@ -6781,7 +6784,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
- LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1b5b3e421bff..e00346799cdf 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4425,6 +4425,12 @@ static int smack_ismaclabel(const char *name)
return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
}
+/*
+ * The smack_release_secctx hook does nothing
+ */
+static void smack_release_secctx(struct lsm_context *cp)
+{
+}
/**
* smack_secid_to_secctx - return the smack label for a secid
@@ -4444,6 +4450,7 @@ static int smack_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp)
cp->context = (l->flags & LSM_EXPORT_LENGTH) ? NULL : skp->smk_known;
cp->len = strlen(skp->smk_known);
+ cp->release = smack_release_secctx;
return 0;
}
@@ -4467,13 +4474,6 @@ static int smack_secctx_to_secid(const struct lsm_context *cp,
return 0;
}
-/*
- * The smack_release_secctx hook does nothing
- */
-static void smack_release_secctx(struct lsm_context *cp)
-{
-}
-
static int smack_inode_notifysecctx(struct inode *inode, struct lsm_context *cp)
{
return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, cp->context,
@@ -4491,6 +4491,7 @@ static int smack_inode_getsecctx(struct inode *inode, struct lsm_context *cp)
cp->context = skp->smk_known;
cp->len = strlen(skp->smk_known);
+ cp->release = smack_release_secctx;
return 0;
}
@@ -4713,7 +4714,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ismaclabel, smack_ismaclabel),
LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid),
- LSM_HOOK_INIT(release_secctx, smack_release_secctx),
LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),
--
2.19.1
^ permalink raw reply related
* [PATCH 48/58] LSM: Use lsm_context in security_secid_to_secctx
From: Casey Schaufler @ 2019-05-31 23:10 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20190531231020.628-1-casey@schaufler-ca.com>
Convert security_secid_to_secctx to use the lsm_context structure
instead of a context/secid pair. There is some scaffolding involved
that will be removed when the related data is updated.
Add a flag for lsm_export to indicate that the caller of
security_secid_to_secctx() is only interested in the length
of the context.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
drivers/android/binder.c | 2 +-
include/linux/security.h | 13 +++++++------
include/net/scm.h | 2 +-
kernel/audit.c | 5 ++---
kernel/auditsc.c | 10 +++++-----
net/ipv4/ip_sockglue.c | 2 +-
net/netfilter/nf_conntrack_netlink.c | 11 ++++++-----
net/netfilter/nf_conntrack_standalone.c | 2 +-
net/netfilter/nfnetlink_queue.c | 2 +-
net/netlabel/netlabel_unlabeled.c | 12 ++++--------
net/netlabel/netlabel_user.c | 3 +--
security/apparmor/secid.c | 3 +--
security/security.c | 13 ++-----------
security/selinux/hooks.c | 3 +++
security/smack/smack_lsm.c | 2 +-
15 files changed, 37 insertions(+), 48 deletions(-)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index c2cfef13257c..58033c003cc2 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3121,7 +3121,7 @@ static void binder_transaction(struct binder_proc *proc,
struct lsm_export le;
security_task_getsecid(proc->tsk, &le);
- ret = security_secid_to_secctx(&le, &lc.context, &lc.len);
+ ret = security_secid_to_secctx(&le, &lc);
if (ret) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
diff --git a/include/linux/security.h b/include/linux/security.h
index 57ce9b824eef..9a9de2bafa55 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -83,10 +83,11 @@ struct lsm_export {
u32 apparmor;
u32 flags;
};
-#define LSM_EXPORT_NONE 0x00
-#define LSM_EXPORT_SELINUX 0x01
-#define LSM_EXPORT_SMACK 0x02
-#define LSM_EXPORT_APPARMOR 0x04
+#define LSM_EXPORT_NONE 0x00000000
+#define LSM_EXPORT_SELINUX 0x00000001
+#define LSM_EXPORT_SMACK 0x00000002
+#define LSM_EXPORT_APPARMOR 0x00000004
+#define LSM_EXPORT_LENGTH 0x80000000 /* Only the length required */
static inline void lsm_export_init(struct lsm_export *l)
{
@@ -431,7 +432,7 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_ismaclabel(const char *name);
-int security_secid_to_secctx(struct lsm_export *l, char **secdata, u32 *seclen);
+int security_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp);
int security_secctx_to_secid(struct lsm_context *cp, struct lsm_export *l);
void security_release_secctx(struct lsm_context *cp);
@@ -1211,7 +1212,7 @@ static inline int security_ismaclabel(const char *name)
}
static inline int security_secid_to_secctx(struct lsm_export *l,
- char **secdata, u32 *seclen)
+ struct lsm_seccontext *cp)
{
return -EOPNOTSUPP;
}
diff --git a/include/net/scm.h b/include/net/scm.h
index 7e242ebdd258..b25ca3b6a514 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -96,7 +96,7 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
int err;
if (test_bit(SOCK_PASSSEC, &sock->flags)) {
- err = security_secid_to_secctx(&scm->le, &lc.context, &lc.len);
+ err = security_secid_to_secctx(&scm->le, &lc);
if (!err) {
put_cmsg(msg, SOL_SOCKET, SCM_SECURITY,
diff --git a/kernel/audit.c b/kernel/audit.c
index 269c76fefe40..203e5b14bea4 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1428,8 +1428,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
}
case AUDIT_SIGNAL_INFO:
if (lsm_export_any(&audit_sig_lsm)) {
- err = security_secid_to_secctx(&audit_sig_lsm,
- &lc.context, &lc.len);
+ err = security_secid_to_secctx(&audit_sig_lsm, &lc);
if (err)
return err;
}
@@ -2076,7 +2075,7 @@ int audit_log_task_context(struct audit_buffer *ab)
if (!lsm_export_any(&le))
return 0;
- error = security_secid_to_secctx(&le, &lc.context, &lc.len);
+ error = security_secid_to_secctx(&le, &lc);
if (error) {
if (error != -EINVAL)
goto error_path;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4dab81c7aca0..ceefd17467f9 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -938,7 +938,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
unsigned int sessionid,
struct lsm_export *l, char *comm)
{
- struct lsm_context lc = { .context = NULL, };
+ struct lsm_context lc;
struct audit_buffer *ab;
int rc = 0;
@@ -950,7 +950,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
if (lsm_export_any(l)) {
- if (security_secid_to_secctx(l, &lc.context, &lc.len)) {
+ if (security_secid_to_secctx(l, &lc)) {
audit_log_format(ab, " obj=(none)");
rc = 1;
} else {
@@ -1190,8 +1190,8 @@ static void show_special(struct audit_context *context, int *call_panic)
from_kgid(&init_user_ns, context->ipc.gid),
context->ipc.mode);
if (lsm_export_any(l)) {
- struct lsm_context lc = { .context = NULL, };
- if (security_secid_to_secctx(l, &lc.context, &lc.len)) {
+ struct lsm_context lc;
+ if (security_secid_to_secctx(l, &lc)) {
audit_log_format(ab, " osid=(unknown)");
*call_panic = 1;
} else {
@@ -1342,7 +1342,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
if (lsm_export_any(&n->olsm)) {
struct lsm_context lc;
- if (security_secid_to_secctx(&n->olsm, &lc.context, &lc.len)) {
+ if (security_secid_to_secctx(&n->olsm, &lc)) {
audit_log_format(ab, " osid=(unknown)");
if (call_panic)
*call_panic = 2;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 18a7fab8b2d3..56035b53952d 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -138,7 +138,7 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
if (err)
return;
- err = security_secid_to_secctx(&le, &lc.context, &lc.len);
+ err = security_secid_to_secctx(&le, &lc);
if (err)
return;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 49bce1b085ce..ea83909af6db 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -337,7 +337,7 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
le.selinux = ct->secmark;
le.smack = ct->secmark;
- ret = security_secid_to_secctx(&le, &lc.context, &lc.len);
+ ret = security_secid_to_secctx(&le, &lc);
if (ret)
return 0;
@@ -620,20 +620,21 @@ static inline size_t ctnetlink_acct_size(const struct nf_conn *ct)
static inline int ctnetlink_secctx_size(const struct nf_conn *ct)
{
#ifdef CONFIG_NF_CONNTRACK_SECMARK
- int len, ret;
+ int ret;
struct lsm_export le;
+ struct lsm_context lc;
lsm_export_init(&le);
- le.flags = LSM_EXPORT_SELINUX | LSM_EXPORT_SMACK;
+ le.flags = LSM_EXPORT_SELINUX | LSM_EXPORT_SMACK | LSM_EXPORT_LENGTH;
le.selinux = ct->secmark;
le.smack = ct->secmark;
- ret = security_secid_to_secctx(&le, NULL, &len);
+ ret = security_secid_to_secctx(&le, &lc);
if (ret)
return 0;
return nla_total_size(0) /* CTA_SECCTX */
- + nla_total_size(sizeof(char) * len); /* CTA_SECCTX_NAME */
+ + nla_total_size(sizeof(char) * lc.len); /* CTA_SECCTX_NAME */
#else
return 0;
#endif
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 97d16a51504b..797abf443a34 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -182,7 +182,7 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
le.selinux = ct->secmark;
le.smack = ct->secmark;
- ret = security_secid_to_secctx(&le, &lc.context, &lc.len);
+ ret = security_secid_to_secctx(&le, &lc);
if (ret)
return;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index b70871693368..4a3d4b52caef 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -322,7 +322,7 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
le.flags = LSM_EXPORT_SELINUX | LSM_EXPORT_SMACK;
le.selinux = skb->secmark;
le.smack = skb->secmark;
- security_secid_to_secctx(&le, &lc.context, &lc.len);
+ security_secid_to_secctx(&le, &lc);
*secdata = lc.context;
}
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 4c4a8f6df261..336d315ee8eb 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -450,7 +450,7 @@ int netlbl_unlhsh_add(struct net *net,
rcu_read_unlock();
if (audit_buf != NULL) {
struct lsm_context lc;
- if (security_secid_to_secctx(l, &lc.context, &lc.len) == 0) {
+ if (security_secid_to_secctx(l, &lc) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", lc.context);
security_release_secctx(&lc);
}
@@ -504,8 +504,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
if (dev != NULL)
dev_put(dev);
if (entry != NULL &&
- security_secid_to_secctx(&entry->le,
- &lc.context, &lc.len) == 0) {
+ security_secid_to_secctx(&entry->le, &lc) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", lc.context);
security_release_secctx(&lc);
}
@@ -544,8 +543,6 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
struct netlbl_unlhsh_addr6 *entry;
struct audit_buffer *audit_buf;
struct net_device *dev;
- char *secctx;
- u32 secctx_len;
spin_lock(&netlbl_unlhsh_lock);
list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
@@ -566,8 +563,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
if (dev != NULL)
dev_put(dev);
if (entry != NULL &&
- security_secid_to_secctx(&entry->le,
- &lc.context, &lc.len) == 0) {
+ security_secid_to_secctx(&entry->le, &lc) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", lc.context);
security_release_secctx(&lc);
}
@@ -1137,7 +1133,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
lep = (struct lsm_export *)&addr6->le;
}
- ret_val = security_secid_to_secctx(lep, &lc.context, &lc.len);
+ ret_val = security_secid_to_secctx(lep, &lc);
if (ret_val != 0)
goto list_cb_failure;
ret_val = nla_put(cb_arg->skb,
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 0418f0935199..11ea98525c4e 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -112,8 +112,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
audit_info->sessionid);
if (lsm_export_any(&audit_info->le) &&
- security_secid_to_secctx(&audit_info->le, &lc.context,
- &lc.len) == 0) {
+ security_secid_to_secctx(&audit_info->le, &lc) == 0) {
audit_log_format(audit_buf, " subj=%s", lc.context);
security_release_secctx(&lc);
}
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 46c8b9a67ac7..9dc17903a936 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -92,8 +92,7 @@ int apparmor_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp)
if (!label)
return -EINVAL;
- /* scaffolding check - Casey */
- if (cp)
+ if (!(l->flags & LSM_EXPORT_LENGTH))
len = aa_label_asxprint(&cp->context, root_ns, label,
FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT,
diff --git a/security/security.c b/security/security.c
index 3da7302d20ec..6588172b3ec8 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1972,18 +1972,9 @@ int security_ismaclabel(const char *name)
}
EXPORT_SYMBOL(security_ismaclabel);
-int security_secid_to_secctx(struct lsm_export *l, char **secdata, u32 *seclen)
+int security_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp)
{
- struct lsm_context lc = { .context = NULL, .len = 0, };
- int rc;
-
- rc = call_one_int_hook(secid_to_secctx, -EOPNOTSUPP, l, &lc);
- if (secdata)
- *secdata = lc.context;
- else
- security_release_secctx(&lc);
- *seclen = lc.len;
- return rc;
+ return call_one_int_hook(secid_to_secctx, -EOPNOTSUPP, l, cp);
}
EXPORT_SYMBOL(security_secid_to_secctx);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 332296f69f76..7bf73493d10d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6306,6 +6306,9 @@ static int selinux_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp)
u32 secid;
selinux_import_secid(l, &secid);
+ if (l->flags & LSM_EXPORT_LENGTH)
+ return security_sid_to_context(&selinux_state, secid,
+ NULL, &cp->len);
return security_sid_to_context(&selinux_state, secid,
&cp->context, &cp->len);
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index cf27905ccaa5..1b5b3e421bff 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4442,7 +4442,7 @@ static int smack_secid_to_secctx(struct lsm_export *l, struct lsm_context *cp)
smack_import_secid(l, &secid);
skp = smack_from_secid(secid);
- cp->context = skp->smk_known;
+ cp->context = (l->flags & LSM_EXPORT_LENGTH) ? NULL : skp->smk_known;
cp->len = strlen(skp->smk_known);
return 0;
}
--
2.19.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox