* [PATCH v13 10/25] LSM: Use lsmblob in security_inode_getsecid
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Change the security_inode_getsecid() interface to fill in a
lsmblob structure instead of a u32 secid. This allows for its
callers to gather data from all registered LSMs. Data is provided
for IMA and audit.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
cc: linux-integrity@vger.kernel.org
---
include/linux/security.h | 7 ++++---
kernel/auditsc.c | 6 +++++-
security/integrity/ima/ima_policy.c | 4 +---
security/security.c | 11 +++++++++--
4 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index b6d5475f8196..e0acc09a79fe 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -409,7 +409,7 @@ int security_inode_killpriv(struct dentry *dentry);
int security_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
-void security_inode_getsecid(struct inode *inode, u32 *secid);
+void security_inode_getsecid(struct inode *inode, struct lsmblob *blob);
int security_inode_copy_up(struct dentry *src, struct cred **new);
int security_inode_copy_up_xattr(const char *name);
int security_kernfs_init_security(struct kernfs_node *kn_dir,
@@ -924,9 +924,10 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer,
return 0;
}
-static inline void security_inode_getsecid(struct inode *inode, u32 *secid)
+static inline void security_inode_getsecid(struct inode *inode,
+ struct lsmblob *blob)
{
- *secid = 0;
+ lsmblob_init(blob, 0);
}
static inline int security_inode_copy_up(struct dentry *src, struct cred **new)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index cccb681ad081..5752e51883d5 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1931,13 +1931,17 @@ static void audit_copy_inode(struct audit_names *name,
const struct dentry *dentry,
struct inode *inode, unsigned int flags)
{
+ struct lsmblob blob;
+
name->ino = inode->i_ino;
name->dev = inode->i_sb->s_dev;
name->mode = inode->i_mode;
name->uid = inode->i_uid;
name->gid = inode->i_gid;
name->rdev = inode->i_rdev;
- security_inode_getsecid(inode, &name->osid);
+ security_inode_getsecid(inode, &blob);
+ /* scaffolding until osid is updated */
+ name->osid = blob.secid[0];
if (flags & AUDIT_INODE_NOEVAL) {
name->fcap_ver = -1;
return;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 68fe533f8a4f..c2118bb071bb 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -413,7 +413,6 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
return false;
for (i = 0; i < MAX_LSM_RULES; i++) {
int rc = 0;
- u32 osid;
struct lsmblob blob;
if (!rule->lsm[i].rule)
@@ -423,8 +422,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
case LSM_OBJ_USER:
case LSM_OBJ_ROLE:
case LSM_OBJ_TYPE:
- security_inode_getsecid(inode, &osid);
- lsmblob_init(&blob, osid);
+ security_inode_getsecid(inode, &blob);
rc = security_filter_rule_match(&blob,
rule->lsm[i].type,
Audit_equal,
diff --git a/security/security.c b/security/security.c
index 7a170c02f8df..88e341ebab60 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1386,9 +1386,16 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
}
EXPORT_SYMBOL(security_inode_listsecurity);
-void security_inode_getsecid(struct inode *inode, u32 *secid)
+void security_inode_getsecid(struct inode *inode, struct lsmblob *blob)
{
- call_void_hook(inode_getsecid, inode, secid);
+ struct security_hook_list *hp;
+
+ lsmblob_init(blob, 0);
+ hlist_for_each_entry(hp, &security_hook_heads.inode_getsecid, list) {
+ if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+ continue;
+ hp->hook.inode_getsecid(inode, &blob->secid[hp->lsmid->slot]);
+ }
}
int security_inode_copy_up(struct dentry *src, struct cred **new)
--
2.20.1
^ permalink raw reply related
* [PATCH v13 11/25] LSM: Use lsmblob in security_cred_getsecid
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Change the security_cred_getsecid() interface to fill in a
lsmblob instead of a u32 secid. The associated data elements
in the audit sub-system are changed from a secid to a lsmblob
to accommodate multiple possible LSM audit users.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: linux-integrity@vger.kernel.org
---
include/linux/security.h | 2 +-
kernel/audit.c | 19 +++++++-----------
kernel/audit.h | 5 +++--
kernel/auditsc.c | 33 +++++++++++--------------------
security/integrity/ima/ima_main.c | 8 ++++----
security/security.c | 12 ++++++++---
6 files changed, 36 insertions(+), 43 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index e0acc09a79fe..d12b5e828b8d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -436,7 +436,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
void security_cred_free(struct cred *cred);
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
void security_transfer_creds(struct cred *new, const struct cred *old);
-void security_cred_getsecid(const struct cred *c, u32 *secid);
+void security_cred_getsecid(const struct cred *c, struct lsmblob *blob);
int security_kernel_act_as(struct cred *new, struct lsmblob *blob);
int security_kernel_create_files_as(struct cred *new, struct inode *inode);
int security_kernel_module_request(char *kmod_name);
diff --git a/kernel/audit.c b/kernel/audit.c
index 6ee53e43c986..69b52f25038a 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -124,7 +124,7 @@ static u32 audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME;
/* The identity of the user shutting down the audit system. */
kuid_t audit_sig_uid = INVALID_UID;
pid_t audit_sig_pid = -1;
-u32 audit_sig_sid = 0;
+struct lsmblob audit_sig_lsm;
/* Records can be lost in several ways:
0) [suppressed in audit_alloc]
@@ -1416,23 +1416,21 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
}
case AUDIT_SIGNAL_INFO:
len = 0;
- if (audit_sig_sid) {
- struct lsmblob blob;
-
- lsmblob_init(&blob, audit_sig_sid);
- err = security_secid_to_secctx(&blob, &ctx, &len);
+ if (lsmblob_is_set(&audit_sig_lsm)) {
+ err = security_secid_to_secctx(&audit_sig_lsm, &ctx,
+ &len);
if (err)
return err;
}
sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
if (!sig_data) {
- if (audit_sig_sid)
+ if (lsmblob_is_set(&audit_sig_lsm))
security_release_secctx(ctx, len);
return -ENOMEM;
}
sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
sig_data->pid = audit_sig_pid;
- if (audit_sig_sid) {
+ if (lsmblob_is_set(&audit_sig_lsm)) {
memcpy(sig_data->ctx, ctx, len);
security_release_secctx(ctx, len);
}
@@ -2275,7 +2273,6 @@ int audit_set_loginuid(kuid_t loginuid)
int audit_signal_info(int sig, struct task_struct *t)
{
kuid_t uid = current_uid(), auid;
- struct lsmblob blob;
if (auditd_test_task(t) &&
(sig == SIGTERM || sig == SIGHUP ||
@@ -2286,9 +2283,7 @@ int audit_signal_info(int sig, struct task_struct *t)
audit_sig_uid = auid;
else
audit_sig_uid = uid;
- security_task_getsecid(current, &blob);
- /* scaffolding until audit_sig_sid is converted */
- audit_sig_sid = blob.secid[0];
+ security_task_getsecid(current, &audit_sig_lsm);
}
return audit_signal_info_syscall(t);
diff --git a/kernel/audit.h b/kernel/audit.h
index 6fb7160412d4..f65f516913c6 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -9,6 +9,7 @@
#include <linux/fs.h>
#include <linux/audit.h>
#include <linux/skbuff.h>
+#include <linux/security.h>
#include <uapi/linux/mqueue.h>
#include <linux/tty.h>
@@ -134,7 +135,7 @@ struct audit_context {
kuid_t target_auid;
kuid_t target_uid;
unsigned int target_sessionid;
- u32 target_sid;
+ struct lsmblob target_lsm;
char target_comm[TASK_COMM_LEN];
struct audit_tree_refs *trees, *first_trees;
@@ -329,7 +330,7 @@ extern char *audit_unpack_string(void **bufp, size_t *remain, size_t len);
extern pid_t audit_sig_pid;
extern kuid_t audit_sig_uid;
-extern u32 audit_sig_sid;
+extern struct lsmblob audit_sig_lsm;
extern int audit_filter(int msgtype, unsigned int listtype);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 5752e51883d5..e188fa1ade17 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -112,7 +112,7 @@ struct audit_aux_data_pids {
kuid_t target_auid[AUDIT_AUX_PIDS];
kuid_t target_uid[AUDIT_AUX_PIDS];
unsigned int target_sessionid[AUDIT_AUX_PIDS];
- u32 target_sid[AUDIT_AUX_PIDS];
+ struct lsmblob target_lsm[AUDIT_AUX_PIDS];
char target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN];
int pid_count;
};
@@ -957,14 +957,14 @@ static inline void audit_free_context(struct audit_context *context)
}
static int audit_log_pid_context(struct audit_context *context, pid_t pid,
- kuid_t auid, kuid_t uid, unsigned int sessionid,
- u32 sid, char *comm)
+ kuid_t auid, kuid_t uid,
+ unsigned int sessionid,
+ struct lsmblob *blob, char *comm)
{
struct audit_buffer *ab;
char *ctx = NULL;
u32 len;
int rc = 0;
- struct lsmblob blob;
ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
if (!ab)
@@ -973,9 +973,8 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
- if (sid) {
- lsmblob_init(&blob, sid);
- if (security_secid_to_secctx(&blob, &ctx, &len)) {
+ if (lsmblob_is_set(blob)) {
+ if (security_secid_to_secctx(blob, &ctx, &len)) {
audit_log_format(ab, " obj=(none)");
rc = 1;
} else {
@@ -1546,7 +1545,7 @@ static void audit_log_exit(void)
axs->target_auid[i],
axs->target_uid[i],
axs->target_sessionid[i],
- axs->target_sid[i],
+ &axs->target_lsm[i],
axs->target_comm[i]))
call_panic = 1;
}
@@ -1555,7 +1554,7 @@ static void audit_log_exit(void)
audit_log_pid_context(context, context->target_pid,
context->target_auid, context->target_uid,
context->target_sessionid,
- context->target_sid, context->target_comm))
+ &context->target_lsm, context->target_comm))
call_panic = 1;
if (context->pwd.dentry && context->pwd.mnt) {
@@ -1733,7 +1732,7 @@ void __audit_syscall_exit(int success, long return_code)
context->aux = NULL;
context->aux_pids = NULL;
context->target_pid = 0;
- context->target_sid = 0;
+ lsmblob_init(&context->target_lsm, 0);
context->sockaddr_len = 0;
context->type = 0;
context->fds[0] = -1;
@@ -2384,15 +2383,12 @@ int __audit_sockaddr(int len, void *a)
void __audit_ptrace(struct task_struct *t)
{
struct audit_context *context = audit_context();
- struct lsmblob blob;
context->target_pid = task_tgid_nr(t);
context->target_auid = audit_get_loginuid(t);
context->target_uid = task_uid(t);
context->target_sessionid = audit_get_sessionid(t);
- security_task_getsecid(t, &blob);
- /* scaffolding - until target_sid is converted */
- context->target_sid = blob.secid[0];
+ security_task_getsecid(t, &context->target_lsm);
memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
}
@@ -2408,7 +2404,6 @@ int audit_signal_info_syscall(struct task_struct *t)
struct audit_aux_data_pids *axp;
struct audit_context *ctx = audit_context();
kuid_t t_uid = task_uid(t);
- struct lsmblob blob;
if (!audit_signals || audit_dummy_context())
return 0;
@@ -2420,9 +2415,7 @@ int audit_signal_info_syscall(struct task_struct *t)
ctx->target_auid = audit_get_loginuid(t);
ctx->target_uid = t_uid;
ctx->target_sessionid = audit_get_sessionid(t);
- security_task_getsecid(t, &blob);
- /* scaffolding until target_sid is converted */
- ctx->target_sid = blob.secid[0];
+ security_task_getsecid(t, &ctx->target_lsm);
memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
return 0;
}
@@ -2443,9 +2436,7 @@ int audit_signal_info_syscall(struct task_struct *t)
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
axp->target_uid[axp->pid_count] = t_uid;
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
- security_task_getsecid(t, &blob);
- /* scaffolding until target_sid is converted */
- axp->target_sid[axp->pid_count] = blob.secid[0];
+ security_task_getsecid(t, &axp->target_lsm[axp->pid_count]);
memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
axp->pid_count++;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 7c4bfc051ebc..c8e3e234d446 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -412,7 +412,6 @@ int ima_file_mmap(struct file *file, unsigned long prot)
int ima_bprm_check(struct linux_binprm *bprm)
{
int ret;
- u32 secid;
struct lsmblob blob;
security_task_getsecid(current, &blob);
@@ -422,9 +421,10 @@ int ima_bprm_check(struct linux_binprm *bprm)
if (ret)
return ret;
- security_cred_getsecid(bprm->cred, &secid);
- return process_measurement(bprm->file, bprm->cred, secid, NULL, 0,
- MAY_EXEC, CREDS_CHECK);
+ security_cred_getsecid(bprm->cred, &blob);
+ /* scaffolding until process_measurement changes */
+ return process_measurement(bprm->file, bprm->cred, blob.secid[0],
+ NULL, 0, MAY_EXEC, CREDS_CHECK);
}
/**
diff --git a/security/security.c b/security/security.c
index 88e341ebab60..cf87e5ef2816 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1615,10 +1615,16 @@ void security_transfer_creds(struct cred *new, const struct cred *old)
call_void_hook(cred_transfer, new, old);
}
-void security_cred_getsecid(const struct cred *c, u32 *secid)
+void security_cred_getsecid(const struct cred *c, struct lsmblob *blob)
{
- *secid = 0;
- call_void_hook(cred_getsecid, c, secid);
+ struct security_hook_list *hp;
+
+ lsmblob_init(blob, 0);
+ hlist_for_each_entry(hp, &security_hook_heads.cred_getsecid, list) {
+ if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+ continue;
+ hp->hook.cred_getsecid(c, &blob->secid[hp->lsmid->slot]);
+ }
}
EXPORT_SYMBOL(security_cred_getsecid);
--
2.20.1
^ permalink raw reply related
* [PATCH v13 12/25] IMA: Change internal interfaces to use lsmblobs
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
The IMA interfaces ima_get_action() and ima_match_policy()
call LSM functions that use lsmblobs. Change the IMA functions
to pass the lsmblob to be compatible with the LSM functions.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: linux-integrity@vger.kernel.org
---
security/integrity/ima/ima.h | 11 ++++-----
security/integrity/ima/ima_api.c | 10 ++++-----
security/integrity/ima/ima_appraise.c | 5 ++---
security/integrity/ima/ima_main.c | 32 +++++++++++----------------
security/integrity/ima/ima_policy.c | 12 +++++-----
5 files changed, 32 insertions(+), 38 deletions(-)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d95b0ece7434..96b6662ea39f 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -205,9 +205,9 @@ extern const char *const func_tokens[];
struct modsig;
/* LIM API function definitions */
-int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
- int mask, enum ima_hooks func, int *pcr,
- struct ima_template_desc **template_desc);
+int ima_get_action(struct inode *inode, const struct cred *cred,
+ struct lsmblob *blob, int mask, enum ima_hooks func,
+ int *pcr, struct ima_template_desc **template_desc);
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file, void *buf, loff_t size,
@@ -232,8 +232,9 @@ void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
/* IMA policy related functions */
-int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
- enum ima_hooks func, int mask, int flags, int *pcr,
+int ima_match_policy(struct inode *inode, const struct cred *cred,
+ struct lsmblob *blob, enum ima_hooks func, int mask,
+ int flags, int *pcr,
struct ima_template_desc **template_desc);
void ima_init_policy(void);
void ima_update_policy(void);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 610759fe63b8..1ab769fa7df6 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -163,7 +163,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* ima_get_action - appraise & measure decision based on policy.
* @inode: pointer to inode to measure
* @cred: pointer to credentials structure to validate
- * @secid: secid of the task being validated
+ * @blob: LSM data of the task being validated
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
* MAY_APPEND)
* @func: caller identifier
@@ -181,15 +181,15 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* Returns IMA_MEASURE, IMA_APPRAISE mask.
*
*/
-int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
- int mask, enum ima_hooks func, int *pcr,
- struct ima_template_desc **template_desc)
+int ima_get_action(struct inode *inode, const struct cred *cred,
+ struct lsmblob *blob, int mask, enum ima_hooks func,
+ int *pcr, struct ima_template_desc **template_desc)
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;
flags &= ima_policy_flag;
- return ima_match_policy(inode, cred, secid, func, mask, flags, pcr,
+ return ima_match_policy(inode, cred, blob, func, mask, flags, pcr,
template_desc);
}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 37f540af45bb..01c755a242ac 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -54,9 +54,8 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
return 0;
security_task_getsecid(current, &blob);
- /* scaffolding the .secid[0] */
- return ima_match_policy(inode, current_cred(), blob.secid[0], func,
- mask, IMA_APPRAISE | IMA_HASH, NULL, NULL);
+ return ima_match_policy(inode, current_cred(), &blob, func, mask,
+ IMA_APPRAISE | IMA_HASH, NULL, NULL);
}
static int ima_fix_xattr(struct dentry *dentry,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index c8e3e234d446..86cc1419587e 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -190,8 +190,8 @@ void ima_file_free(struct file *file)
}
static int process_measurement(struct file *file, const struct cred *cred,
- u32 secid, char *buf, loff_t size, int mask,
- enum ima_hooks func)
+ struct lsmblob *blob, char *buf, loff_t size,
+ int mask, enum ima_hooks func)
{
struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint = NULL;
@@ -214,7 +214,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
* bitmask based on the appraise/audit/measurement policy.
* Included is the appraise submask.
*/
- action = ima_get_action(inode, cred, secid, mask, func, &pcr,
+ action = ima_get_action(inode, cred, blob, mask, func, &pcr,
&template_desc);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
@@ -388,8 +388,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
if (file && (prot & PROT_EXEC)) {
security_task_getsecid(current, &blob);
- /* scaffolding - until process_measurement changes */
- return process_measurement(file, current_cred(), blob.secid[0],
+ return process_measurement(file, current_cred(), &blob,
NULL, 0, MAY_EXEC, MMAP_CHECK);
}
@@ -415,16 +414,14 @@ int ima_bprm_check(struct linux_binprm *bprm)
struct lsmblob blob;
security_task_getsecid(current, &blob);
- /* scaffolding until process_measurement changes */
- ret = process_measurement(bprm->file, current_cred(), blob.secid[0],
- NULL, 0, MAY_EXEC, BPRM_CHECK);
+ ret = process_measurement(bprm->file, current_cred(), &blob, NULL, 0,
+ MAY_EXEC, BPRM_CHECK);
if (ret)
return ret;
security_cred_getsecid(bprm->cred, &blob);
- /* scaffolding until process_measurement changes */
- return process_measurement(bprm->file, bprm->cred, blob.secid[0],
- NULL, 0, MAY_EXEC, CREDS_CHECK);
+ return process_measurement(bprm->file, bprm->cred, &blob, NULL, 0,
+ MAY_EXEC, CREDS_CHECK);
}
/**
@@ -442,8 +439,7 @@ int ima_file_check(struct file *file, int mask)
struct lsmblob blob;
security_task_getsecid(current, &blob);
- /* scaffolding until process_measurement changes */
- return process_measurement(file, current_cred(), blob.secid[0], NULL, 0,
+ return process_measurement(file, current_cred(), &blob, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
MAY_APPEND), FILE_CHECK);
}
@@ -575,9 +571,8 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
func = read_idmap[read_id] ?: FILE_CHECK;
security_task_getsecid(current, &blob);
- /* scaffolding until process_measurement changes */
- return process_measurement(file, current_cred(), blob.secid[0], buf,
- size, MAY_READ, func);
+ return process_measurement(file, current_cred(), &blob, buf, size,
+ MAY_READ, func);
}
/**
@@ -669,9 +664,8 @@ void process_buffer_measurement(const void *buf, int size,
*/
if (func) {
security_task_getsecid(current, &blob);
- /* scaffolding */
- action = ima_get_action(NULL, current_cred(), blob.secid[0],
- 0, func, &pcr, &template);
+ action = ima_get_action(NULL, current_cred(), &blob, 0, func,
+ &pcr, &template);
if (!(action & IMA_MEASURE))
return;
}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index c2118bb071bb..1c617ae74558 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -368,7 +368,7 @@ int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
* Returns true on rule match, false on failure.
*/
static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
- const struct cred *cred, u32 secid,
+ const struct cred *cred, struct lsmblob *blob,
enum ima_hooks func, int mask)
{
int i;
@@ -431,7 +431,6 @@ 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:
- lsmblob_init(&blob, secid);
rc = security_filter_rule_match(&blob,
rule->lsm[i].type,
Audit_equal,
@@ -475,7 +474,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @inode: pointer to an inode for which the policy decision is being made
* @cred: pointer to a credentials structure for which the policy decision is
* being made
- * @secid: LSM secid of the task to be validated
+ * @blob: LSM data of the task to be validated
* @func: IMA hook identifier
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
* @pcr: set the pcr to extend
@@ -488,8 +487,9 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* list when walking it. Reads are many orders of magnitude more numerous
* than writes so ima_match_policy() is classical RCU candidate.
*/
-int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
- enum ima_hooks func, int mask, int flags, int *pcr,
+int ima_match_policy(struct inode *inode, const struct cred *cred,
+ struct lsmblob *blob, enum ima_hooks func, int mask,
+ int flags, int *pcr,
struct ima_template_desc **template_desc)
{
struct ima_rule_entry *entry;
@@ -504,7 +504,7 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
if (!(entry->action & actmask))
continue;
- if (!ima_match_rules(entry, inode, cred, secid, func, mask))
+ if (!ima_match_rules(entry, inode, cred, blob, func, mask))
continue;
action |= entry->flags & IMA_ACTION_FLAGS;
--
2.20.1
^ permalink raw reply related
* [PATCH v13 13/25] LSM: Specify which LSM to display
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Create a new entry "display" in the procfs attr directory for
controlling which LSM security information is displayed for a
process. A process can only read or write its own display value.
The name of an active LSM that supplies hooks for
human readable data may be written to "display" to set the
value. The name of the LSM currently in use can be read from
"display". At this point there can only be one LSM capable
of display active. A helper function lsm_task_display() is
provided to get the display slot for a task_struct.
Setting the "display" requires that all security modules using
setprocattr hooks allow the action. Each security module is
responsible for defining its policy.
AppArmor hook provided by John Johansen <john.johansen@canonical.com>
SELinux hook provided by Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
fs/proc/base.c | 1 +
include/linux/lsm_hooks.h | 15 +++
security/apparmor/include/apparmor.h | 3 +-
security/apparmor/lsm.c | 32 +++++
security/security.c | 168 ++++++++++++++++++++++++---
security/selinux/hooks.c | 11 ++
security/selinux/include/classmap.h | 2 +-
security/smack/smack_lsm.c | 7 ++
8 files changed, 220 insertions(+), 19 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index ebea9501afb8..950c200cb9ad 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2652,6 +2652,7 @@ static const struct pid_entry attr_dir_stuff[] = {
ATTR(NULL, "fscreate", 0666),
ATTR(NULL, "keycreate", 0666),
ATTR(NULL, "sockcreate", 0666),
+ ATTR(NULL, "display", 0666),
#ifdef CONFIG_SECURITY_SMACK
DIR("smack", 0555,
proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7eb808cde051..2bf82e1cf347 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2186,4 +2186,19 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
extern int lsm_inode_alloc(struct inode *inode);
+/**
+ * lsm_task_display - the "display" LSM for this task
+ * @task: The task to report on
+ *
+ * Returns the task's display LSM slot.
+ */
+static inline int lsm_task_display(struct task_struct *task)
+{
+ int *display = task->security;
+
+ if (display)
+ return *display;
+ return LSMBLOB_INVALID;
+}
+
#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 1fbabdb565a8..b1622fcb4394 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -28,8 +28,9 @@
#define AA_CLASS_SIGNAL 10
#define AA_CLASS_NET 14
#define AA_CLASS_LABEL 16
+#define AA_CLASS_DISPLAY_LSM 17
-#define AA_CLASS_LAST AA_CLASS_LABEL
+#define AA_CLASS_LAST AA_CLASS_DISPLAY_LSM
/* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 146d75e5e021..16b992235c11 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -612,6 +612,25 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
return error;
}
+
+static int profile_display_lsm(struct aa_profile *profile,
+ struct common_audit_data *sa)
+{
+ struct aa_perms perms = { };
+ unsigned int state;
+
+ state = PROFILE_MEDIATES(profile, AA_CLASS_DISPLAY_LSM);
+ if (state) {
+ aa_compute_perms(profile->policy.dfa, state, &perms);
+ aa_apply_modes_to_perms(profile, &perms);
+ aad(sa)->label = &profile->label;
+
+ return aa_check_perms(profile, &perms, AA_MAY_WRITE, sa, NULL);
+ }
+
+ return 0;
+}
+
static int apparmor_setprocattr(const char *name, void *value,
size_t size)
{
@@ -623,6 +642,19 @@ static int apparmor_setprocattr(const char *name, void *value,
if (size == 0)
return -EINVAL;
+ /* LSM infrastructure does actual setting of display if allowed */
+ if (!strcmp(name, "display")) {
+ struct aa_profile *profile;
+ struct aa_label *label;
+
+ aad(&sa)->info = "set display lsm";
+ label = begin_current_label_crit_section();
+ error = fn_for_each_confined(label, profile,
+ profile_display_lsm(profile, &sa));
+ end_current_label_crit_section(label);
+ return error;
+ }
+
/* AppArmor requires that the buffer must be null terminated atm */
if (args[size - 1] != '\0') {
/* null terminate */
diff --git a/security/security.c b/security/security.c
index cf87e5ef2816..aaf6db47dd8a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -27,6 +27,7 @@
#include <linux/backing-dev.h>
#include <linux/string.h>
#include <linux/msg.h>
+#include <linux/binfmts.h>
#include <net/flow.h>
#include <net/sock.h>
@@ -43,7 +44,14 @@ static struct kmem_cache *lsm_file_cache;
static struct kmem_cache *lsm_inode_cache;
char *lsm_names;
-static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;
+
+/*
+ * The task blob includes the "display" slot used for
+ * chosing which module presents contexts.
+ */
+static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init = {
+ .lbs_task = sizeof(int),
+};
/* Boot-time LSM user choice */
static __initdata const char *chosen_lsm_order;
@@ -438,8 +446,10 @@ static int lsm_append(const char *new, char **result)
/*
* Current index to use while initializing the lsmblob secid list.
+ * Pointers to the LSM id structures for local use.
*/
static int lsm_slot __lsm_ro_after_init;
+static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES];
/**
* security_add_hooks - Add a modules hooks to the hook lists.
@@ -459,6 +469,7 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
if (lsmid->slot == LSMBLOB_NEEDED) {
if (lsm_slot >= LSMBLOB_ENTRIES)
panic("%s Too many LSMs registered.\n", __func__);
+ lsm_slotlist[lsm_slot] = lsmid;
lsmid->slot = lsm_slot++;
init_debug("%s assigned lsmblob slot %d\n", lsmid->lsm,
lsmid->slot);
@@ -588,6 +599,8 @@ int lsm_inode_alloc(struct inode *inode)
*/
static int lsm_task_alloc(struct task_struct *task)
{
+ int *display;
+
if (blob_sizes.lbs_task == 0) {
task->security = NULL;
return 0;
@@ -596,6 +609,15 @@ static int lsm_task_alloc(struct task_struct *task)
task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
if (task->security == NULL)
return -ENOMEM;
+
+ /*
+ * The start of the task blob contains the "display" LSM slot number.
+ * Start with it set to the invalid slot number, indicating that the
+ * default first registered LSM be displayed.
+ */
+ display = task->security;
+ *display = LSMBLOB_INVALID;
+
return 0;
}
@@ -1551,14 +1573,26 @@ int security_file_open(struct file *file)
int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
{
+ int *odisplay = current->security;
+ int *ndisplay;
int rc = lsm_task_alloc(task);
- if (rc)
+ if (unlikely(rc))
return rc;
+
rc = call_int_hook(task_alloc, 0, task, clone_flags);
- if (unlikely(rc))
+ if (unlikely(rc)) {
security_task_free(task);
- return rc;
+ return rc;
+ }
+
+ if (odisplay) {
+ ndisplay = task->security;
+ if (ndisplay)
+ *ndisplay = *odisplay;
+ }
+
+ return 0;
}
void security_task_free(struct task_struct *task)
@@ -1955,23 +1989,110 @@ int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
char **value)
{
struct security_hook_list *hp;
+ int display = lsm_task_display(current);
+ int slot = 0;
+
+ if (!strcmp(name, "display")) {
+ /*
+ * lsm_slot will be 0 if there are no displaying modules.
+ */
+ if (lsm_slot == 0)
+ return -EINVAL;
+
+ /*
+ * Only allow getting the current process' display.
+ * There are too few reasons to get another process'
+ * display and too many LSM policy issues.
+ */
+ if (current != p)
+ return -EINVAL;
+
+ display = lsm_task_display(p);
+ if (display != LSMBLOB_INVALID)
+ slot = display;
+ *value = kstrdup(lsm_slotlist[slot]->lsm, GFP_KERNEL);
+ if (*value)
+ return strlen(*value);
+ return -ENOMEM;
+ }
hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm))
continue;
+ if (lsm == NULL && display != LSMBLOB_INVALID &&
+ display != hp->lsmid->slot)
+ continue;
return hp->hook.getprocattr(p, name, value);
}
return -EINVAL;
}
+/**
+ * security_setprocattr - Set process attributes via /proc
+ * @lsm: name of module involved, or NULL
+ * @name: name of the attribute
+ * @value: value to set the attribute to
+ * @size: size of the value
+ *
+ * Set the process attribute for the specified security module
+ * to the specified value. Note that this can only be used to set
+ * the process attributes for the current, or "self" process.
+ * The /proc code has already done this check.
+ *
+ * Returns 0 on success, an appropriate code otherwise.
+ */
int security_setprocattr(const char *lsm, const char *name, void *value,
size_t size)
{
struct security_hook_list *hp;
+ char *termed;
+ char *copy;
+ int *display = current->security;
+ int rc = -EINVAL;
+ int slot = 0;
+
+ if (!strcmp(name, "display")) {
+ /*
+ * Change the "display" value only if all the security
+ * modules that support setting a procattr allow it.
+ * It is assumed that all such security modules will be
+ * cooperative.
+ */
+ if (size == 0)
+ return -EINVAL;
+
+ hlist_for_each_entry(hp, &security_hook_heads.setprocattr,
+ list) {
+ rc = hp->hook.setprocattr(name, value, size);
+ if (rc < 0)
+ return rc;
+ }
+
+ rc = -EINVAL;
+
+ copy = kmemdup_nul(value, size, GFP_KERNEL);
+ if (copy == NULL)
+ return -ENOMEM;
+
+ termed = strsep(©, " \n");
+
+ for (slot = 0; slot < lsm_slot; slot++)
+ if (!strcmp(termed, lsm_slotlist[slot]->lsm)) {
+ *display = lsm_slotlist[slot]->slot;
+ rc = size;
+ break;
+ }
+
+ kfree(copy);
+ return rc;
+ }
hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm))
continue;
+ if (lsm == NULL && *display != LSMBLOB_INVALID &&
+ *display != hp->lsmid->slot)
+ continue;
return hp->hook.setprocattr(name, value, size);
}
return -EINVAL;
@@ -1991,15 +2112,15 @@ EXPORT_SYMBOL(security_ismaclabel);
int security_secid_to_secctx(struct lsmblob *blob, char **secdata, u32 *seclen)
{
struct security_hook_list *hp;
- int rc;
+ int display = lsm_task_display(current);
hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
continue;
- rc = hp->hook.secid_to_secctx(blob->secid[hp->lsmid->slot],
- secdata, seclen);
- if (rc != 0)
- return rc;
+ if (display == LSMBLOB_INVALID || display == hp->lsmid->slot)
+ return hp->hook.secid_to_secctx(
+ blob->secid[hp->lsmid->slot],
+ secdata, seclen);
}
return 0;
}
@@ -2009,16 +2130,15 @@ int security_secctx_to_secid(const char *secdata, u32 seclen,
struct lsmblob *blob)
{
struct security_hook_list *hp;
- int rc;
+ int display = lsm_task_display(current);
lsmblob_init(blob, 0);
hlist_for_each_entry(hp, &security_hook_heads.secctx_to_secid, list) {
if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
continue;
- rc = hp->hook.secctx_to_secid(secdata, seclen,
- &blob->secid[hp->lsmid->slot]);
- if (rc != 0)
- return rc;
+ if (display == LSMBLOB_INVALID || display == hp->lsmid->slot)
+ return hp->hook.secctx_to_secid(secdata, seclen,
+ &blob->secid[hp->lsmid->slot]);
}
return 0;
}
@@ -2026,7 +2146,14 @@ EXPORT_SYMBOL(security_secctx_to_secid);
void security_release_secctx(char *secdata, u32 seclen)
{
- call_void_hook(release_secctx, secdata, seclen);
+ struct security_hook_list *hp;
+ int display = lsm_task_display(current);
+
+ hlist_for_each_entry(hp, &security_hook_heads.release_secctx, list)
+ if (display == LSMBLOB_INVALID || display == hp->lsmid->slot) {
+ hp->hook.release_secctx(secdata, seclen);
+ return;
+ }
}
EXPORT_SYMBOL(security_release_secctx);
@@ -2151,8 +2278,15 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
- return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
- optval, optlen, len);
+ int display = lsm_task_display(current);
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream,
+ list)
+ if (display == LSMBLOB_INVALID || display == hp->lsmid->slot)
+ return hp->hook.socket_getpeersec_stream(sock, optval,
+ optlen, len);
+ return -ENOPROTOOPT;
}
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 97f2ee6e4080..b8501ca3c8f3 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6323,6 +6323,17 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
/*
* Basic control over ability to set these attributes at all.
*/
+
+ /*
+ * For setting display, we only perform a permission check;
+ * the actual update to the display value is handled by the
+ * LSM framework.
+ */
+ if (!strcmp(name, "display"))
+ return avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS2,
+ PROCESS2__SETDISPLAY, NULL);
+
if (!strcmp(name, "exec"))
error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 7db24855e12d..323da8a38c43 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -52,7 +52,7 @@ struct security_class_mapping secclass_map[] = {
"execmem", "execstack", "execheap", "setkeycreate",
"setsockcreate", "getrlimit", NULL } },
{ "process2",
- { "nnp_transition", "nosuid_transition", NULL } },
+ { "nnp_transition", "nosuid_transition", "setdisplay", NULL } },
{ "system",
{ "ipc_info", "syslog_read", "syslog_mod",
"syslog_console", "module_request", "module_load", NULL } },
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 82cbb3eeec76..9737ead06b39 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3518,6 +3518,13 @@ static int smack_setprocattr(const char *name, void *value, size_t size)
struct smack_known_list_elem *sklep;
int rc;
+ /*
+ * Allow the /proc/.../attr/current and SO_PEERSEC "display"
+ * to be reset at will.
+ */
+ if (strcmp(name, "display") == 0)
+ return 0;
+
if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
return -EPERM;
--
2.20.1
^ permalink raw reply related
* [PATCH v13 14/25] LSM: Ensure the correct LSM context releaser
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Add a new lsmcontext data structure to hold all the information
about a "security context", including the string, its size and
which LSM allocated the string. The allocation information is
necessary because LSMs have different policies regarding the
lifecycle of these strings. SELinux allocates and destroys
them on each use, whereas Smack provides a pointer to an entry
in a list that never goes away.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: linux-integrity@vger.kernel.org
cc: netdev@vger.kernel.org
---
drivers/android/binder.c | 10 ++++---
fs/ceph/xattr.c | 6 ++++-
fs/nfs/nfs4proc.c | 8 ++++--
fs/nfsd/nfs4xdr.c | 7 +++--
include/linux/security.h | 35 +++++++++++++++++++++++--
include/net/scm.h | 5 +++-
kernel/audit.c | 14 +++++++---
kernel/auditsc.c | 12 ++++++---
net/ipv4/ip_sockglue.c | 4 ++-
net/netfilter/nf_conntrack_netlink.c | 4 ++-
net/netfilter/nf_conntrack_standalone.c | 4 ++-
net/netfilter/nfnetlink_queue.c | 13 ++++++---
net/netlabel/netlabel_unlabeled.c | 19 +++++++++++---
net/netlabel/netlabel_user.c | 4 ++-
security/security.c | 11 ++++----
15 files changed, 121 insertions(+), 35 deletions(-)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 22fef6e130df..7559c5d5eea4 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2861,6 +2861,7 @@ static void binder_transaction(struct binder_proc *proc,
int t_debug_id = atomic_inc_return(&binder_last_id);
char *secctx = NULL;
u32 secctx_sz = 0;
+ struct lsmcontext scaff; /* scaffolding */
e = binder_transaction_log_add(&binder_transaction_log);
e->debug_id = t_debug_id;
@@ -3157,7 +3158,8 @@ static void binder_transaction(struct binder_proc *proc,
t->security_ctx = 0;
WARN_ON(1);
}
- security_release_secctx(secctx, secctx_sz);
+ lsmcontext_init(&scaff, secctx, secctx_sz, 0);
+ security_release_secctx(&scaff);
secctx = NULL;
}
t->buffer->debug_id = t->debug_id;
@@ -3490,8 +3492,10 @@ static void binder_transaction(struct binder_proc *proc,
binder_alloc_free_buf(&target_proc->alloc, t->buffer);
err_binder_alloc_buf_failed:
err_bad_extra_size:
- if (secctx)
- security_release_secctx(secctx, secctx_sz);
+ if (secctx) {
+ lsmcontext_init(&scaff, secctx, secctx_sz, 0);
+ security_release_secctx(&scaff);
+ }
err_get_secctx_failed:
kfree(tcomplete);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index cb18ee637cb7..ad501b5cad2c 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -1271,12 +1271,16 @@ int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx)
{
+#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
+ struct lsmcontext scaff; /* scaffolding */
+#endif
#ifdef CONFIG_CEPH_FS_POSIX_ACL
posix_acl_release(as_ctx->acl);
posix_acl_release(as_ctx->default_acl);
#endif
#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
- security_release_secctx(as_ctx->sec_ctx, as_ctx->sec_ctxlen);
+ lsmcontext_init(&scaff, as_ctx->sec_ctx, as_ctx->sec_ctxlen, 0);
+ security_release_secctx(&scaff);
#endif
if (as_ctx->pagelist)
ceph_pagelist_release(as_ctx->pagelist);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 76d37161409a..a30e36654c57 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -130,8 +130,12 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
static inline void
nfs4_label_release_security(struct nfs4_label *label)
{
- if (label)
- security_release_secctx(label->label, label->len);
+ struct lsmcontext scaff; /* scaffolding */
+
+ if (label) {
+ lsmcontext_init(&scaff, label->label, label->len, 0);
+ security_release_secctx(&scaff);
+ }
}
static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
{
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index d2dc4c0e22e8..e20011281915 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2421,6 +2421,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
int err;
struct nfs4_acl *acl = NULL;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ struct lsmcontext scaff; /* scaffolding */
void *context = NULL;
int contextlen;
#endif
@@ -2923,8 +2924,10 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
out:
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
- if (context)
- security_release_secctx(context, contextlen);
+ if (context) {
+ lsmcontext_init(&scaff, context, contextlen, 0); /*scaffolding*/
+ security_release_secctx(&scaff);
+ }
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
kfree(acl);
if (tempfh) {
diff --git a/include/linux/security.h b/include/linux/security.h
index d12b5e828b8d..c040c959b413 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -128,6 +128,37 @@ enum lockdown_reason {
LOCKDOWN_CONFIDENTIALITY_MAX,
};
+/*
+ * A "security context" is the text representation of
+ * the information used by LSMs.
+ * This structure contains the string, its length, and which LSM
+ * it is useful for.
+ */
+struct lsmcontext {
+ char *context; /* Provided by the module */
+ u32 len;
+ int slot; /* Identifies the module */
+};
+
+/**
+ * lsmcontext_init - initialize an lsmcontext structure.
+ * @cp: Pointer to the context to initialize
+ * @context: Initial context, or NULL
+ * @size: Size of context, or 0
+ * @slot: Which LSM provided the context
+ *
+ * Fill in the lsmcontext from the provided information.
+ * This is a scaffolding function that will be removed when
+ * lsmcontext integration is complete.
+ */
+static inline void lsmcontext_init(struct lsmcontext *cp, char *context,
+ u32 size, int slot)
+{
+ cp->slot = slot;
+ cp->context = context;
+ cp->len = size;
+}
+
/*
* Data exported by the security modules
*
@@ -498,7 +529,7 @@ int security_ismaclabel(const char *name);
int security_secid_to_secctx(struct lsmblob *blob, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen,
struct lsmblob *blob);
-void security_release_secctx(char *secdata, u32 seclen);
+void security_release_secctx(struct lsmcontext *cp);
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);
@@ -1312,7 +1343,7 @@ static inline int security_secctx_to_secid(const char *secdata,
return -EOPNOTSUPP;
}
-static inline void security_release_secctx(char *secdata, u32 seclen)
+static inline void security_release_secctx(struct lsmcontext *cp)
{
}
diff --git a/include/net/scm.h b/include/net/scm.h
index 31ae605fcc0a..30ba801c91bd 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -92,6 +92,7 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
#ifdef CONFIG_SECURITY_NETWORK
static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
{
+ struct lsmcontext context;
char *secdata;
u32 seclen;
int err;
@@ -102,7 +103,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
if (!err) {
put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
- security_release_secctx(secdata, seclen);
+ /*scaffolding*/
+ lsmcontext_init(&context, secdata, seclen, 0);
+ security_release_secctx(&context);
}
}
}
diff --git a/kernel/audit.c b/kernel/audit.c
index 69b52f25038a..3305c4af43a8 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1180,6 +1180,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
struct audit_sig_info *sig_data;
char *ctx = NULL;
u32 len;
+ struct lsmcontext scaff; /* scaffolding */
err = audit_netlink_ok(skb, msg_type);
if (err)
@@ -1424,15 +1425,18 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
}
sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
if (!sig_data) {
- if (lsmblob_is_set(&audit_sig_lsm))
- security_release_secctx(ctx, len);
+ if (lsmblob_is_set(&audit_sig_lsm)) {
+ lsmcontext_init(&scaff, ctx, len, 0);
+ security_release_secctx(&scaff);
+ }
return -ENOMEM;
}
sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
sig_data->pid = audit_sig_pid;
if (lsmblob_is_set(&audit_sig_lsm)) {
memcpy(sig_data->ctx, ctx, len);
- security_release_secctx(ctx, len);
+ lsmcontext_init(&scaff, ctx, len, 0);
+ security_release_secctx(&scaff);
}
audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
sig_data, sizeof(*sig_data) + len);
@@ -2061,6 +2065,7 @@ int audit_log_task_context(struct audit_buffer *ab)
unsigned len;
int error;
struct lsmblob blob;
+ struct lsmcontext scaff; /* scaffolding */
security_task_getsecid(current, &blob);
if (!lsmblob_is_set(&blob))
@@ -2074,7 +2079,8 @@ int audit_log_task_context(struct audit_buffer *ab)
}
audit_log_format(ab, " subj=%s", ctx);
- security_release_secctx(ctx, len);
+ lsmcontext_init(&scaff, ctx, len, 0);
+ security_release_secctx(&scaff);
return 0;
error_path:
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e188fa1ade17..9774d9947128 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -962,6 +962,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
struct lsmblob *blob, char *comm)
{
struct audit_buffer *ab;
+ struct lsmcontext lsmcxt;
char *ctx = NULL;
u32 len;
int rc = 0;
@@ -979,7 +980,8 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
rc = 1;
} else {
audit_log_format(ab, " obj=%s", ctx);
- security_release_secctx(ctx, len);
+ lsmcontext_init(&lsmcxt, ctx, len, 0); /*scaffolding*/
+ security_release_secctx(&lsmcxt);
}
}
audit_log_format(ab, " ocomm=");
@@ -1192,6 +1194,7 @@ static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
static void show_special(struct audit_context *context, int *call_panic)
{
+ struct lsmcontext lsmcxt;
struct audit_buffer *ab;
int i;
@@ -1225,7 +1228,8 @@ static void show_special(struct audit_context *context, int *call_panic)
*call_panic = 1;
} else {
audit_log_format(ab, " obj=%s", ctx);
- security_release_secctx(ctx, len);
+ lsmcontext_init(&lsmcxt, ctx, len, 0);
+ security_release_secctx(&lsmcxt);
}
}
if (context->ipc.has_perm) {
@@ -1371,6 +1375,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
char *ctx = NULL;
u32 len;
struct lsmblob blob;
+ struct lsmcontext lsmcxt;
lsmblob_init(&blob, n->osid);
if (security_secid_to_secctx(&blob, &ctx, &len)) {
@@ -1379,7 +1384,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
*call_panic = 2;
} else {
audit_log_format(ab, " obj=%s", ctx);
- security_release_secctx(ctx, len);
+ lsmcontext_init(&lsmcxt, ctx, len, 0); /* scaffolding */
+ security_release_secctx(&lsmcxt);
}
}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 1ca97d0cb4a9..96d56a30ecca 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -130,6 +130,7 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
{
+ struct lsmcontext context;
struct lsmblob lb;
char *secdata;
u32 seclen;
@@ -144,7 +145,8 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
return;
put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
- security_release_secctx(secdata, seclen);
+ lsmcontext_init(&context, secdata, seclen, 0); /* scaffolding */
+ security_release_secctx(&context);
}
static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 873dbd95f84a..2f233f40c926 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -332,6 +332,7 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
int len, ret;
char *secctx;
struct lsmblob blob;
+ struct lsmcontext context;
lsmblob_init(&blob, ct->secmark);
ret = security_secid_to_secctx(&blob, &secctx, &len);
@@ -349,7 +350,8 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
ret = 0;
nla_put_failure:
- security_release_secctx(secctx, len);
+ lsmcontext_init(&context, secctx, len, 0); /* scaffolding */
+ security_release_secctx(&context);
return ret;
}
#else
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 183a85412155..8601fcb99f7a 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -176,6 +176,7 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
u32 len;
char *secctx;
struct lsmblob blob;
+ struct lsmcontext context;
lsmblob_init(&blob, ct->secmark);
ret = security_secid_to_secctx(&blob, &secctx, &len);
@@ -184,7 +185,8 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
seq_printf(s, "secctx=%s ", secctx);
- security_release_secctx(secctx, len);
+ lsmcontext_init(&context, secctx, len, 0); /* scaffolding */
+ security_release_secctx(&context);
}
#else
static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index bfa7f12fde99..cc3ef03ee198 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -395,6 +395,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
enum ip_conntrack_info uninitialized_var(ctinfo);
struct nfnl_ct_hook *nfnl_ct;
bool csum_verify;
+ struct lsmcontext scaff; /* scaffolding */
char *secdata = NULL;
u32 seclen = 0;
@@ -625,8 +626,10 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
}
nlh->nlmsg_len = skb->len;
- if (seclen)
- security_release_secctx(secdata, seclen);
+ if (seclen) {
+ lsmcontext_init(&scaff, secdata, seclen, 0);
+ security_release_secctx(&scaff);
+ }
return skb;
nla_put_failure:
@@ -634,8 +637,10 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
kfree_skb(skb);
net_err_ratelimited("nf_queue: error creating packet message\n");
nlmsg_failure:
- if (seclen)
- security_release_secctx(secdata, seclen);
+ if (seclen) {
+ lsmcontext_init(&scaff, secdata, seclen, 0);
+ security_release_secctx(&scaff);
+ }
return NULL;
}
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index e279b81d9545..288c005b44c7 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -373,6 +373,7 @@ int netlbl_unlhsh_add(struct net *net,
struct net_device *dev;
struct netlbl_unlhsh_iface *iface;
struct audit_buffer *audit_buf = NULL;
+ struct lsmcontext context;
char *secctx = NULL;
u32 secctx_len;
struct lsmblob blob;
@@ -443,7 +444,9 @@ int netlbl_unlhsh_add(struct net *net,
&secctx,
&secctx_len) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", secctx);
- security_release_secctx(secctx, secctx_len);
+ /* scaffolding */
+ lsmcontext_init(&context, secctx, secctx_len, 0);
+ security_release_secctx(&context);
}
audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
audit_log_end(audit_buf);
@@ -474,6 +477,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
struct netlbl_unlhsh_addr4 *entry;
struct audit_buffer *audit_buf;
struct net_device *dev;
+ struct lsmcontext context;
char *secctx;
u32 secctx_len;
struct lsmblob blob;
@@ -502,7 +506,9 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
security_secid_to_secctx(&blob,
&secctx, &secctx_len) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", secctx);
- security_release_secctx(secctx, secctx_len);
+ /* scaffolding */
+ lsmcontext_init(&context, secctx, secctx_len, 0);
+ security_release_secctx(&context);
}
audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
audit_log_end(audit_buf);
@@ -539,6 +545,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
struct netlbl_unlhsh_addr6 *entry;
struct audit_buffer *audit_buf;
struct net_device *dev;
+ struct lsmcontext context;
char *secctx;
u32 secctx_len;
struct lsmblob blob;
@@ -566,7 +573,8 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
security_secid_to_secctx(&blob,
&secctx, &secctx_len) == 0) {
audit_log_format(audit_buf, " sec_obj=%s", secctx);
- security_release_secctx(secctx, secctx_len);
+ lsmcontext_init(&context, secctx, secctx_len, 0);
+ security_release_secctx(&context);
}
audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
audit_log_end(audit_buf);
@@ -1080,6 +1088,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
int ret_val = -ENOMEM;
struct netlbl_unlhsh_walk_arg *cb_arg = arg;
struct net_device *dev;
+ struct lsmcontext context;
void *data;
u32 secid;
char *secctx;
@@ -1147,7 +1156,9 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
NLBL_UNLABEL_A_SECCTX,
secctx_len,
secctx);
- security_release_secctx(secctx, secctx_len);
+ /* scaffolding */
+ lsmcontext_init(&context, secctx, secctx_len, 0);
+ security_release_secctx(&context);
if (ret_val != 0)
goto list_cb_failure;
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 893301ae0131..ef139d8ae7cd 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -84,6 +84,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
struct netlbl_audit *audit_info)
{
struct audit_buffer *audit_buf;
+ struct lsmcontext context;
char *secctx;
u32 secctx_len;
struct lsmblob blob;
@@ -103,7 +104,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
if (audit_info->secid != 0 &&
security_secid_to_secctx(&blob, &secctx, &secctx_len) == 0) {
audit_log_format(audit_buf, " subj=%s", secctx);
- security_release_secctx(secctx, secctx_len);
+ lsmcontext_init(&context, secctx, secctx_len, 0);/*scaffolding*/
+ security_release_secctx(&context);
}
return audit_buf;
diff --git a/security/security.c b/security/security.c
index aaf6db47dd8a..6be4be40127e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2144,16 +2144,17 @@ int security_secctx_to_secid(const char *secdata, u32 seclen,
}
EXPORT_SYMBOL(security_secctx_to_secid);
-void security_release_secctx(char *secdata, u32 seclen)
+void security_release_secctx(struct lsmcontext *cp)
{
struct security_hook_list *hp;
- int display = lsm_task_display(current);
hlist_for_each_entry(hp, &security_hook_heads.release_secctx, list)
- if (display == LSMBLOB_INVALID || display == hp->lsmid->slot) {
- hp->hook.release_secctx(secdata, seclen);
- return;
+ if (cp->slot == hp->lsmid->slot) {
+ hp->hook.release_secctx(cp->context, cp->len);
+ break;
}
+
+ memset(cp, 0, sizeof(*cp));
}
EXPORT_SYMBOL(security_release_secctx);
--
2.20.1
^ permalink raw reply related
* [PATCH v13 15/25] LSM: Use lsmcontext in security_secid_to_secctx
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Replace the (secctx,seclen) pointer pair with a single
lsmcontext pointer to allow return of the LSM identifier
along with the context and context length. This allows
security_release_secctx() to know how to release the
context. Callers have been modified to use or save the
returned data from the new structure.
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: netdev@vger.kernel.org
---
drivers/android/binder.c | 26 +++++++---------
include/linux/security.h | 4 +--
include/net/scm.h | 10 ++-----
kernel/audit.c | 29 +++++++-----------
kernel/auditsc.c | 31 +++++++------------
net/ipv4/ip_sockglue.c | 7 ++---
net/netfilter/nf_conntrack_netlink.c | 14 +++++----
net/netfilter/nf_conntrack_standalone.c | 7 ++---
net/netfilter/nfnetlink_queue.c | 5 +++-
net/netlabel/netlabel_unlabeled.c | 40 ++++++++-----------------
net/netlabel/netlabel_user.c | 7 ++---
security/security.c | 10 +++++--
12 files changed, 74 insertions(+), 116 deletions(-)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 7559c5d5eea4..463372198099 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2859,9 +2859,7 @@ static void binder_transaction(struct binder_proc *proc,
binder_size_t last_fixup_min_off = 0;
struct binder_context *context = proc->context;
int t_debug_id = atomic_inc_return(&binder_last_id);
- char *secctx = NULL;
- u32 secctx_sz = 0;
- struct lsmcontext scaff; /* scaffolding */
+ struct lsmcontext lsmctx = { };
e = binder_transaction_log_add(&binder_transaction_log);
e->debug_id = t_debug_id;
@@ -3109,14 +3107,14 @@ static void binder_transaction(struct binder_proc *proc,
size_t added_size;
security_task_getsecid(proc->tsk, &blob);
- ret = security_secid_to_secctx(&blob, &secctx, &secctx_sz);
+ ret = security_secid_to_secctx(&blob, &lsmctx);
if (ret) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
return_error_line = __LINE__;
goto err_get_secctx_failed;
}
- added_size = ALIGN(secctx_sz, sizeof(u64));
+ added_size = ALIGN(lsmctx.len, sizeof(u64));
extra_buffers_size += added_size;
if (extra_buffers_size < added_size) {
/* integer overflow of extra_buffers_size */
@@ -3143,24 +3141,22 @@ static void binder_transaction(struct binder_proc *proc,
t->buffer = NULL;
goto err_binder_alloc_buf_failed;
}
- if (secctx) {
+ if (lsmctx.context) {
int err;
size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
ALIGN(tr->offsets_size, sizeof(void *)) +
ALIGN(extra_buffers_size, sizeof(void *)) -
- ALIGN(secctx_sz, sizeof(u64));
+ ALIGN(lsmctx.len, sizeof(u64));
t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset;
err = binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer, buf_offset,
- secctx, secctx_sz);
+ lsmctx.context, lsmctx.len);
if (err) {
t->security_ctx = 0;
WARN_ON(1);
}
- lsmcontext_init(&scaff, secctx, secctx_sz, 0);
- security_release_secctx(&scaff);
- secctx = NULL;
+ security_release_secctx(&lsmctx);
}
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;
@@ -3216,7 +3212,7 @@ static void binder_transaction(struct binder_proc *proc,
off_end_offset = off_start_offset + tr->offsets_size;
sg_buf_offset = ALIGN(off_end_offset, sizeof(void *));
sg_buf_end_offset = sg_buf_offset + extra_buffers_size -
- ALIGN(secctx_sz, sizeof(u64));
+ ALIGN(lsmctx.len, sizeof(u64));
off_min = 0;
for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
buffer_offset += sizeof(binder_size_t)) {
@@ -3492,10 +3488,8 @@ static void binder_transaction(struct binder_proc *proc,
binder_alloc_free_buf(&target_proc->alloc, t->buffer);
err_binder_alloc_buf_failed:
err_bad_extra_size:
- if (secctx) {
- lsmcontext_init(&scaff, secctx, secctx_sz, 0);
- security_release_secctx(&scaff);
- }
+ if (lsmctx.context)
+ security_release_secctx(&lsmctx);
err_get_secctx_failed:
kfree(tcomplete);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
diff --git a/include/linux/security.h b/include/linux/security.h
index c040c959b413..390cc0561bb3 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -526,7 +526,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 lsmblob *blob, char **secdata, u32 *seclen);
+int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp);
int security_secctx_to_secid(const char *secdata, u32 seclen,
struct lsmblob *blob);
void security_release_secctx(struct lsmcontext *cp);
@@ -1331,7 +1331,7 @@ static inline int security_ismaclabel(const char *name)
}
static inline int security_secid_to_secctx(struct lsmblob *blob,
- char **secdata, u32 *seclen)
+ struct lsmcontext *cp)
{
return -EOPNOTSUPP;
}
diff --git a/include/net/scm.h b/include/net/scm.h
index 30ba801c91bd..4a6ad8caf423 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -93,18 +93,14 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
{
struct lsmcontext context;
- char *secdata;
- u32 seclen;
int err;
if (test_bit(SOCK_PASSSEC, &sock->flags)) {
- err = security_secid_to_secctx(&scm->lsmblob, &secdata,
- &seclen);
+ err = security_secid_to_secctx(&scm->lsmblob, &context);
if (!err) {
- put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
- /*scaffolding*/
- lsmcontext_init(&context, secdata, seclen, 0);
+ put_cmsg(msg, SOL_SOCKET, SCM_SECURITY,
+ context.len, context.context);
security_release_secctx(&context);
}
}
diff --git a/kernel/audit.c b/kernel/audit.c
index 3305c4af43a8..224c7b4a1bc0 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1178,9 +1178,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
struct audit_buffer *ab;
u16 msg_type = nlh->nlmsg_type;
struct audit_sig_info *sig_data;
- char *ctx = NULL;
u32 len;
- struct lsmcontext scaff; /* scaffolding */
+ struct lsmcontext context = { };
err = audit_netlink_ok(skb, msg_type);
if (err)
@@ -1418,25 +1417,22 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case AUDIT_SIGNAL_INFO:
len = 0;
if (lsmblob_is_set(&audit_sig_lsm)) {
- err = security_secid_to_secctx(&audit_sig_lsm, &ctx,
- &len);
+ err = security_secid_to_secctx(&audit_sig_lsm,
+ &context);
if (err)
return err;
}
sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
if (!sig_data) {
- if (lsmblob_is_set(&audit_sig_lsm)) {
- lsmcontext_init(&scaff, ctx, len, 0);
- security_release_secctx(&scaff);
- }
+ if (lsmblob_is_set(&audit_sig_lsm))
+ security_release_secctx(&context);
return -ENOMEM;
}
sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
sig_data->pid = audit_sig_pid;
if (lsmblob_is_set(&audit_sig_lsm)) {
- memcpy(sig_data->ctx, ctx, len);
- lsmcontext_init(&scaff, ctx, len, 0);
- security_release_secctx(&scaff);
+ memcpy(sig_data->ctx, context.context, context.len);
+ security_release_secctx(&context);
}
audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
sig_data, sizeof(*sig_data) + len);
@@ -2061,26 +2057,23 @@ void audit_log_key(struct audit_buffer *ab, char *key)
int audit_log_task_context(struct audit_buffer *ab)
{
- char *ctx = NULL;
- unsigned len;
int error;
struct lsmblob blob;
- struct lsmcontext scaff; /* scaffolding */
+ struct lsmcontext context;
security_task_getsecid(current, &blob);
if (!lsmblob_is_set(&blob))
return 0;
- error = security_secid_to_secctx(&blob, &ctx, &len);
+ error = security_secid_to_secctx(&blob, &context);
if (error) {
if (error != -EINVAL)
goto error_path;
return 0;
}
- audit_log_format(ab, " subj=%s", ctx);
- lsmcontext_init(&scaff, ctx, len, 0);
- security_release_secctx(&scaff);
+ audit_log_format(ab, " subj=%s", context.context);
+ security_release_secctx(&context);
return 0;
error_path:
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 9774d9947128..7d66bb7497ef 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -962,9 +962,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
struct lsmblob *blob, char *comm)
{
struct audit_buffer *ab;
- struct lsmcontext lsmcxt;
- char *ctx = NULL;
- u32 len;
+ struct lsmcontext lsmctx;
int rc = 0;
ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
@@ -975,13 +973,12 @@ 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 (lsmblob_is_set(blob)) {
- if (security_secid_to_secctx(blob, &ctx, &len)) {
+ if (security_secid_to_secctx(blob, &lsmctx)) {
audit_log_format(ab, " obj=(none)");
rc = 1;
} else {
- audit_log_format(ab, " obj=%s", ctx);
- lsmcontext_init(&lsmcxt, ctx, len, 0); /*scaffolding*/
- security_release_secctx(&lsmcxt);
+ audit_log_format(ab, " obj=%s", lsmctx.context);
+ security_release_secctx(&lsmctx);
}
}
audit_log_format(ab, " ocomm=");
@@ -1194,7 +1191,6 @@ static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
static void show_special(struct audit_context *context, int *call_panic)
{
- struct lsmcontext lsmcxt;
struct audit_buffer *ab;
int i;
@@ -1218,17 +1214,15 @@ static void show_special(struct audit_context *context, int *call_panic)
from_kgid(&init_user_ns, context->ipc.gid),
context->ipc.mode);
if (osid) {
- char *ctx = NULL;
- u32 len;
+ struct lsmcontext lsmcxt;
struct lsmblob blob;
lsmblob_init(&blob, osid);
- if (security_secid_to_secctx(&blob, &ctx, &len)) {
+ if (security_secid_to_secctx(&blob, &lsmcxt)) {
audit_log_format(ab, " osid=%u", osid);
*call_panic = 1;
} else {
- audit_log_format(ab, " obj=%s", ctx);
- lsmcontext_init(&lsmcxt, ctx, len, 0);
+ audit_log_format(ab, " obj=%s", lsmcxt.context);
security_release_secctx(&lsmcxt);
}
}
@@ -1372,20 +1366,17 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
MAJOR(n->rdev),
MINOR(n->rdev));
if (n->osid != 0) {
- char *ctx = NULL;
- u32 len;
struct lsmblob blob;
- struct lsmcontext lsmcxt;
+ struct lsmcontext lsmctx;
lsmblob_init(&blob, n->osid);
- if (security_secid_to_secctx(&blob, &ctx, &len)) {
+ if (security_secid_to_secctx(&blob, &lsmctx)) {
audit_log_format(ab, " osid=%u", n->osid);
if (call_panic)
*call_panic = 2;
} else {
- audit_log_format(ab, " obj=%s", ctx);
- lsmcontext_init(&lsmcxt, ctx, len, 0); /* scaffolding */
- security_release_secctx(&lsmcxt);
+ audit_log_format(ab, " obj=%s", lsmctx.context);
+ security_release_secctx(&lsmctx);
}
}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 96d56a30ecca..27af7a6b8780 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -132,20 +132,17 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
{
struct lsmcontext context;
struct lsmblob lb;
- char *secdata;
- u32 seclen;
int err;
err = security_socket_getpeersec_dgram(NULL, skb, &lb);
if (err)
return;
- err = security_secid_to_secctx(&lb, &secdata, &seclen);
+ err = security_secid_to_secctx(&lb, &context);
if (err)
return;
- put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
- lsmcontext_init(&context, secdata, seclen, 0); /* scaffolding */
+ put_cmsg(msg, SOL_IP, SCM_SECURITY, context.len, context.context);
security_release_secctx(&context);
}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 2f233f40c926..255bcb886a2f 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -329,13 +329,12 @@ static int ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
{
struct nlattr *nest_secctx;
- int len, ret;
- char *secctx;
+ int ret;
struct lsmblob blob;
struct lsmcontext context;
lsmblob_init(&blob, ct->secmark);
- ret = security_secid_to_secctx(&blob, &secctx, &len);
+ ret = security_secid_to_secctx(&blob, &context);
if (ret)
return 0;
@@ -344,13 +343,12 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
if (!nest_secctx)
goto nla_put_failure;
- if (nla_put_string(skb, CTA_SECCTX_NAME, secctx))
+ if (nla_put_string(skb, CTA_SECCTX_NAME, context.context))
goto nla_put_failure;
nla_nest_end(skb, nest_secctx);
ret = 0;
nla_put_failure:
- lsmcontext_init(&context, secctx, len, 0); /* scaffolding */
security_release_secctx(&context);
return ret;
}
@@ -648,12 +646,16 @@ static inline int ctnetlink_secctx_size(const struct nf_conn *ct)
#ifdef CONFIG_NF_CONNTRACK_SECMARK
int len, ret;
struct lsmblob blob;
+ struct lsmcontext context;
lsmblob_init(&blob, ct->secmark);
- ret = security_secid_to_secctx(&blob, NULL, &len);
+ ret = security_secid_to_secctx(&blob, &context);
if (ret)
return 0;
+ len = context.len;
+ security_release_secctx(&context);
+
return nla_total_size(0) /* CTA_SECCTX */
+ nla_total_size(sizeof(char) * len); /* CTA_SECCTX_NAME */
#else
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 8601fcb99f7a..8969754d7fe9 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -173,19 +173,16 @@ static void ct_seq_stop(struct seq_file *s, void *v)
static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
{
int ret;
- u32 len;
- char *secctx;
struct lsmblob blob;
struct lsmcontext context;
lsmblob_init(&blob, ct->secmark);
- ret = security_secid_to_secctx(&blob, &secctx, &len);
+ ret = security_secid_to_secctx(&blob, &context);
if (ret)
return;
- seq_printf(s, "secctx=%s ", secctx);
+ seq_printf(s, "secctx=%s ", context.context);
- lsmcontext_init(&context, secctx, len, 0); /* scaffolding */
security_release_secctx(&context);
}
#else
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index cc3ef03ee198..2d6668fd026c 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -306,6 +306,7 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
u32 seclen = 0;
#if IS_ENABLED(CONFIG_NETWORK_SECMARK)
struct lsmblob blob;
+ struct lsmcontext context = { };
if (!skb || !sk_fullsock(skb->sk))
return 0;
@@ -314,10 +315,12 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
if (skb->secmark) {
lsmblob_init(&blob, skb->secmark);
- security_secid_to_secctx(&blob, secdata, &seclen);
+ security_secid_to_secctx(&blob, &context);
+ *secdata = context.context;
}
read_unlock_bh(&skb->sk->sk_callback_lock);
+ seclen = context.len;
#endif
return seclen;
}
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 288c005b44c7..c03fe9a4f7b9 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -374,8 +374,6 @@ int netlbl_unlhsh_add(struct net *net,
struct netlbl_unlhsh_iface *iface;
struct audit_buffer *audit_buf = NULL;
struct lsmcontext context;
- char *secctx = NULL;
- u32 secctx_len;
struct lsmblob blob;
if (addr_len != sizeof(struct in_addr) &&
@@ -440,12 +438,9 @@ int netlbl_unlhsh_add(struct net *net,
rcu_read_unlock();
if (audit_buf != NULL) {
lsmblob_init(&blob, secid);
- if (security_secid_to_secctx(&blob,
- &secctx,
- &secctx_len) == 0) {
- audit_log_format(audit_buf, " sec_obj=%s", secctx);
- /* scaffolding */
- lsmcontext_init(&context, secctx, secctx_len, 0);
+ if (security_secid_to_secctx(&blob, &context) == 0) {
+ audit_log_format(audit_buf, " sec_obj=%s",
+ context.context);
security_release_secctx(&context);
}
audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
@@ -478,8 +473,6 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
struct audit_buffer *audit_buf;
struct net_device *dev;
struct lsmcontext context;
- char *secctx;
- u32 secctx_len;
struct lsmblob blob;
spin_lock(&netlbl_unlhsh_lock);
@@ -503,11 +496,9 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
if (entry != NULL)
lsmblob_init(&blob, entry->secid);
if (entry != NULL &&
- security_secid_to_secctx(&blob,
- &secctx, &secctx_len) == 0) {
- audit_log_format(audit_buf, " sec_obj=%s", secctx);
- /* scaffolding */
- lsmcontext_init(&context, secctx, secctx_len, 0);
+ security_secid_to_secctx(&blob, &context) == 0) {
+ audit_log_format(audit_buf, " sec_obj=%s",
+ context.context);
security_release_secctx(&context);
}
audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
@@ -546,8 +537,6 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
struct audit_buffer *audit_buf;
struct net_device *dev;
struct lsmcontext context;
- char *secctx;
- u32 secctx_len;
struct lsmblob blob;
spin_lock(&netlbl_unlhsh_lock);
@@ -570,10 +559,9 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
if (entry != NULL)
lsmblob_init(&blob, entry->secid);
if (entry != NULL &&
- security_secid_to_secctx(&blob,
- &secctx, &secctx_len) == 0) {
- audit_log_format(audit_buf, " sec_obj=%s", secctx);
- lsmcontext_init(&context, secctx, secctx_len, 0);
+ security_secid_to_secctx(&blob, &context) == 0) {
+ audit_log_format(audit_buf, " sec_obj=%s",
+ context.context);
security_release_secctx(&context);
}
audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
@@ -1091,8 +1079,6 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
struct lsmcontext context;
void *data;
u32 secid;
- char *secctx;
- u32 secctx_len;
struct lsmblob blob;
data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
@@ -1149,15 +1135,13 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
}
lsmblob_init(&blob, secid);
- ret_val = security_secid_to_secctx(&blob, &secctx, &secctx_len);
+ ret_val = security_secid_to_secctx(&blob, &context);
if (ret_val != 0)
goto list_cb_failure;
ret_val = nla_put(cb_arg->skb,
NLBL_UNLABEL_A_SECCTX,
- secctx_len,
- secctx);
- /* scaffolding */
- lsmcontext_init(&context, secctx, secctx_len, 0);
+ context.len,
+ context.context);
security_release_secctx(&context);
if (ret_val != 0)
goto list_cb_failure;
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index ef139d8ae7cd..951ba0639d20 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -85,8 +85,6 @@ struct audit_buffer *netlbl_audit_start_common(int type,
{
struct audit_buffer *audit_buf;
struct lsmcontext context;
- char *secctx;
- u32 secctx_len;
struct lsmblob blob;
if (audit_enabled == AUDIT_OFF)
@@ -102,9 +100,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
lsmblob_init(&blob, audit_info->secid);
if (audit_info->secid != 0 &&
- security_secid_to_secctx(&blob, &secctx, &secctx_len) == 0) {
- audit_log_format(audit_buf, " subj=%s", secctx);
- lsmcontext_init(&context, secctx, secctx_len, 0);/*scaffolding*/
+ security_secid_to_secctx(&blob, &context) == 0) {
+ audit_log_format(audit_buf, " subj=%s", context.context);
security_release_secctx(&context);
}
diff --git a/security/security.c b/security/security.c
index 6be4be40127e..e80b71c03062 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2109,18 +2109,22 @@ int security_ismaclabel(const char *name)
}
EXPORT_SYMBOL(security_ismaclabel);
-int security_secid_to_secctx(struct lsmblob *blob, char **secdata, u32 *seclen)
+int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
{
struct security_hook_list *hp;
int display = lsm_task_display(current);
+ memset(cp, 0, sizeof(*cp));
+
hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
continue;
- if (display == LSMBLOB_INVALID || display == hp->lsmid->slot)
+ if (display == LSMBLOB_INVALID || display == hp->lsmid->slot) {
+ cp->slot = hp->lsmid->slot;
return hp->hook.secid_to_secctx(
blob->secid[hp->lsmid->slot],
- secdata, seclen);
+ &cp->context, &cp->len);
+ }
}
return 0;
}
--
2.20.1
^ permalink raw reply related
* [PATCH v13 17/25] LSM: Use lsmcontext in security_inode_getsecctx
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Change the security_inode_getsecctx() interface to fill
a lsmcontext structure instead of data and length pointers.
This provides the information about which LSM created the
context so that security_release_secctx() can use the
correct hook.
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
fs/nfsd/nfs4xdr.c | 23 +++++++++--------------
include/linux/security.h | 5 +++--
security/security.c | 13 +++++++++++--
3 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index e20011281915..98d20178e60f 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2304,11 +2304,11 @@ nfsd4_encode_layout_types(struct xdr_stream *xdr, u32 layout_types)
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
static inline __be32
nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
- void *context, int len)
+ struct lsmcontext *context)
{
__be32 *p;
- p = xdr_reserve_space(xdr, len + 4 + 4 + 4);
+ p = xdr_reserve_space(xdr, context->len + 4 + 4 + 4);
if (!p)
return nfserr_resource;
@@ -2318,13 +2318,13 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
*/
*p++ = cpu_to_be32(0); /* lfs */
*p++ = cpu_to_be32(0); /* pi */
- p = xdr_encode_opaque(p, context, len);
+ p = xdr_encode_opaque(p, context->context, context->len);
return 0;
}
#else
static inline __be32
nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
- void *context, int len)
+ struct lsmcontext *context)
{ return 0; }
#endif
@@ -2421,9 +2421,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
int err;
struct nfs4_acl *acl = NULL;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
- struct lsmcontext scaff; /* scaffolding */
- void *context = NULL;
- int contextlen;
+ struct lsmcontext context = { };
#endif
bool contextsupport = false;
struct nfsd4_compoundres *resp = rqstp->rq_resp;
@@ -2481,7 +2479,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
err = security_inode_getsecctx(d_inode(dentry),
- &context, &contextlen);
+ &context);
else
err = -EOPNOTSUPP;
contextsupport = (err == 0);
@@ -2911,8 +2909,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
- status = nfsd4_encode_security_label(xdr, rqstp, context,
- contextlen);
+ status = nfsd4_encode_security_label(xdr, rqstp, &context);
if (status)
goto out;
}
@@ -2924,10 +2921,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
out:
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
- if (context) {
- lsmcontext_init(&scaff, context, contextlen, 0); /*scaffolding*/
- security_release_secctx(&scaff);
- }
+ if (context.context)
+ security_release_secctx(&context);
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
kfree(acl);
if (tempfh) {
diff --git a/include/linux/security.h b/include/linux/security.h
index ea98dff5ec03..49d2a778020e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -533,7 +533,7 @@ void security_release_secctx(struct lsmcontext *cp);
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_inode_getsecctx(struct inode *inode, struct lsmcontext *cp);
int security_locked_down(enum lockdown_reason what);
#else /* CONFIG_SECURITY */
@@ -1358,7 +1358,8 @@ static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32
{
return -EOPNOTSUPP;
}
-static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+static inline int security_inode_getsecctx(struct inode *inode,
+ struct lsmcontext *cp)
{
return -EOPNOTSUPP;
}
diff --git a/security/security.c b/security/security.c
index 29f070aa172c..affd53f04805 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2201,9 +2201,18 @@ int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
}
EXPORT_SYMBOL(security_inode_setsecctx);
-int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+int security_inode_getsecctx(struct inode *inode, struct lsmcontext *cp)
{
- return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen);
+ struct security_hook_list *hp;
+
+ memset(cp, 0, sizeof(*cp));
+
+ hlist_for_each_entry(hp, &security_hook_heads.inode_getsecctx, list) {
+ cp->slot = hp->lsmid->slot;
+ return hp->hook.inode_getsecctx(inode, (void **)&cp->context,
+ &cp->len);
+ }
+ return -EOPNOTSUPP;
}
EXPORT_SYMBOL(security_inode_getsecctx);
--
2.20.1
^ permalink raw reply related
* [PATCH v13 16/25] LSM: Use lsmcontext in security_dentry_init_security
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Change the security_dentry_init_security() interface to
fill an lsmcontext structure instead of a void * data area
and a length. The lone caller of this interface is NFS4,
which may make copies of the data using its own mechanisms.
A rework of the nfs4 code to use the lsmcontext properly
is a significant project. SELinux is handled correctly, and
is the only current user.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
fs/nfs/nfs4proc.c | 15 ++++++++-------
include/linux/security.h | 7 +++----
security/security.c | 29 +++++++++++++++++++++++++----
3 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index a30e36654c57..6cd2463f890b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -112,6 +112,7 @@ static inline struct nfs4_label *
nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
struct iattr *sattr, struct nfs4_label *label)
{
+ struct lsmcontext context;
int err;
if (label == NULL)
@@ -121,21 +122,21 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
return NULL;
err = security_dentry_init_security(dentry, sattr->ia_mode,
- &dentry->d_name, (void **)&label->label, &label->len);
+ &dentry->d_name, &context);
+
+ label->label = context.context;
+ label->len = context.len;
+
if (err == 0)
return label;
return NULL;
+
}
static inline void
nfs4_label_release_security(struct nfs4_label *label)
{
- struct lsmcontext scaff; /* scaffolding */
-
- if (label) {
- lsmcontext_init(&scaff, label->label, label->len, 0);
- security_release_secctx(&scaff);
- }
+ kfree(label->label);
}
static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
{
diff --git a/include/linux/security.h b/include/linux/security.h
index 390cc0561bb3..ea98dff5ec03 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -394,8 +394,8 @@ int security_add_mnt_opt(const char *option, const char *val,
int len, void **mnt_opts);
int security_move_mount(const struct path *from_path, const struct path *to_path);
int security_dentry_init_security(struct dentry *dentry, int mode,
- const struct qstr *name, void **ctx,
- u32 *ctxlen);
+ const struct qstr *name,
+ struct lsmcontext *ctx);
int security_dentry_create_files_as(struct dentry *dentry, int mode,
struct qstr *name,
const struct cred *old,
@@ -786,8 +786,7 @@ static inline void security_inode_free(struct inode *inode)
static inline int security_dentry_init_security(struct dentry *dentry,
int mode,
const struct qstr *name,
- void **ctx,
- u32 *ctxlen)
+ struct lsmcontext *ctx)
{
return -EOPNOTSUPP;
}
diff --git a/security/security.c b/security/security.c
index e80b71c03062..29f070aa172c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1011,12 +1011,33 @@ void security_inode_free(struct inode *inode)
inode_free_by_rcu);
}
+/*
+ * security_dentry_init_security - initial context for a dentry
+ * @dentry: directory entry
+ * @mode: access mode
+ * @name: path name
+ * @context: resulting security context
+ *
+ * Use at most one security module to get the initial
+ * security context. Do not use the "display".
+ *
+ * Returns -EOPNOTSUPP if not supplied by any module or the module result.
+ */
int security_dentry_init_security(struct dentry *dentry, int mode,
- const struct qstr *name, void **ctx,
- u32 *ctxlen)
+ const struct qstr *name,
+ struct lsmcontext *cp)
{
- return call_int_hook(dentry_init_security, -EOPNOTSUPP, dentry, mode,
- name, ctx, ctxlen);
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security,
+ list) {
+ cp->slot = hp->lsmid->slot;
+ return hp->hook.dentry_init_security(dentry, mode, name,
+ (void **)&cp->context,
+ &cp->len);
+ }
+
+ return -EOPNOTSUPP;
}
EXPORT_SYMBOL(security_dentry_init_security);
--
2.20.1
^ permalink raw reply related
* [PATCH v13 18/25] LSM: security_secid_to_secctx in netlink netfilter
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Change netlink netfilter interfaces to use lsmcontext
pointers, and remove scaffolding.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: netdev@vger.kernel.org
---
net/netfilter/nfnetlink_queue.c | 32 +++++++++++++-------------------
1 file changed, 13 insertions(+), 19 deletions(-)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 2d6668fd026c..a1296453d8f2 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -301,12 +301,10 @@ static int nfqnl_put_sk_uidgid(struct sk_buff *skb, struct sock *sk)
return -1;
}
-static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
+static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsmcontext *context)
{
- u32 seclen = 0;
#if IS_ENABLED(CONFIG_NETWORK_SECMARK)
struct lsmblob blob;
- struct lsmcontext context = { };
if (!skb || !sk_fullsock(skb->sk))
return 0;
@@ -314,15 +312,16 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata)
read_lock_bh(&skb->sk->sk_callback_lock);
if (skb->secmark) {
+ /* Any LSM might be looking for the secmark */
lsmblob_init(&blob, skb->secmark);
- security_secid_to_secctx(&blob, &context);
- *secdata = context.context;
+ security_secid_to_secctx(&blob, context);
}
read_unlock_bh(&skb->sk->sk_callback_lock);
- seclen = context.len;
+ return context->len;
+#else
+ return 0;
#endif
- return seclen;
}
static u32 nfqnl_get_bridge_size(struct nf_queue_entry *entry)
@@ -398,8 +397,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
enum ip_conntrack_info uninitialized_var(ctinfo);
struct nfnl_ct_hook *nfnl_ct;
bool csum_verify;
- struct lsmcontext scaff; /* scaffolding */
- char *secdata = NULL;
+ struct lsmcontext context = { };
u32 seclen = 0;
size = nlmsg_total_size(sizeof(struct nfgenmsg))
@@ -466,7 +464,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
}
if ((queue->flags & NFQA_CFG_F_SECCTX) && entskb->sk) {
- seclen = nfqnl_get_sk_secctx(entskb, &secdata);
+ seclen = nfqnl_get_sk_secctx(entskb, &context);
if (seclen)
size += nla_total_size(seclen);
}
@@ -601,7 +599,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
nfqnl_put_sk_uidgid(skb, entskb->sk) < 0)
goto nla_put_failure;
- if (seclen && nla_put(skb, NFQA_SECCTX, seclen, secdata))
+ if (seclen && nla_put(skb, NFQA_SECCTX, context.len, context.context))
goto nla_put_failure;
if (ct && nfnl_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0)
@@ -629,10 +627,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
}
nlh->nlmsg_len = skb->len;
- if (seclen) {
- lsmcontext_init(&scaff, secdata, seclen, 0);
- security_release_secctx(&scaff);
- }
+ if (seclen)
+ security_release_secctx(&context);
return skb;
nla_put_failure:
@@ -640,10 +636,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
kfree_skb(skb);
net_err_ratelimited("nf_queue: error creating packet message\n");
nlmsg_failure:
- if (seclen) {
- lsmcontext_init(&scaff, secdata, seclen, 0);
- security_release_secctx(&scaff);
- }
+ if (seclen)
+ security_release_secctx(&context);
return NULL;
}
--
2.20.1
^ permalink raw reply related
* [PATCH v13 19/25] NET: Store LSM netlabel data in a lsmblob
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Netlabel uses LSM interfaces requiring an lsmblob and
the internal storage is used to pass information between
these interfaces, so change the internal data from a secid
to a lsmblob. Update the netlabel interfaces and their
callers to accommodate the change. This requires that the
modules using netlabel use the lsm_id.slot to access the
correct secid when using netlabel.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/net/netlabel.h | 8 ++--
net/ipv4/cipso_ipv4.c | 23 +++++++-----
net/netlabel/netlabel_kapi.c | 6 +--
net/netlabel/netlabel_unlabeled.c | 57 +++++++++++------------------
net/netlabel/netlabel_unlabeled.h | 2 +-
security/selinux/hooks.c | 2 +-
security/selinux/include/security.h | 1 +
security/selinux/netlabel.c | 2 +-
security/selinux/ss/services.c | 4 +-
security/smack/smack.h | 1 +
security/smack/smack_lsm.c | 5 ++-
security/smack/smackfs.c | 10 +++--
12 files changed, 59 insertions(+), 62 deletions(-)
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 43ae50337685..73fc25b4042b 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -166,7 +166,7 @@ struct netlbl_lsm_catmap {
* @attr.mls: MLS sensitivity label
* @attr.mls.cat: MLS category bitmap
* @attr.mls.lvl: MLS sensitivity level
- * @attr.secid: LSM specific secid token
+ * @attr.lsmblob: LSM specific data
*
* Description:
* This structure is used to pass security attributes between NetLabel and the
@@ -201,7 +201,7 @@ struct netlbl_lsm_secattr {
struct netlbl_lsm_catmap *cat;
u32 lvl;
} mls;
- u32 secid;
+ struct lsmblob lsmblob;
} attr;
};
@@ -415,7 +415,7 @@ int netlbl_cfg_unlbl_static_add(struct net *net,
const void *addr,
const void *mask,
u16 family,
- u32 secid,
+ struct lsmblob *lsmblob,
struct netlbl_audit *audit_info);
int netlbl_cfg_unlbl_static_del(struct net *net,
const char *dev_name,
@@ -523,7 +523,7 @@ static inline int netlbl_cfg_unlbl_static_add(struct net *net,
const void *addr,
const void *mask,
u16 family,
- u32 secid,
+ struct lsmblob *lsmblob,
struct netlbl_audit *audit_info)
{
return -ENOSYS;
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 376882215919..adb9dffc3952 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -106,15 +106,17 @@ int cipso_v4_rbm_strictvalid = 1;
/* Base length of the local tag (non-standard tag).
* Tag definition (may change between kernel versions)
*
- * 0 8 16 24 32
- * +----------+----------+----------+----------+
- * | 10000000 | 00000110 | 32-bit secid value |
- * +----------+----------+----------+----------+
- * | in (host byte order)|
- * +----------+----------+
- *
+ * 0 8 16 16 + sizeof(struct lsmblob)
+ * +----------+----------+---------------------+
+ * | 10000000 | 00000110 | LSM blob data |
+ * +----------+----------+---------------------+
+ *
+ * All secid and flag fields are in host byte order.
+ * The lsmblob structure size varies depending on which
+ * Linux security modules are built in the kernel.
+ * The data is opaque.
*/
-#define CIPSO_V4_TAG_LOC_BLEN 6
+#define CIPSO_V4_TAG_LOC_BLEN (2 + sizeof(struct lsmblob))
/*
* Helper Functions
@@ -1467,7 +1469,8 @@ static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def,
buffer[0] = CIPSO_V4_TAG_LOCAL;
buffer[1] = CIPSO_V4_TAG_LOC_BLEN;
- *(u32 *)&buffer[2] = secattr->attr.secid;
+ memcpy(&buffer[2], &secattr->attr.lsmblob,
+ sizeof(secattr->attr.lsmblob));
return CIPSO_V4_TAG_LOC_BLEN;
}
@@ -1487,7 +1490,7 @@ static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
const unsigned char *tag,
struct netlbl_lsm_secattr *secattr)
{
- secattr->attr.secid = *(u32 *)&tag[2];
+ memcpy(&secattr->attr.lsmblob, &tag[2], sizeof(secattr->attr.lsmblob));
secattr->flags |= NETLBL_SECATTR_SECID;
return 0;
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 409a3ae47ce2..f2ebd43a7992 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -196,7 +196,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
* @addr: IP address in network byte order (struct in[6]_addr)
* @mask: address mask in network byte order (struct in[6]_addr)
* @family: address family
- * @secid: LSM secid value for the entry
+ * @lsmblob: LSM data value for the entry
* @audit_info: NetLabel audit information
*
* Description:
@@ -210,7 +210,7 @@ int netlbl_cfg_unlbl_static_add(struct net *net,
const void *addr,
const void *mask,
u16 family,
- u32 secid,
+ struct lsmblob *lsmblob,
struct netlbl_audit *audit_info)
{
u32 addr_len;
@@ -230,7 +230,7 @@ int netlbl_cfg_unlbl_static_add(struct net *net,
return netlbl_unlhsh_add(net,
dev_name, addr, mask, addr_len,
- secid, audit_info);
+ lsmblob, audit_info);
}
/**
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index c03fe9a4f7b9..3b0f07b59436 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -66,7 +66,7 @@ struct netlbl_unlhsh_tbl {
#define netlbl_unlhsh_addr4_entry(iter) \
container_of(iter, struct netlbl_unlhsh_addr4, list)
struct netlbl_unlhsh_addr4 {
- u32 secid;
+ struct lsmblob lsmblob;
struct netlbl_af4list list;
struct rcu_head rcu;
@@ -74,7 +74,7 @@ struct netlbl_unlhsh_addr4 {
#define netlbl_unlhsh_addr6_entry(iter) \
container_of(iter, struct netlbl_unlhsh_addr6, list)
struct netlbl_unlhsh_addr6 {
- u32 secid;
+ struct lsmblob lsmblob;
struct netlbl_af6list list;
struct rcu_head rcu;
@@ -219,7 +219,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
* @iface: the associated interface entry
* @addr: IPv4 address in network byte order
* @mask: IPv4 address mask in network byte order
- * @secid: LSM secid value for entry
+ * @lsmblob: LSM data value for entry
*
* Description:
* Add a new address entry into the unlabeled connection hash table using the
@@ -230,7 +230,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
const struct in_addr *addr,
const struct in_addr *mask,
- u32 secid)
+ struct lsmblob *lsmblob)
{
int ret_val;
struct netlbl_unlhsh_addr4 *entry;
@@ -242,7 +242,7 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
entry->list.addr = addr->s_addr & mask->s_addr;
entry->list.mask = mask->s_addr;
entry->list.valid = 1;
- entry->secid = secid;
+ entry->lsmblob = *lsmblob;
spin_lock(&netlbl_unlhsh_lock);
ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
@@ -259,7 +259,7 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
* @iface: the associated interface entry
* @addr: IPv6 address in network byte order
* @mask: IPv6 address mask in network byte order
- * @secid: LSM secid value for entry
+ * @lsmblob: LSM data value for entry
*
* Description:
* Add a new address entry into the unlabeled connection hash table using the
@@ -270,7 +270,7 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
const struct in6_addr *addr,
const struct in6_addr *mask,
- u32 secid)
+ struct lsmblob *lsmblob)
{
int ret_val;
struct netlbl_unlhsh_addr6 *entry;
@@ -286,7 +286,7 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
entry->list.mask = *mask;
entry->list.valid = 1;
- entry->secid = secid;
+ entry->lsmblob = *lsmblob;
spin_lock(&netlbl_unlhsh_lock);
ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
@@ -365,7 +365,7 @@ int netlbl_unlhsh_add(struct net *net,
const void *addr,
const void *mask,
u32 addr_len,
- u32 secid,
+ struct lsmblob *lsmblob,
struct netlbl_audit *audit_info)
{
int ret_val;
@@ -374,7 +374,6 @@ int netlbl_unlhsh_add(struct net *net,
struct netlbl_unlhsh_iface *iface;
struct audit_buffer *audit_buf = NULL;
struct lsmcontext context;
- struct lsmblob blob;
if (addr_len != sizeof(struct in_addr) &&
addr_len != sizeof(struct in6_addr))
@@ -407,7 +406,7 @@ int netlbl_unlhsh_add(struct net *net,
const struct in_addr *addr4 = addr;
const struct in_addr *mask4 = mask;
- ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
+ ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, lsmblob);
if (audit_buf != NULL)
netlbl_af4list_audit_addr(audit_buf, 1,
dev_name,
@@ -420,7 +419,7 @@ int netlbl_unlhsh_add(struct net *net,
const struct in6_addr *addr6 = addr;
const struct in6_addr *mask6 = mask;
- ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
+ ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, lsmblob);
if (audit_buf != NULL)
netlbl_af6list_audit_addr(audit_buf, 1,
dev_name,
@@ -437,8 +436,7 @@ int netlbl_unlhsh_add(struct net *net,
unlhsh_add_return:
rcu_read_unlock();
if (audit_buf != NULL) {
- lsmblob_init(&blob, secid);
- if (security_secid_to_secctx(&blob, &context) == 0) {
+ if (security_secid_to_secctx(lsmblob, &context) == 0) {
audit_log_format(audit_buf, " sec_obj=%s",
context.context);
security_release_secctx(&context);
@@ -473,7 +471,6 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
struct audit_buffer *audit_buf;
struct net_device *dev;
struct lsmcontext context;
- struct lsmblob blob;
spin_lock(&netlbl_unlhsh_lock);
list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
@@ -493,10 +490,8 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
addr->s_addr, mask->s_addr);
if (dev != NULL)
dev_put(dev);
- if (entry != NULL)
- lsmblob_init(&blob, entry->secid);
if (entry != NULL &&
- security_secid_to_secctx(&blob, &context) == 0) {
+ security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
audit_log_format(audit_buf, " sec_obj=%s",
context.context);
security_release_secctx(&context);
@@ -537,7 +532,6 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
struct audit_buffer *audit_buf;
struct net_device *dev;
struct lsmcontext context;
- struct lsmblob blob;
spin_lock(&netlbl_unlhsh_lock);
list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
@@ -556,10 +550,8 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
addr, mask);
if (dev != NULL)
dev_put(dev);
- if (entry != NULL)
- lsmblob_init(&blob, entry->secid);
if (entry != NULL &&
- security_secid_to_secctx(&blob, &context) == 0) {
+ security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
audit_log_format(audit_buf, " sec_obj=%s",
context.context);
security_release_secctx(&context);
@@ -913,9 +905,8 @@ static int netlbl_unlabel_staticadd(struct sk_buff *skb,
if (ret_val != 0)
return ret_val;
- /* scaffolding with the [0] */
return netlbl_unlhsh_add(&init_net,
- dev_name, addr, mask, addr_len, blob.secid[0],
+ dev_name, addr, mask, addr_len, &blob,
&audit_info);
}
@@ -963,10 +954,8 @@ static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
if (ret_val != 0)
return ret_val;
- /* scaffolding with the [0] */
return netlbl_unlhsh_add(&init_net,
- NULL, addr, mask, addr_len, blob.secid[0],
- &audit_info);
+ NULL, addr, mask, addr_len, &blob, &audit_info);
}
/**
@@ -1078,8 +1067,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
struct net_device *dev;
struct lsmcontext context;
void *data;
- u32 secid;
- struct lsmblob blob;
+ struct lsmblob *lsmb;
data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
cb_arg->seq, &netlbl_unlabel_gnl_family,
@@ -1117,7 +1105,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
if (ret_val != 0)
goto list_cb_failure;
- secid = addr4->secid;
+ lsmb = (struct lsmblob *)&addr4->lsmblob;
} else {
ret_val = nla_put_in6_addr(cb_arg->skb,
NLBL_UNLABEL_A_IPV6ADDR,
@@ -1131,11 +1119,10 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
if (ret_val != 0)
goto list_cb_failure;
- secid = addr6->secid;
+ lsmb = (struct lsmblob *)&addr6->lsmblob;
}
- lsmblob_init(&blob, secid);
- ret_val = security_secid_to_secctx(&blob, &context);
+ ret_val = security_secid_to_secctx(lsmb, &context);
if (ret_val != 0)
goto list_cb_failure;
ret_val = nla_put(cb_arg->skb,
@@ -1487,7 +1474,7 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
&iface->addr4_list);
if (addr4 == NULL)
goto unlabel_getattr_nolabel;
- secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
+ secattr->attr.lsmblob = netlbl_unlhsh_addr4_entry(addr4)->lsmblob;
break;
}
#if IS_ENABLED(CONFIG_IPV6)
@@ -1500,7 +1487,7 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
&iface->addr6_list);
if (addr6 == NULL)
goto unlabel_getattr_nolabel;
- secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
+ secattr->attr.lsmblob = netlbl_unlhsh_addr6_entry(addr6)->lsmblob;
break;
}
#endif /* IPv6 */
diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h
index 058e3a285d56..168920780994 100644
--- a/net/netlabel/netlabel_unlabeled.h
+++ b/net/netlabel/netlabel_unlabeled.h
@@ -211,7 +211,7 @@ int netlbl_unlhsh_add(struct net *net,
const void *addr,
const void *mask,
u32 addr_len,
- u32 secid,
+ struct lsmblob *lsmblob,
struct netlbl_audit *audit_info);
int netlbl_unlhsh_remove(struct net *net,
const char *dev_name,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b8501ca3c8f3..cd4743331800 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6871,7 +6871,7 @@ static int selinux_perf_event_write(struct perf_event *event)
}
#endif
-static struct lsm_id selinux_lsmid __lsm_ro_after_init = {
+struct lsm_id selinux_lsmid __lsm_ro_after_init = {
.lsm = "selinux",
.slot = LSMBLOB_NEEDED
};
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ae840634e3c7..741ba0e6dd83 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -70,6 +70,7 @@
struct netlbl_lsm_secattr;
extern int selinux_enabled;
+extern struct lsm_id selinux_lsmid;
/* Policy capabilities */
enum {
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 6a94b31b5472..d8d7603ab14e 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -108,7 +108,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
return NULL;
if ((secattr->flags & NETLBL_SECATTR_SECID) &&
- (secattr->attr.secid == sid))
+ (secattr->attr.lsmblob.secid[selinux_lsmid.slot] == sid))
return secattr;
return NULL;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index a5813c7629c1..2b7680903b6b 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3599,7 +3599,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
if (secattr->flags & NETLBL_SECATTR_CACHE)
*sid = *(u32 *)secattr->cache->data;
else if (secattr->flags & NETLBL_SECATTR_SECID)
- *sid = secattr->attr.secid;
+ *sid = secattr->attr.lsmblob.secid[selinux_lsmid.slot];
else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
rc = -EIDRM;
ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
@@ -3672,7 +3672,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state,
if (secattr->domain == NULL)
goto out;
- secattr->attr.secid = sid;
+ secattr->attr.lsmblob.secid[selinux_lsmid.slot] = sid;
secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
mls_export_netlbl_lvl(policydb, ctx, secattr);
rc = mls_export_netlbl_cat(policydb, ctx, secattr);
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 2836540f9577..6e76b6b33063 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -316,6 +316,7 @@ void smk_destroy_label_list(struct list_head *list);
* Shared data.
*/
extern int smack_enabled;
+extern struct lsm_id smack_lsmid;
extern int smack_cipso_direct;
extern int smack_cipso_mapped;
extern struct smack_known *smack_net_ambient;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 9737ead06b39..9ce67e03ac49 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3775,7 +3775,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
/*
* Looks like a fallback, which gives us a secid.
*/
- return smack_from_secid(sap->attr.secid);
+ return smack_from_secid(
+ sap->attr.lsmblob.secid[smack_lsmid.slot]);
/*
* Without guidance regarding the smack value
* for the packet fall back on the network
@@ -4592,7 +4593,7 @@ struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
.lbs_sock = sizeof(struct socket_smack),
};
-static struct lsm_id smack_lsmid __lsm_ro_after_init = {
+struct lsm_id smack_lsmid __lsm_ro_after_init = {
.lsm = "smack",
.slot = LSMBLOB_NEEDED
};
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index e3e05c04dbd1..d10e9c96717e 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -1122,6 +1122,7 @@ static void smk_net4addr_insert(struct smk_net4addr *new)
static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct lsmblob lsmblob;
struct smk_net4addr *snp;
struct sockaddr_in newname;
char *smack;
@@ -1253,10 +1254,13 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
* this host so that incoming packets get labeled.
* but only if we didn't get the special CIPSO option
*/
- if (rc == 0 && skp != NULL)
+ if (rc == 0 && skp != NULL) {
+ lsmblob_init(&lsmblob, 0);
+ lsmblob.secid[smack_lsmid.slot] = snp->smk_label->smk_secid;
rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
- &snp->smk_host, &snp->smk_mask, PF_INET,
- snp->smk_label->smk_secid, &audit_info);
+ &snp->smk_host, &snp->smk_mask, PF_INET, &lsmblob,
+ &audit_info);
+ }
if (rc == 0)
rc = count;
--
2.20.1
^ permalink raw reply related
* [PATCH v13 20/25] LSM: Verify LSM display sanity in binder
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Verify that the tasks on the ends of a binder transaction
use the same "display" security module. This prevents confusion
of security "contexts".
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
security/security.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/security/security.c b/security/security.c
index affd53f04805..1dc3d2f71a63 100644
--- a/security/security.c
+++ b/security/security.c
@@ -738,9 +738,38 @@ int security_binder_set_context_mgr(struct task_struct *mgr)
return call_int_hook(binder_set_context_mgr, 0, mgr);
}
+/**
+ * security_binder_transaction - Binder driver transaction check
+ * @from: source of the transaction
+ * @to: destination of the transaction
+ *
+ * Verify that the tasks have the same LSM "display", then
+ * call the security module hooks.
+ *
+ * Returns -EINVAL if the displays don't match, or the
+ * result of the security module checks.
+ */
int security_binder_transaction(struct task_struct *from,
struct task_struct *to)
{
+ int from_display = lsm_task_display(from);
+ int to_display = lsm_task_display(to);
+
+ /*
+ * If the display is LSMBLOB_INVALID the first module that has
+ * an entry is used. This will be in the 0 slot.
+ *
+ * This is currently only required if the server has requested
+ * peer contexts, but it would be unwieldly to have too much of
+ * the binder driver detail here.
+ */
+ if (from_display == LSMBLOB_INVALID)
+ from_display = 0;
+ if (to_display == LSMBLOB_INVALID)
+ to_display = 0;
+ if (from_display != to_display)
+ return -EINVAL;
+
return call_int_hook(binder_transaction, 0, from, to);
}
--
2.20.1
^ permalink raw reply related
* [PATCH v13 21/25] Audit: Add subj_LSM fields when necessary
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Add record entries to identify subject data for all of the
security modules when there is more than one.
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: netdev@vger.kernel.org
cc: linux-audit@redhat.com
---
drivers/android/binder.c | 2 +-
include/linux/audit.h | 1 +
include/linux/security.h | 9 ++++-
include/net/scm.h | 3 +-
kernel/audit.c | 40 ++++++++++++++++++-
kernel/audit_fsnotify.c | 1 +
kernel/auditfilter.c | 1 +
kernel/auditsc.c | 10 +++--
net/ipv4/ip_sockglue.c | 2 +-
net/netfilter/nf_conntrack_netlink.c | 4 +-
net/netfilter/nf_conntrack_standalone.c | 2 +-
net/netfilter/nfnetlink_queue.c | 2 +-
net/netlabel/netlabel_unlabeled.c | 11 ++++--
net/netlabel/netlabel_user.c | 2 +-
net/xfrm/xfrm_policy.c | 2 +
net/xfrm/xfrm_state.c | 2 +
security/integrity/ima/ima_api.c | 1 +
security/integrity/integrity_audit.c | 1 +
security/security.c | 51 +++++++++++++++++++++++--
19 files changed, 124 insertions(+), 23 deletions(-)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 463372198099..57e14b80588f 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3107,7 +3107,7 @@ static void binder_transaction(struct binder_proc *proc,
size_t added_size;
security_task_getsecid(proc->tsk, &blob);
- ret = security_secid_to_secctx(&blob, &lsmctx);
+ ret = security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_DISPLAY);
if (ret) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index f9ceae57ca8d..2ce0e8da3922 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -161,6 +161,7 @@ extern void audit_log_path_denied(int type,
extern void audit_log_lost(const char *message);
extern int audit_log_task_context(struct audit_buffer *ab);
+extern void audit_log_task_lsms(struct audit_buffer *ab);
extern void audit_log_task_info(struct audit_buffer *ab);
extern int audit_update_lsm_rules(void);
diff --git a/include/linux/security.h b/include/linux/security.h
index 49d2a778020e..d7af2bbbc878 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -176,6 +176,8 @@ struct lsmblob {
#define LSMBLOB_INVALID -1 /* Not a valid LSM slot number */
#define LSMBLOB_NEEDED -2 /* Slot requested on initialization */
#define LSMBLOB_NOT_NEEDED -3 /* Slot not requested */
+#define LSMBLOB_DISPLAY -4 /* Use the "display" slot */
+#define LSMBLOB_FIRST -5 /* Use the default "display" slot */
/**
* lsmblob_init - initialize an lsmblob structure.
@@ -217,6 +219,8 @@ static inline bool lsmblob_equal(struct lsmblob *bloba, struct lsmblob *blobb)
return !memcmp(bloba, blobb, sizeof(*bloba));
}
+const char *security_lsm_slot_name(int slot);
+
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
int cap, unsigned int opts);
@@ -526,7 +530,8 @@ 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 lsmblob *blob, struct lsmcontext *cp);
+int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
+ int display);
int security_secctx_to_secid(const char *secdata, u32 seclen,
struct lsmblob *blob);
void security_release_secctx(struct lsmcontext *cp);
@@ -1330,7 +1335,7 @@ static inline int security_ismaclabel(const char *name)
}
static inline int security_secid_to_secctx(struct lsmblob *blob,
- struct lsmcontext *cp)
+ struct lsmcontext *cp, int display)
{
return -EOPNOTSUPP;
}
diff --git a/include/net/scm.h b/include/net/scm.h
index 4a6ad8caf423..8b5a4737e1b8 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -96,7 +96,8 @@ 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->lsmblob, &context);
+ err = security_secid_to_secctx(&scm->lsmblob, &context,
+ LSMBLOB_DISPLAY);
if (!err) {
put_cmsg(msg, SOL_SOCKET, SCM_SECURITY,
diff --git a/kernel/audit.c b/kernel/audit.c
index 224c7b4a1bc0..d40f64a47c4b 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -392,6 +392,7 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old,
if (rc)
allow_changes = 0; /* Something weird, deny request */
audit_log_format(ab, " res=%d", allow_changes);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
return rc;
}
@@ -1097,6 +1098,7 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature
audit_log_format(ab, " feature=%s old=%u new=%u old_lock=%u new_lock=%u res=%d",
audit_feature_names[which], !!old_feature, !!new_feature,
!!old_lock, !!new_lock, res);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
@@ -1347,6 +1349,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
size--;
audit_log_n_untrustedstring(ab, data, size);
}
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
break;
@@ -1361,6 +1364,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
msg_type == AUDIT_ADD_RULE ?
"add_rule" : "remove_rule",
audit_enabled);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
return -EPERM;
}
@@ -1374,6 +1378,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
audit_log_common_recv_msg(audit_context(), &ab,
AUDIT_CONFIG_CHANGE);
audit_log_format(ab, " op=trim res=1");
+ audit_log_task_lsms(ab);
audit_log_end(ab);
break;
case AUDIT_MAKE_EQUIV: {
@@ -1409,6 +1414,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
audit_log_format(ab, " new=");
audit_log_untrustedstring(ab, new);
audit_log_format(ab, " res=%d", !err);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
kfree(old);
kfree(new);
@@ -1418,7 +1424,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
len = 0;
if (lsmblob_is_set(&audit_sig_lsm)) {
err = security_secid_to_secctx(&audit_sig_lsm,
- &context);
+ &context, LSMBLOB_FIRST);
if (err)
return err;
}
@@ -1477,6 +1483,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
" old-log_passwd=%d new-log_passwd=%d res=%d",
old.enabled, s.enabled, old.log_passwd,
s.log_passwd, !err);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
break;
}
@@ -2055,6 +2062,33 @@ void audit_log_key(struct audit_buffer *ab, char *key)
audit_log_format(ab, "(null)");
}
+void audit_log_task_lsms(struct audit_buffer *ab)
+{
+ int i;
+ const char *lsm;
+ struct lsmblob blob;
+ struct lsmcontext context;
+
+ /*
+ * Don't do anything unless there is more than one LSM
+ * with a security context to report.
+ */
+ if (security_lsm_slot_name(1) == NULL)
+ return;
+
+ security_task_getsecid(current, &blob);
+
+ for (i = 0; i < LSMBLOB_ENTRIES; i++) {
+ lsm = security_lsm_slot_name(i);
+ if (lsm == NULL)
+ break;
+ if (security_secid_to_secctx(&blob, &context, i))
+ continue;
+ audit_log_format(ab, " subj_%s=%s", lsm, context.context);
+ security_release_secctx(&context);
+ }
+}
+
int audit_log_task_context(struct audit_buffer *ab)
{
int error;
@@ -2065,7 +2099,7 @@ int audit_log_task_context(struct audit_buffer *ab)
if (!lsmblob_is_set(&blob))
return 0;
- error = security_secid_to_secctx(&blob, &context);
+ error = security_secid_to_secctx(&blob, &context, LSMBLOB_FIRST);
if (error) {
if (error != -EINVAL)
goto error_path;
@@ -2173,6 +2207,7 @@ void audit_log_path_denied(int type, const char *operation)
audit_log_format(ab, "op=%s", operation);
audit_log_task_info(ab);
audit_log_format(ab, " res=0");
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
@@ -2223,6 +2258,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
oldsessionid, sessionid, !rc);
audit_put_tty(tty);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
diff --git a/kernel/audit_fsnotify.c b/kernel/audit_fsnotify.c
index f0d243318452..7f8c4b1a2884 100644
--- a/kernel/audit_fsnotify.c
+++ b/kernel/audit_fsnotify.c
@@ -126,6 +126,7 @@ static void audit_mark_log_rule_change(struct audit_fsnotify_mark *audit_mark, c
audit_log_untrustedstring(ab, audit_mark->path);
audit_log_key(ab, rule->filterkey);
audit_log_format(ab, " list=%d res=1", rule->listnr);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 19cfbe716f9d..bf28bb599b6d 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1103,6 +1103,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re
audit_log_format(ab, " op=%s", action);
audit_log_key(ab, rule->filterkey);
audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 7d66bb7497ef..7c381b1e9993 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -973,7 +973,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 (lsmblob_is_set(blob)) {
- if (security_secid_to_secctx(blob, &lsmctx)) {
+ if (security_secid_to_secctx(blob, &lsmctx, LSMBLOB_FIRST)) {
audit_log_format(ab, " obj=(none)");
rc = 1;
} else {
@@ -1218,7 +1218,8 @@ static void show_special(struct audit_context *context, int *call_panic)
struct lsmblob blob;
lsmblob_init(&blob, osid);
- if (security_secid_to_secctx(&blob, &lsmcxt)) {
+ if (security_secid_to_secctx(&blob, &lsmcxt,
+ LSMBLOB_FIRST)) {
audit_log_format(ab, " osid=%u", osid);
*call_panic = 1;
} else {
@@ -1370,7 +1371,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
struct lsmcontext lsmctx;
lsmblob_init(&blob, n->osid);
- if (security_secid_to_secctx(&blob, &lsmctx)) {
+ if (security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_FIRST)) {
audit_log_format(ab, " osid=%u", n->osid);
if (call_panic)
*call_panic = 2;
@@ -1479,6 +1480,7 @@ static void audit_log_exit(void)
audit_log_task_info(ab);
audit_log_key(ab, context->filterkey);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
for (aux = context->aux; aux; aux = aux->next) {
@@ -2602,6 +2604,7 @@ void audit_core_dumps(long signr)
return;
audit_log_task(ab);
audit_log_format(ab, " sig=%ld res=1", signr);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
@@ -2628,6 +2631,7 @@ void audit_seccomp(unsigned long syscall, long signr, int code)
audit_log_format(ab, " sig=%ld arch=%x syscall=%ld compat=%d ip=0x%lx code=0x%x",
signr, syscall_get_arch(current), syscall,
in_compat_syscall(), KSTK_EIP(current), code);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 27af7a6b8780..10b418029cdd 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(&lb, &context);
+ err = security_secid_to_secctx(&lb, &context, LSMBLOB_DISPLAY);
if (err)
return;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 255bcb886a2f..b2f522b39a1a 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -334,7 +334,7 @@ static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
struct lsmcontext context;
lsmblob_init(&blob, ct->secmark);
- ret = security_secid_to_secctx(&blob, &context);
+ ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
if (ret)
return 0;
@@ -649,7 +649,7 @@ static inline int ctnetlink_secctx_size(const struct nf_conn *ct)
struct lsmcontext context;
lsmblob_init(&blob, ct->secmark);
- ret = security_secid_to_secctx(&blob, &context);
+ ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
if (ret)
return 0;
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 8969754d7fe9..0ff2b8300c28 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -177,7 +177,7 @@ static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
struct lsmcontext context;
lsmblob_init(&blob, ct->secmark);
- ret = security_secid_to_secctx(&blob, &context);
+ ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
if (ret)
return;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a1296453d8f2..b6f71be884e8 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -314,7 +314,7 @@ static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsmcontext *context)
if (skb->secmark) {
/* Any LSM might be looking for the secmark */
lsmblob_init(&blob, skb->secmark);
- security_secid_to_secctx(&blob, context);
+ security_secid_to_secctx(&blob, context, LSMBLOB_DISPLAY);
}
read_unlock_bh(&skb->sk->sk_callback_lock);
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 3b0f07b59436..60a7665de0e3 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -436,7 +436,8 @@ int netlbl_unlhsh_add(struct net *net,
unlhsh_add_return:
rcu_read_unlock();
if (audit_buf != NULL) {
- if (security_secid_to_secctx(lsmblob, &context) == 0) {
+ if (security_secid_to_secctx(lsmblob, &context,
+ LSMBLOB_FIRST) == 0) {
audit_log_format(audit_buf, " sec_obj=%s",
context.context);
security_release_secctx(&context);
@@ -491,7 +492,8 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
if (dev != NULL)
dev_put(dev);
if (entry != NULL &&
- security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
+ security_secid_to_secctx(&entry->lsmblob, &context,
+ LSMBLOB_FIRST) == 0) {
audit_log_format(audit_buf, " sec_obj=%s",
context.context);
security_release_secctx(&context);
@@ -551,7 +553,8 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
if (dev != NULL)
dev_put(dev);
if (entry != NULL &&
- security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
+ security_secid_to_secctx(&entry->lsmblob, &context,
+ LSMBLOB_FIRST) == 0) {
audit_log_format(audit_buf, " sec_obj=%s",
context.context);
security_release_secctx(&context);
@@ -1122,7 +1125,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
lsmb = (struct lsmblob *)&addr6->lsmblob;
}
- ret_val = security_secid_to_secctx(lsmb, &context);
+ ret_val = security_secid_to_secctx(lsmb, &context, LSMBLOB_FIRST);
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 951ba0639d20..1941877fd16f 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -100,7 +100,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
lsmblob_init(&blob, audit_info->secid);
if (audit_info->secid != 0 &&
- security_secid_to_secctx(&blob, &context) == 0) {
+ security_secid_to_secctx(&blob, &context, LSMBLOB_FIRST) == 0) {
audit_log_format(audit_buf, " subj=%s", context.context);
security_release_secctx(&context);
}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index f2d1e573ea55..bd2b36a83e66 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -4206,6 +4206,7 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid)
xfrm_audit_helper_usrinfo(task_valid, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
xfrm_audit_common_policyinfo(xp, audit_buf);
+ audit_log_task_lsms(audit_buf);
audit_log_end(audit_buf);
}
EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
@@ -4221,6 +4222,7 @@ void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
xfrm_audit_helper_usrinfo(task_valid, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
xfrm_audit_common_policyinfo(xp, audit_buf);
+ audit_log_task_lsms(audit_buf);
audit_log_end(audit_buf);
}
EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index f3423562d933..bfb8402cb28d 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2642,6 +2642,7 @@ void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid)
xfrm_audit_helper_usrinfo(task_valid, audit_buf);
xfrm_audit_helper_sainfo(x, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
+ audit_log_task_lsms(audit_buf);
audit_log_end(audit_buf);
}
EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
@@ -2656,6 +2657,7 @@ void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid)
xfrm_audit_helper_usrinfo(task_valid, audit_buf);
xfrm_audit_helper_sainfo(x, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
+ audit_log_task_lsms(audit_buf);
audit_log_end(audit_buf);
}
EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 1ab769fa7df6..252dc00700e8 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -363,6 +363,7 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
audit_log_format(ab, " hash=\"%s:%s\"", algo_name, hash);
audit_log_task_info(ab);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
iint->flags |= IMA_AUDITED;
diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c
index 5109173839cc..bca89ae72e3d 100644
--- a/security/integrity/integrity_audit.c
+++ b/security/integrity/integrity_audit.c
@@ -54,5 +54,6 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
audit_log_format(ab, " ino=%lu", inode->i_ino);
}
audit_log_format(ab, " res=%d", !result);
+ audit_log_task_lsms(ab);
audit_log_end(ab);
}
diff --git a/security/security.c b/security/security.c
index 1dc3d2f71a63..6d05222aac9c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -449,7 +449,31 @@ static int lsm_append(const char *new, char **result)
* Pointers to the LSM id structures for local use.
*/
static int lsm_slot __lsm_ro_after_init;
-static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES];
+static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES] __lsm_ro_after_init;
+
+/**
+ * security_lsm_slot_name - Get the name of the security module in a slot
+ * @slot: index into the "display" slot list.
+ *
+ * Provide the name of the security module associated with
+ * a display slot.
+ *
+ * If @slot is LSMBLOB_INVALID return the value
+ * for slot 0 if it has been set, otherwise NULL.
+ *
+ * Returns a pointer to the name string or NULL.
+ */
+const char *security_lsm_slot_name(int slot)
+{
+ if (slot == LSMBLOB_INVALID)
+ slot = 0;
+ else if (slot >= LSMBLOB_ENTRIES || slot < 0)
+ return NULL;
+
+ if (lsm_slotlist[slot] == NULL)
+ return NULL;
+ return lsm_slotlist[slot]->lsm;
+}
/**
* security_add_hooks - Add a modules hooks to the hook lists.
@@ -2159,13 +2183,32 @@ int security_ismaclabel(const char *name)
}
EXPORT_SYMBOL(security_ismaclabel);
-int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
+int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
+ int display)
{
struct security_hook_list *hp;
- int display = lsm_task_display(current);
memset(cp, 0, sizeof(*cp));
+ /*
+ * display either is the slot number use for formatting
+ * or an instruction on which relative slot to use.
+ */
+ if (display == LSMBLOB_DISPLAY)
+ display = lsm_task_display(current);
+ else if (display == LSMBLOB_FIRST)
+ display = LSMBLOB_INVALID;
+ else if (display < 0) {
+ WARN_ONCE(true,
+ "LSM: security_secid_to_secctx unknown display\n");
+ display = LSMBLOB_INVALID;
+ } else if (display >= lsm_slot) {
+ WARN_ONCE(true,
+ "LSM: security_secid_to_secctx invalid display\n");
+ display = LSMBLOB_INVALID;
+ }
+
+
hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
continue;
@@ -2176,7 +2219,7 @@ int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
&cp->context, &cp->len);
}
}
- return 0;
+ return -EOPNOTSUPP;
}
EXPORT_SYMBOL(security_secid_to_secctx);
--
2.20.1
^ permalink raw reply related
* [PATCH v13 09/25] LSM: Use lsmblob in security_task_getsecid
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Change the security_task_getsecid() interface to fill in
a lsmblob structure instead of a u32 secid in support of
LSM stacking. Audit interfaces will need to collect all
possible secids for possible reporting.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: linux-integrity@vger.kernel.org
---
drivers/android/binder.c | 4 +--
include/linux/security.h | 7 +++--
kernel/audit.c | 11 +++----
kernel/auditfilter.c | 4 +--
kernel/auditsc.c | 18 ++++++++----
net/netlabel/netlabel_unlabeled.c | 5 +++-
net/netlabel/netlabel_user.h | 6 +++-
security/integrity/ima/ima_appraise.c | 9 +++---
security/integrity/ima/ima_main.c | 42 +++++++++++++++------------
security/security.c | 12 ++++++--
10 files changed, 71 insertions(+), 47 deletions(-)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index f9b67f585e06..22fef6e130df 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3104,12 +3104,10 @@ static void binder_transaction(struct binder_proc *proc,
t->priority = task_nice(current);
if (target_node && target_node->txn_security_ctx) {
- u32 secid;
struct lsmblob blob;
size_t added_size;
- security_task_getsecid(proc->tsk, &secid);
- lsmblob_init(&blob, secid);
+ security_task_getsecid(proc->tsk, &blob);
ret = security_secid_to_secctx(&blob, &secctx, &secctx_sz);
if (ret) {
return_error = BR_FAILED_REPLY;
diff --git a/include/linux/security.h b/include/linux/security.h
index 61a80afbbdba..b6d5475f8196 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -449,7 +449,7 @@ int security_task_fix_setuid(struct cred *new, const struct cred *old,
int security_task_setpgid(struct task_struct *p, pid_t pgid);
int security_task_getpgid(struct task_struct *p);
int security_task_getsid(struct task_struct *p);
-void security_task_getsecid(struct task_struct *p, u32 *secid);
+void security_task_getsecid(struct task_struct *p, struct lsmblob *blob);
int security_task_setnice(struct task_struct *p, int nice);
int security_task_setioprio(struct task_struct *p, int ioprio);
int security_task_getioprio(struct task_struct *p);
@@ -1101,9 +1101,10 @@ static inline int security_task_getsid(struct task_struct *p)
return 0;
}
-static inline void security_task_getsecid(struct task_struct *p, u32 *secid)
+static inline void security_task_getsecid(struct task_struct *p,
+ struct lsmblob *blob)
{
- *secid = 0;
+ lsmblob_init(blob, 0);
}
static inline int security_task_setnice(struct task_struct *p, int nice)
diff --git a/kernel/audit.c b/kernel/audit.c
index e3e515158295..6ee53e43c986 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -2062,14 +2062,12 @@ int audit_log_task_context(struct audit_buffer *ab)
char *ctx = NULL;
unsigned len;
int error;
- u32 sid;
struct lsmblob blob;
- security_task_getsecid(current, &sid);
- if (!sid)
+ security_task_getsecid(current, &blob);
+ if (!lsmblob_is_set(&blob))
return 0;
- lsmblob_init(&blob, sid);
error = security_secid_to_secctx(&blob, &ctx, &len);
if (error) {
if (error != -EINVAL)
@@ -2277,6 +2275,7 @@ int audit_set_loginuid(kuid_t loginuid)
int audit_signal_info(int sig, struct task_struct *t)
{
kuid_t uid = current_uid(), auid;
+ struct lsmblob blob;
if (auditd_test_task(t) &&
(sig == SIGTERM || sig == SIGHUP ||
@@ -2287,7 +2286,9 @@ int audit_signal_info(int sig, struct task_struct *t)
audit_sig_uid = auid;
else
audit_sig_uid = uid;
- security_task_getsecid(current, &audit_sig_sid);
+ security_task_getsecid(current, &blob);
+ /* scaffolding until audit_sig_sid is converted */
+ audit_sig_sid = blob.secid[0];
}
return audit_signal_info_syscall(t);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 356db1dd276c..19cfbe716f9d 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1324,7 +1324,6 @@ int audit_filter(int msgtype, unsigned int listtype)
for (i = 0; i < e->rule.field_count; i++) {
struct audit_field *f = &e->rule.fields[i];
pid_t pid;
- u32 sid;
struct lsmblob blob;
switch (f->type) {
@@ -1355,8 +1354,7 @@ int audit_filter(int msgtype, unsigned int listtype)
case AUDIT_SUBJ_SEN:
case AUDIT_SUBJ_CLR:
if (f->lsm_rule) {
- security_task_getsecid(current, &sid);
- lsmblob_init(&blob, sid);
+ security_task_getsecid(current, &blob);
result = security_audit_rule_match(
&blob, f->type,
f->op, f->lsm_rule);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ce8bf2d8f8d2..cccb681ad081 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -444,7 +444,6 @@ static int audit_filter_rules(struct task_struct *tsk,
{
const struct cred *cred;
int i, need_sid = 1;
- u32 sid;
struct lsmblob blob;
unsigned int sessionid;
@@ -641,10 +640,9 @@ static int audit_filter_rules(struct task_struct *tsk,
logged upon error */
if (f->lsm_rule) {
if (need_sid) {
- security_task_getsecid(tsk, &sid);
+ security_task_getsecid(tsk, &blob);
need_sid = 0;
}
- lsmblob_init(&blob, sid);
result = security_audit_rule_match(&blob,
f->type,
f->op,
@@ -2382,12 +2380,15 @@ int __audit_sockaddr(int len, void *a)
void __audit_ptrace(struct task_struct *t)
{
struct audit_context *context = audit_context();
+ struct lsmblob blob;
context->target_pid = task_tgid_nr(t);
context->target_auid = audit_get_loginuid(t);
context->target_uid = task_uid(t);
context->target_sessionid = audit_get_sessionid(t);
- security_task_getsecid(t, &context->target_sid);
+ security_task_getsecid(t, &blob);
+ /* scaffolding - until target_sid is converted */
+ context->target_sid = blob.secid[0];
memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
}
@@ -2403,6 +2404,7 @@ int audit_signal_info_syscall(struct task_struct *t)
struct audit_aux_data_pids *axp;
struct audit_context *ctx = audit_context();
kuid_t t_uid = task_uid(t);
+ struct lsmblob blob;
if (!audit_signals || audit_dummy_context())
return 0;
@@ -2414,7 +2416,9 @@ int audit_signal_info_syscall(struct task_struct *t)
ctx->target_auid = audit_get_loginuid(t);
ctx->target_uid = t_uid;
ctx->target_sessionid = audit_get_sessionid(t);
- security_task_getsecid(t, &ctx->target_sid);
+ security_task_getsecid(t, &blob);
+ /* scaffolding until target_sid is converted */
+ ctx->target_sid = blob.secid[0];
memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
return 0;
}
@@ -2435,7 +2439,9 @@ int audit_signal_info_syscall(struct task_struct *t)
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
axp->target_uid[axp->pid_count] = t_uid;
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
- security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
+ security_task_getsecid(t, &blob);
+ /* scaffolding until target_sid is converted */
+ axp->target_sid[axp->pid_count] = blob.secid[0];
memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
axp->pid_count++;
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 0cda17cb44a0..e279b81d9545 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1539,11 +1539,14 @@ int __init netlbl_unlabel_defconf(void)
int ret_val;
struct netlbl_dom_map *entry;
struct netlbl_audit audit_info;
+ struct lsmblob blob;
/* Only the kernel is allowed to call this function and the only time
* it is called is at bootup before the audit subsystem is reporting
* messages so don't worry to much about these values. */
- security_task_getsecid(current, &audit_info.secid);
+ security_task_getsecid(current, &blob);
+ /* scaffolding until audit_info.secid is converted */
+ audit_info.secid = blob.secid[0];
audit_info.loginuid = GLOBAL_ROOT_UID;
audit_info.sessionid = 0;
diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
index 3c67afce64f1..438b5db6c714 100644
--- a/net/netlabel/netlabel_user.h
+++ b/net/netlabel/netlabel_user.h
@@ -34,7 +34,11 @@
static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
struct netlbl_audit *audit_info)
{
- security_task_getsecid(current, &audit_info->secid);
+ struct lsmblob blob;
+
+ security_task_getsecid(current, &blob);
+ /* scaffolding until secid is converted */
+ audit_info->secid = blob.secid[0];
audit_info->loginuid = audit_get_loginuid(current);
audit_info->sessionid = audit_get_sessionid(current);
}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 300c8d2943c5..37f540af45bb 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -48,14 +48,15 @@ bool is_ima_appraise_enabled(void)
*/
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
{
- u32 secid;
+ struct lsmblob blob;
if (!ima_appraise)
return 0;
- security_task_getsecid(current, &secid);
- return ima_match_policy(inode, current_cred(), secid, func, mask,
- IMA_APPRAISE | IMA_HASH, NULL, NULL);
+ security_task_getsecid(current, &blob);
+ /* scaffolding the .secid[0] */
+ return ima_match_policy(inode, current_cred(), blob.secid[0], func,
+ mask, IMA_APPRAISE | IMA_HASH, NULL, NULL);
}
static int ima_fix_xattr(struct dentry *dentry,
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index d7e987baf127..7c4bfc051ebc 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -384,12 +384,13 @@ static int process_measurement(struct file *file, const struct cred *cred,
*/
int ima_file_mmap(struct file *file, unsigned long prot)
{
- u32 secid;
+ struct lsmblob blob;
if (file && (prot & PROT_EXEC)) {
- security_task_getsecid(current, &secid);
- return process_measurement(file, current_cred(), secid, NULL,
- 0, MAY_EXEC, MMAP_CHECK);
+ security_task_getsecid(current, &blob);
+ /* scaffolding - until process_measurement changes */
+ return process_measurement(file, current_cred(), blob.secid[0],
+ NULL, 0, MAY_EXEC, MMAP_CHECK);
}
return 0;
@@ -412,10 +413,12 @@ int ima_bprm_check(struct linux_binprm *bprm)
{
int ret;
u32 secid;
+ struct lsmblob blob;
- security_task_getsecid(current, &secid);
- ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0,
- MAY_EXEC, BPRM_CHECK);
+ security_task_getsecid(current, &blob);
+ /* scaffolding until process_measurement changes */
+ ret = process_measurement(bprm->file, current_cred(), blob.secid[0],
+ NULL, 0, MAY_EXEC, BPRM_CHECK);
if (ret)
return ret;
@@ -436,10 +439,11 @@ int ima_bprm_check(struct linux_binprm *bprm)
*/
int ima_file_check(struct file *file, int mask)
{
- u32 secid;
+ struct lsmblob blob;
- security_task_getsecid(current, &secid);
- return process_measurement(file, current_cred(), secid, NULL, 0,
+ security_task_getsecid(current, &blob);
+ /* scaffolding until process_measurement changes */
+ return process_measurement(file, current_cred(), blob.secid[0], NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
MAY_APPEND), FILE_CHECK);
}
@@ -548,7 +552,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id read_id)
{
enum ima_hooks func;
- u32 secid;
+ struct lsmblob blob;
if (!file && read_id == READING_FIRMWARE) {
if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
@@ -570,9 +574,10 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
}
func = read_idmap[read_id] ?: FILE_CHECK;
- security_task_getsecid(current, &secid);
- return process_measurement(file, current_cred(), secid, buf, size,
- MAY_READ, func);
+ security_task_getsecid(current, &blob);
+ /* scaffolding until process_measurement changes */
+ return process_measurement(file, current_cred(), blob.secid[0], buf,
+ size, MAY_READ, func);
}
/**
@@ -653,7 +658,7 @@ void process_buffer_measurement(const void *buf, int size,
} hash = {};
int violation = 0;
int action = 0;
- u32 secid;
+ struct lsmblob blob;
/*
* Both LSM hooks and auxilary based buffer measurements are
@@ -663,9 +668,10 @@ void process_buffer_measurement(const void *buf, int size,
* buffer measurements.
*/
if (func) {
- security_task_getsecid(current, &secid);
- action = ima_get_action(NULL, current_cred(), secid, 0, func,
- &pcr, &template);
+ security_task_getsecid(current, &blob);
+ /* scaffolding */
+ action = ima_get_action(NULL, current_cred(), blob.secid[0],
+ 0, func, &pcr, &template);
if (!(action & IMA_MEASURE))
return;
}
diff --git a/security/security.c b/security/security.c
index 793c4ee0cf4e..7a170c02f8df 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1700,10 +1700,16 @@ int security_task_getsid(struct task_struct *p)
return call_int_hook(task_getsid, 0, p);
}
-void security_task_getsecid(struct task_struct *p, u32 *secid)
+void security_task_getsecid(struct task_struct *p, struct lsmblob *blob)
{
- *secid = 0;
- call_void_hook(task_getsecid, p, secid);
+ struct security_hook_list *hp;
+
+ lsmblob_init(blob, 0);
+ hlist_for_each_entry(hp, &security_hook_heads.task_getsecid, list) {
+ if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+ continue;
+ hp->hook.task_getsecid(p, &blob->secid[hp->lsmid->slot]);
+ }
}
EXPORT_SYMBOL(security_task_getsecid);
--
2.20.1
^ permalink raw reply related
* [PATCH v13 22/25] Audit: Include object data for all security modules
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
When there is more than one context displaying security
module extend what goes into the audit record by supplimenting
the "obj=" with an "obj_<lsm>=" for each such security
module.
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc:linux-audit@redhat.com
---
kernel/audit.h | 4 +-
kernel/auditsc.c | 110 ++++++++++++++++++++++++-----------------------
2 files changed, 58 insertions(+), 56 deletions(-)
diff --git a/kernel/audit.h b/kernel/audit.h
index f65f516913c6..9a26ba213f6a 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -78,7 +78,7 @@ struct audit_names {
kuid_t uid;
kgid_t gid;
dev_t rdev;
- u32 osid;
+ struct lsmblob oblob;
struct audit_cap_data fcap;
unsigned int fcap_ver;
unsigned char type; /* record type */
@@ -152,7 +152,7 @@ struct audit_context {
kuid_t uid;
kgid_t gid;
umode_t mode;
- u32 osid;
+ struct lsmblob oblob;
int has_perm;
uid_t perm_uid;
gid_t perm_gid;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 7c381b1e9993..28fea2e73040 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -659,17 +659,15 @@ static int audit_filter_rules(struct task_struct *tsk,
if (f->lsm_rule) {
/* Find files that match */
if (name) {
- lsmblob_init(&blob, name->osid);
result = security_audit_rule_match(
- &blob,
+ &name->oblob,
f->type,
f->op,
f->lsm_rule);
} else if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
- lsmblob_init(&blob, n->osid);
if (security_audit_rule_match(
- &blob,
+ &n->oblob,
f->type,
f->op,
f->lsm_rule)) {
@@ -681,8 +679,7 @@ static int audit_filter_rules(struct task_struct *tsk,
/* Find ipc objects that match */
if (!ctx || ctx->type != AUDIT_IPC)
break;
- lsmblob_init(&blob, ctx->ipc.osid);
- if (security_audit_rule_match(&blob,
+ if (security_audit_rule_match(&ctx->ipc.oblob,
f->type, f->op,
f->lsm_rule))
++result;
@@ -956,13 +953,57 @@ static inline void audit_free_context(struct audit_context *context)
kfree(context);
}
+static int audit_log_object_context(struct audit_buffer *ab,
+ struct lsmblob *blob)
+{
+ struct lsmcontext context;
+ const char *lsm;
+ int i;
+
+ /*
+ * None of the installed modules have object labels.
+ */
+ if (security_lsm_slot_name(0) == NULL)
+ return 0;
+
+ if (blob->secid[0] != 0) {
+ if (security_secid_to_secctx(blob, &context, 0)) {
+ audit_log_format(ab, " obj=?");
+ return 1;
+ }
+ audit_log_format(ab, " obj=%s", context.context);
+ security_release_secctx(&context);
+ }
+
+ /*
+ * Don't do anything more unless there is more than one LSM
+ * with a security context to report.
+ */
+ if (security_lsm_slot_name(1) == NULL)
+ return 0;
+
+ for (i = 0; i < LSMBLOB_ENTRIES; i++) {
+ lsm = security_lsm_slot_name(i);
+ if (lsm == NULL)
+ break;
+ if (blob->secid[i] == 0)
+ continue;
+ if (security_secid_to_secctx(blob, &context, i)) {
+ audit_log_format(ab, " obj_%s=?", lsm);
+ continue;
+ }
+ audit_log_format(ab, " obj_%s=%s", lsm, context.context);
+ security_release_secctx(&context);
+ }
+ return 0;
+}
+
static int audit_log_pid_context(struct audit_context *context, pid_t pid,
kuid_t auid, kuid_t uid,
unsigned int sessionid,
struct lsmblob *blob, char *comm)
{
struct audit_buffer *ab;
- struct lsmcontext lsmctx;
int rc = 0;
ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
@@ -972,15 +1013,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
- if (lsmblob_is_set(blob)) {
- if (security_secid_to_secctx(blob, &lsmctx, LSMBLOB_FIRST)) {
- audit_log_format(ab, " obj=(none)");
- rc = 1;
- } else {
- audit_log_format(ab, " obj=%s", lsmctx.context);
- security_release_secctx(&lsmctx);
- }
- }
+ rc = audit_log_object_context(ab, blob);
audit_log_format(ab, " ocomm=");
audit_log_untrustedstring(ab, comm);
audit_log_end(ab);
@@ -1207,26 +1240,14 @@ static void show_special(struct audit_context *context, int *call_panic)
context->socketcall.args[i]);
break; }
case AUDIT_IPC: {
- u32 osid = context->ipc.osid;
+ struct lsmblob *oblob = & context->ipc.oblob;
audit_log_format(ab, "ouid=%u ogid=%u mode=%#ho",
from_kuid(&init_user_ns, context->ipc.uid),
from_kgid(&init_user_ns, context->ipc.gid),
context->ipc.mode);
- if (osid) {
- struct lsmcontext lsmcxt;
- struct lsmblob blob;
-
- lsmblob_init(&blob, osid);
- if (security_secid_to_secctx(&blob, &lsmcxt,
- LSMBLOB_FIRST)) {
- audit_log_format(ab, " osid=%u", osid);
- *call_panic = 1;
- } else {
- audit_log_format(ab, " obj=%s", lsmcxt.context);
- security_release_secctx(&lsmcxt);
- }
- }
+ if (audit_log_object_context(ab, oblob))
+ *call_panic = 1;
if (context->ipc.has_perm) {
audit_log_end(ab);
ab = audit_log_start(context, GFP_KERNEL,
@@ -1366,20 +1387,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
from_kgid(&init_user_ns, n->gid),
MAJOR(n->rdev),
MINOR(n->rdev));
- if (n->osid != 0) {
- struct lsmblob blob;
- struct lsmcontext lsmctx;
-
- lsmblob_init(&blob, n->osid);
- if (security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_FIRST)) {
- audit_log_format(ab, " osid=%u", n->osid);
- if (call_panic)
- *call_panic = 2;
- } else {
- audit_log_format(ab, " obj=%s", lsmctx.context);
- security_release_secctx(&lsmctx);
- }
- }
+ if (audit_log_object_context(ab, &n->oblob) && call_panic)
+ *call_panic = 2;
/* log the audit_names record type */
switch (n->type) {
@@ -1929,17 +1938,13 @@ static void audit_copy_inode(struct audit_names *name,
const struct dentry *dentry,
struct inode *inode, unsigned int flags)
{
- struct lsmblob blob;
-
name->ino = inode->i_ino;
name->dev = inode->i_sb->s_dev;
name->mode = inode->i_mode;
name->uid = inode->i_uid;
name->gid = inode->i_gid;
name->rdev = inode->i_rdev;
- security_inode_getsecid(inode, &blob);
- /* scaffolding until osid is updated */
- name->osid = blob.secid[0];
+ security_inode_getsecid(inode, &name->oblob);
if (flags & AUDIT_INODE_NOEVAL) {
name->fcap_ver = -1;
return;
@@ -2285,14 +2290,11 @@ void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
struct audit_context *context = audit_context();
- struct lsmblob blob;
context->ipc.uid = ipcp->uid;
context->ipc.gid = ipcp->gid;
context->ipc.mode = ipcp->mode;
context->ipc.has_perm = 0;
- security_ipc_getsecid(ipcp, &blob);
- /* scaffolding on the [0] - change "osid" to a lsmblob */
- context->ipc.osid = blob.secid[0];
+ security_ipc_getsecid(ipcp, &context->ipc.oblob);
context->type = AUDIT_IPC;
}
--
2.20.1
^ permalink raw reply related
* [PATCH v13 23/25] NET: Add SO_PEERCONTEXT for multiple LSMs
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
The getsockopt SO_PEERSEC provides the LSM based security
information for a single module, but for reasons of backward
compatibility cannot include the information for multiple
modules. A new option SO_PEERCONTEXT is added to report the
security "context" of multiple modules using a "compound" format
lsm1\0value\0lsm2\0value\0
This is expected to be used by system services, including dbus-daemon.
The exact format of a compound context has been the subject of
considerable debate. This format was suggested by Simon McVittie,
a dbus maintainer with a significant stake in the format being
usable.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: netdev@vger.kernel.org
cc: linux-api@vger.kernel.org
---
Documentation/security/lsm.rst | 15 ++++
arch/alpha/include/uapi/asm/socket.h | 1 +
arch/mips/include/uapi/asm/socket.h | 1 +
arch/parisc/include/uapi/asm/socket.h | 1 +
arch/sparc/include/uapi/asm/socket.h | 1 +
include/linux/lsm_hooks.h | 9 +-
include/linux/security.h | 10 ++-
include/uapi/asm-generic/socket.h | 1 +
net/core/sock.c | 7 +-
security/apparmor/lsm.c | 20 ++---
security/security.c | 115 +++++++++++++++++++++++---
security/selinux/hooks.c | 20 ++---
security/smack/smack_lsm.c | 31 +++----
13 files changed, 170 insertions(+), 62 deletions(-)
diff --git a/Documentation/security/lsm.rst b/Documentation/security/lsm.rst
index aadf47c808c0..77cc326a52cc 100644
--- a/Documentation/security/lsm.rst
+++ b/Documentation/security/lsm.rst
@@ -199,3 +199,18 @@ capability-related fields:
- ``fs/nfsd/auth.c``::c:func:`nfsd_setuser()`
- ``fs/proc/array.c``::c:func:`task_cap()`
+
+LSM External Interfaces
+=======================
+
+The LSM infrastructure does not generally provide external interfaces.
+The individual security modules provide what external interfaces they
+require. The infrastructure does provide two interfaces for the special
+case where multiple security modules provide a process context. This
+is provided in compound context format.
+
+- `lsm1\0value\0lsm2\0value\0`
+
+The special file ``/proc/pid/attr/context`` provides the security
+context of the identified process. The socket option SO_PEERCONTEXT
+provides the security context of a packet.
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index de6c4df61082..b26fb34e4226 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -123,6 +123,7 @@
#define SO_SNDTIMEO_NEW 67
#define SO_DETACH_REUSEPORT_BPF 68
+#define SO_PEERCONTEXT 69
#if !defined(__KERNEL__)
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index d0a9ed2ca2d6..10e03507b1ed 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -134,6 +134,7 @@
#define SO_SNDTIMEO_NEW 67
#define SO_DETACH_REUSEPORT_BPF 68
+#define SO_PEERCONTEXT 69
#if !defined(__KERNEL__)
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index 10173c32195e..e11df59a84d1 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -115,6 +115,7 @@
#define SO_SNDTIMEO_NEW 0x4041
#define SO_DETACH_REUSEPORT_BPF 0x4042
+#define SO_PEERCONTEXT 0x4043
#if !defined(__KERNEL__)
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index 8029b681fc7c..5b41ef778040 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -116,6 +116,7 @@
#define SO_SNDTIMEO_NEW 0x0045
#define SO_DETACH_REUSEPORT_BPF 0x0047
+#define SO_PEERCONTEXT 0x0048
#if !defined(__KERNEL__)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 2bf82e1cf347..2ae10e7f81a7 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -880,8 +880,8 @@
* SO_GETPEERSEC. For tcp sockets this can be meaningful if the
* socket is associated with an ipsec SA.
* @sock is the local socket.
- * @optval userspace memory where the security state is to be copied.
- * @optlen userspace int where the module should copy the actual length
+ * @optval memory where the security state is to be copied.
+ * @optlen int where the module should copy the actual length
* of the security state.
* @len as input is the maximum length to copy to userspace provided
* by the caller.
@@ -1724,9 +1724,8 @@ union security_list_options {
int (*socket_setsockopt)(struct socket *sock, int level, int optname);
int (*socket_shutdown)(struct socket *sock, int how);
int (*socket_sock_rcv_skb)(struct sock *sk, struct sk_buff *skb);
- int (*socket_getpeersec_stream)(struct socket *sock,
- char __user *optval,
- int __user *optlen, unsigned len);
+ int (*socket_getpeersec_stream)(struct socket *sock, char **optval,
+ int *optlen, unsigned len);
int (*socket_getpeersec_dgram)(struct socket *sock,
struct sk_buff *skb, u32 *secid);
int (*sk_alloc_security)(struct sock *sk, int family, gfp_t priority);
diff --git a/include/linux/security.h b/include/linux/security.h
index d7af2bbbc878..26967055a002 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -178,6 +178,7 @@ struct lsmblob {
#define LSMBLOB_NOT_NEEDED -3 /* Slot not requested */
#define LSMBLOB_DISPLAY -4 /* Use the "display" slot */
#define LSMBLOB_FIRST -5 /* Use the default "display" slot */
+#define LSMBLOB_COMPOUND -6 /* A compound "display" */
/**
* lsmblob_init - initialize an lsmblob structure.
@@ -1396,7 +1397,8 @@ int security_socket_setsockopt(struct socket *sock, int level, int optname);
int security_socket_shutdown(struct socket *sock, int how);
int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len);
+ int __user *optlen, unsigned len,
+ int display);
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
struct lsmblob *blob);
int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
@@ -1530,8 +1532,10 @@ static inline int security_sock_rcv_skb(struct sock *sk,
return 0;
}
-static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len)
+static inline int security_socket_getpeersec_stream(struct socket *sock,
+ char __user *optval,
+ int __user *optlen,
+ unsigned len, int display)
{
return -ENOPROTOOPT;
}
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 77f7c1638eb1..e3a853d53705 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -118,6 +118,7 @@
#define SO_SNDTIMEO_NEW 67
#define SO_DETACH_REUSEPORT_BPF 68
+#define SO_PEERCONTEXT 69
#if !defined(__KERNEL__)
diff --git a/net/core/sock.c b/net/core/sock.c
index 043db3ce023e..63b7eda81a90 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1411,7 +1411,12 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_PEERSEC:
- return security_socket_getpeersec_stream(sock, optval, optlen, len);
+ return security_socket_getpeersec_stream(sock, optval, optlen,
+ len, LSMBLOB_DISPLAY);
+
+ case SO_PEERCONTEXT:
+ return security_socket_getpeersec_stream(sock, optval, optlen,
+ len, LSMBLOB_COMPOUND);
case SO_MARK:
v.val = sk->sk_mark;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 16b992235c11..34edfd29c32f 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1078,10 +1078,8 @@ static struct aa_label *sk_peer_label(struct sock *sk)
*
* Note: for tcp only valid if using ipsec or cipso on lan
*/
-static int apparmor_socket_getpeersec_stream(struct socket *sock,
- char __user *optval,
- int __user *optlen,
- unsigned int len)
+static int apparmor_socket_getpeersec_stream(struct socket *sock, char **optval,
+ int *optlen, unsigned int len)
{
char *name;
int slen, error = 0;
@@ -1101,17 +1099,11 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
if (slen < 0) {
error = -ENOMEM;
} else {
- if (slen > len) {
+ if (slen > len)
error = -ERANGE;
- } else if (copy_to_user(optval, name, slen)) {
- error = -EFAULT;
- goto out;
- }
- if (put_user(slen, optlen))
- error = -EFAULT;
-out:
- kfree(name);
-
+ else
+ *optval = name;
+ *optlen = slen;
}
done:
diff --git a/security/security.c b/security/security.c
index 6d05222aac9c..80539dfd0245 100644
--- a/security/security.c
+++ b/security/security.c
@@ -723,6 +723,42 @@ static void __init lsm_early_task(struct task_struct *task)
panic("%s: Early task alloc failed.\n", __func__);
}
+/**
+ * append_ctx - append a lsm/context pair to a compound context
+ * @ctx: the existing compound context
+ * @ctxlen: size of the old context, including terminating nul byte
+ * @lsm: new lsm name, nul terminated
+ * @new: new context, possibly nul terminated
+ * @newlen: maximum size of @new
+ *
+ * replace @ctx with a new compound context, appending @newlsm and @new
+ * to @ctx. On exit the new data replaces the old, which is freed.
+ * @ctxlen is set to the new size, which includes a trailing nul byte.
+ *
+ * Returns 0 on success, -ENOMEM if no memory is available.
+ */
+static int append_ctx(char **ctx, int *ctxlen, const char *lsm, char *new,
+ int newlen)
+{
+ char *final;
+ int llen;
+
+ llen = strlen(lsm) + 1;
+ newlen = strnlen(new, newlen) + 1;
+
+ final = kzalloc(*ctxlen + llen + newlen, GFP_KERNEL);
+ if (final == NULL)
+ return -ENOMEM;
+ if (*ctxlen)
+ memcpy(final, *ctx, *ctxlen);
+ memcpy(final + *ctxlen, lsm, llen);
+ memcpy(final + *ctxlen + llen, new, newlen);
+ kfree(*ctx);
+ *ctx = final;
+ *ctxlen = *ctxlen + llen + newlen;
+ return 0;
+}
+
/*
* Hook list operation macros.
*
@@ -2164,8 +2200,8 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm))
continue;
- if (lsm == NULL && *display != LSMBLOB_INVALID &&
- *display != hp->lsmid->slot)
+ if (lsm == NULL && display != NULL &&
+ *display != LSMBLOB_INVALID && *display != hp->lsmid->slot)
continue;
return hp->hook.setprocattr(name, value, size);
}
@@ -2245,12 +2281,21 @@ void security_release_secctx(struct lsmcontext *cp)
{
struct security_hook_list *hp;
+ if (cp->slot == LSMBLOB_INVALID)
+ return;
+
+ if (cp->slot == LSMBLOB_COMPOUND) {
+ kfree(cp->context);
+ goto clear_out;
+ }
+
hlist_for_each_entry(hp, &security_hook_heads.release_secctx, list)
if (cp->slot == hp->lsmid->slot) {
hp->hook.release_secctx(cp->context, cp->len);
break;
}
+clear_out:
memset(cp, 0, sizeof(*cp));
}
EXPORT_SYMBOL(security_release_secctx);
@@ -2383,17 +2428,67 @@ int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
EXPORT_SYMBOL(security_sock_rcv_skb);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len)
+ int __user *optlen, unsigned len,
+ int display)
{
- int display = lsm_task_display(current);
struct security_hook_list *hp;
+ char *final = NULL;
+ char *cp;
+ int rc = 0;
+ unsigned finallen = 0;
+ unsigned clen = 0;
- hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream,
- list)
- if (display == LSMBLOB_INVALID || display == hp->lsmid->slot)
- return hp->hook.socket_getpeersec_stream(sock, optval,
- optlen, len);
- return -ENOPROTOOPT;
+ switch (display) {
+ case LSMBLOB_DISPLAY:
+ rc = -ENOPROTOOPT;
+ display = lsm_task_display(current);
+ hlist_for_each_entry(hp,
+ &security_hook_heads.socket_getpeersec_stream,
+ list)
+ if (display == LSMBLOB_INVALID ||
+ display == hp->lsmid->slot) {
+ rc = hp->hook.socket_getpeersec_stream(sock,
+ &final, &finallen, len);
+ break;
+ }
+ break;
+ case LSMBLOB_COMPOUND:
+ /*
+ * A compound context, in the form [lsm\0value\0]...
+ */
+ hlist_for_each_entry(hp,
+ &security_hook_heads.socket_getpeersec_stream,
+ list) {
+ rc = hp->hook.socket_getpeersec_stream(sock, &cp, &clen,
+ len);
+ if (rc == -EINVAL || rc == -ENOPROTOOPT) {
+ rc = 0;
+ continue;
+ }
+ if (rc) {
+ kfree(final);
+ return rc;
+ }
+ rc = append_ctx(&final, &finallen, hp->lsmid->lsm,
+ cp, clen);
+ }
+ if (final == NULL)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (finallen > len)
+ rc = -ERANGE;
+ else if (copy_to_user(optval, final, finallen))
+ rc = -EFAULT;
+
+ if (put_user(finallen, optlen))
+ rc = -EFAULT;
+
+ kfree(final);
+ return rc;
}
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index cd4743331800..c3e6fd3f8c56 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5056,10 +5056,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
}
-static int selinux_socket_getpeersec_stream(struct socket *sock,
- char __user *optval,
- int __user *optlen,
- unsigned int len)
+static int selinux_socket_getpeersec_stream(struct socket *sock, char **optval,
+ int *optlen, unsigned int len)
{
int err = 0;
char *scontext;
@@ -5079,18 +5077,12 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
if (err)
return err;
- if (scontext_len > len) {
+ if (scontext_len > len)
err = -ERANGE;
- goto out_len;
- }
-
- if (copy_to_user(optval, scontext, scontext_len))
- err = -EFAULT;
+ else
+ *optval = scontext;
-out_len:
- if (put_user(scontext_len, optlen))
- err = -EFAULT;
- kfree(scontext);
+ *optlen = scontext_len;
return err;
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 9ce67e03ac49..316c5faf9053 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3957,28 +3957,29 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
*
* returns zero on success, an error code otherwise
*/
-static int smack_socket_getpeersec_stream(struct socket *sock,
- char __user *optval,
- int __user *optlen, unsigned len)
+static int smack_socket_getpeersec_stream(struct socket *sock, char **optval,
+ int *optlen, unsigned len)
{
- struct socket_smack *ssp;
- char *rcp = "";
- int slen = 1;
+ struct socket_smack *ssp = smack_sock(sock->sk);
+ char *rcp;
+ int slen;
int rc = 0;
- ssp = smack_sock(sock->sk);
- if (ssp->smk_packet != NULL) {
- rcp = ssp->smk_packet->smk_known;
- slen = strlen(rcp) + 1;
+ if (ssp->smk_packet == NULL) {
+ *optlen = 0;
+ return -EINVAL;
}
+ rcp = ssp->smk_packet->smk_known;
+ slen = strlen(rcp) + 1;
if (slen > len)
rc = -ERANGE;
- else if (copy_to_user(optval, rcp, slen) != 0)
- rc = -EFAULT;
-
- if (put_user(slen, optlen) != 0)
- rc = -EFAULT;
+ else {
+ *optval = kstrdup(rcp, GFP_KERNEL);
+ if (*optval == NULL)
+ rc = -ENOMEM;
+ }
+ *optlen = slen;
return rc;
}
--
2.20.1
^ permalink raw reply related
* [PATCH v13 25/25] AppArmor: Remove the exclusive flag
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
With the inclusion of the "display" process attribute
mechanism AppArmor no longer needs to be treated as an
"exclusive" security module. Remove the flag that indicates
it is exclusive. Remove the stub getpeersec_dgram AppArmor
hook as it has no effect in the single LSM case and
interferes in the multiple LSM case.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
security/apparmor/lsm.c | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 34edfd29c32f..402a919190fd 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1112,22 +1112,6 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock, char **optval,
return error;
}
-/**
- * apparmor_socket_getpeersec_dgram - get security label of packet
- * @sock: the peer socket
- * @skb: packet data
- * @secid: pointer to where to put the secid of the packet
- *
- * Sets the netlabel socket state on sk from parent
- */
-static int apparmor_socket_getpeersec_dgram(struct socket *sock,
- struct sk_buff *skb, u32 *secid)
-
-{
- /* TODO: requires secid support */
- return -ENOPROTOOPT;
-}
-
/**
* apparmor_sock_graft - Initialize newly created socket
* @sk: child sock
@@ -1231,8 +1215,6 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
#endif
LSM_HOOK_INIT(socket_getpeersec_stream,
apparmor_socket_getpeersec_stream),
- LSM_HOOK_INIT(socket_getpeersec_dgram,
- apparmor_socket_getpeersec_dgram),
LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
#ifdef CONFIG_NETWORK_SECMARK
LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request),
@@ -1901,7 +1883,7 @@ static int __init apparmor_init(void)
DEFINE_LSM(apparmor) = {
.name = "apparmor",
- .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+ .flags = LSM_FLAG_LEGACY_MAJOR,
.enabled = &apparmor_enabled,
.blobs = &apparmor_blob_sizes,
.init = apparmor_init,
--
2.20.1
^ permalink raw reply related
* [PATCH 24/25] LSM: Add /proc attr entry for full LSM context
From: Casey Schaufler @ 2019-12-24 23:59 UTC (permalink / raw)
To: casey.schaufler, jmorris, linux-security-module, selinux
Cc: casey, keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191224235939.7483-1-casey@schaufler-ca.com>
Add an entry /proc/.../attr/context which displays the full
process security "context" in compound format:'
lsm1\0value\0lsm2\0value\0...
This entry is not writable.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
cc: linux-api@vger.kernel.org
---
fs/proc/base.c | 1 +
security/security.c | 27 +++++++++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 950c200cb9ad..d13c2cf50e4b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2653,6 +2653,7 @@ static const struct pid_entry attr_dir_stuff[] = {
ATTR(NULL, "keycreate", 0666),
ATTR(NULL, "sockcreate", 0666),
ATTR(NULL, "display", 0666),
+ ATTR(NULL, "context", 0666),
#ifdef CONFIG_SECURITY_SMACK
DIR("smack", 0555,
proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
diff --git a/security/security.c b/security/security.c
index 80539dfd0245..e94de64e114c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2099,6 +2099,10 @@ int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
char **value)
{
struct security_hook_list *hp;
+ char *final = NULL;
+ char *cp;
+ int rc = 0;
+ int finallen = 0;
int display = lsm_task_display(current);
int slot = 0;
@@ -2126,6 +2130,29 @@ int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
return -ENOMEM;
}
+ if (!strcmp(name, "context")) {
+ hlist_for_each_entry(hp, &security_hook_heads.getprocattr,
+ list) {
+ rc = hp->hook.getprocattr(p, "current", &cp);
+ if (rc == -EINVAL || rc == -ENOPROTOOPT)
+ continue;
+ if (rc < 0) {
+ kfree(final);
+ return rc;
+ }
+ rc = append_ctx(&final, &finallen, hp->lsmid->lsm,
+ cp, rc);
+ if (rc < 0) {
+ kfree(final);
+ return rc;
+ }
+ }
+ if (final == NULL)
+ return -EINVAL;
+ *value = final;
+ return finallen;
+ }
+
hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm))
continue;
--
2.20.1
^ permalink raw reply related
* Take home 750,000 Euros this end of year
From: La Primitiva @ 2019-12-25 4:33 UTC (permalink / raw)
To: linux-security-module
Attn: Email User,
You have won, you are to reply back with your name and phone number for
claim.
La Primitiva
----------------------------------------------------
This email was sent by the shareware version of Postman Professional.
^ permalink raw reply
* [PATCH v6 01/10] proc: Rename struct proc_fs_info to proc_fs_opts
From: Alexey Gladkov @ 2019-12-25 12:51 UTC (permalink / raw)
To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
Linux Security Module
Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer,
Stephen Rothwell
In-Reply-To: <20191225125151.1950142-1-gladkov.alexey@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
fs/proc_namespace.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c
index 273ee82d8aa9..9a8b624bc3db 100644
--- a/fs/proc_namespace.c
+++ b/fs/proc_namespace.c
@@ -37,23 +37,23 @@ static __poll_t mounts_poll(struct file *file, poll_table *wait)
return res;
}
-struct proc_fs_info {
+struct proc_fs_opts {
int flag;
const char *str;
};
static int show_sb_opts(struct seq_file *m, struct super_block *sb)
{
- static const struct proc_fs_info fs_info[] = {
+ static const struct proc_fs_opts fs_opts[] = {
{ SB_SYNCHRONOUS, ",sync" },
{ SB_DIRSYNC, ",dirsync" },
{ SB_MANDLOCK, ",mand" },
{ SB_LAZYTIME, ",lazytime" },
{ 0, NULL }
};
- const struct proc_fs_info *fs_infop;
+ const struct proc_fs_opts *fs_infop;
- for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
+ for (fs_infop = fs_opts; fs_infop->flag; fs_infop++) {
if (sb->s_flags & fs_infop->flag)
seq_puts(m, fs_infop->str);
}
@@ -63,7 +63,7 @@ static int show_sb_opts(struct seq_file *m, struct super_block *sb)
static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
{
- static const struct proc_fs_info mnt_info[] = {
+ static const struct proc_fs_opts mnt_opts[] = {
{ MNT_NOSUID, ",nosuid" },
{ MNT_NODEV, ",nodev" },
{ MNT_NOEXEC, ",noexec" },
@@ -72,9 +72,9 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
{ MNT_RELATIME, ",relatime" },
{ 0, NULL }
};
- const struct proc_fs_info *fs_infop;
+ const struct proc_fs_opts *fs_infop;
- for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
+ for (fs_infop = mnt_opts; fs_infop->flag; fs_infop++) {
if (mnt->mnt_flags & fs_infop->flag)
seq_puts(m, fs_infop->str);
}
--
2.24.1
^ permalink raw reply related
* [PATCH v6 00/10] proc: modernize proc to support multiple private instances
From: Alexey Gladkov @ 2019-12-25 12:51 UTC (permalink / raw)
To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
Linux Security Module
Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer,
Stephen Rothwell
From: Alex Gladkov <gladkov.alexey@gmail.com>
Greetings!
Preface:
--------
This is RFC v6 to modernize procfs and make it able to support multiple
private instances per the same pid namespace.
RFC v1 is here:
https://lkml.org/lkml/2017/3/30/670
RFC v2 is here:
https://lkml.org/lkml/2017/4/25/282
RFC v5 is here:
https://lkml.org/lkml/2018/5/11/155
This RFC v6 can be applied on top of v5.4-rc7-49-g0e3f1ad80fc8
Procfs modernization:
---------------------
Historically procfs was always tied to pid namespaces, during pid
namespace creation we internally create a procfs mount for it. However,
this has the effect that all new procfs mounts are just a mirror of the
internal one, any change, any mount option update, any new future
introduction will propagate to all other procfs mounts that are in the
same pid namespace.
This may have solved several use cases in that time. However today we
face new requirements, and making procfs able to support new private
instances inside same pid namespace seems a major point. If we want to
to introduce new features and security mechanisms we have to make sure
first that we do not break existing usecases. Supporting private procfs
instances will allow to support new features and behaviour without
propagating it to all other procfs mounts.
Today procfs is more of a burden especially to some Embedded, IoT,
sandbox, container use cases. In user space we are over-mounting null
or inaccessible files on top to hide files and information. If we want
to hide pids we have to create PID namespaces otherwise mount options
propagate to all other proc mounts, changing a mount option value in one
mount will propagate to all other proc mounts. If we want to introduce
new features, then they will propagate to all other mounts too, resulting
either maybe new useful functionality or maybe breaking stuff. We have
also to note that userspace should not workaround procfs, the kernel
should just provide a sane simple interface.
In this regard several developers and maintainers pointed out that
there are problems with procfs and it has to be modernized:
"Here's another one: split up and modernize /proc." by Andy Lutomirski [1]
Discussion about kernel pointer leaks:
"And yes, as Kees and Daniel mentioned, it's definitely not just dmesg.
In fact, the primary things tend to be /proc and /sys, not dmesg
itself." By Linus Torvalds [2]
Lot of other areas in the kernel and filesystems have been updated to be
able to support private instances, devpts is one major example [3].
Which will be used for:
1) Embedded systems and IoT: usually we have one supervisor for
apps, we have some lightweight sandbox support, however if we create
pid namespaces we have to manage all the processes inside too,
where our goal is to be able to run a bunch of apps each one inside
its own mount namespace, maybe use network namespaces for vlans
setups, but right now we only want mount namespaces, without all the
other complexity. We want procfs to behave more like a real file system,
and block access to inodes that belong to other users. The 'hidepid=' will
not work since it is a shared mount option.
2) Containers, sandboxes and Private instances of file systems - devpts case
Historically, lot of file systems inside Linux kernel view when instantiated
were just a mirror of an already created and mounted filesystem. This was the
case of devpts filesystem, it seems at that time the requirements were to
optimize things and reuse the same memory, etc. This design used to work but not
anymore with today's containers, IoT, hostile environments and all the privacy
challenges that Linux faces.
In that regards, devpts was updated so that each new mounts is a total
independent file system by the following patches:
"devpts: Make each mount of devpts an independent filesystem" by
Eric W. Biederman [3] [4]
3) Linux Security Modules have multiple ptrace paths inside some
subsystems, however inside procfs, the implementation does not guarantee
that the ptrace() check which triggers the security_ptrace_check() hook
will always run. We have the 'hidepid' mount option that can be used to
force the ptrace_may_access() check inside has_pid_permissions() to run.
The problem is that 'hidepid' is per pid namespace and not attached to
the mount point, any remount or modification of 'hidepid' will propagate
to all other procfs mounts.
This also does not allow to support Yama LSM easily in desktop and user
sessions. Yama ptrace scope which restricts ptrace and some other
syscalls to be allowed only on inferiors, can be updated to have a
per-task context, where the context will be inherited during fork(),
clone() and preserved across execve(). If we support multiple private
procfs instances, then we may force the ptrace_may_access() on
/proc/<pids>/ to always run inside that new procfs instances. This will
allow to specifiy on user sessions if we should populate procfs with
pids that the user can ptrace or not.
By using Yama ptrace scope, some restricted users will only be able to see
inferiors inside /proc, they won't even be able to see their other
processes. Some software like Chromium, Firefox's crash handler, Wine
and others are already using Yama to restrict which processes can be
ptracable. With this change this will give the possibility to restrict
/proc/<pids>/ but more importantly this will give desktop users a
generic and usuable way to specifiy which users should see all processes
and which user can not.
Side notes:
* This covers the lack of seccomp where it is not able to parse
arguments, it is easy to install a seccomp filter on direct syscalls
that operate on pids, however /proc/<pid>/ is a Linux ABI using
filesystem syscalls. With this change all LSMs should be able to analyze
open/read/write/close... on /proc/<pid>/
4) This will allow to implement new features either in kernel or
userspace without having to worry about procfs.
In containers, sandboxes, etc we have workarounds to hide some /proc
inodes, this should be supported natively without doing extra complex
work, the kernel should be able to support sane options that work with
today and future Linux use cases.
5) Creation of new superblock with all procfs options for each procfs
mount will fix the ignoring of mount options. The problem is that the
second mount of procfs in the same pid namespace ignores the mount
options. The mount options are ignored without error until procfs is
remounted.
Before:
# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=2 0 0
# strace -e mount mount -o hidepid=1 -t proc proc /tmp/proc
mount("proc", "/tmp/proc", "proc", 0, "hidepid=1") = 0
+++ exited with 0 +++
# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=2 0 0
proc /tmp/proc proc rw,relatime,hidepid=2 0 0
# mount -o remount,hidepid=1 -t proc proc /tmp/proc
# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=1 0 0
proc /tmp/proc proc rw,relatime,hidepid=1 0 0
After:
# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=2 0 0
# mount -o hidepid=1 -t proc proc /tmp/proc
# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=2 0 0
proc /tmp/proc proc rw,relatime,hidepid=1 0 0
Introduced changes:
-------------------
Each mount of procfs creates a separate procfs instance with its own
mount options.
This series adds few new mount options:
* New 'hidepid=3' mount option to show only ptraceable processes in the procfs.
This allows to support lightweight sandboxes in Embedded Linux, also
solves the case for LSM where now with this mount option, we make sure
that they have a ptrace path in procfs.
( Maybe I should use a mask? hidepid=4? )
* 'pidonly=1' that allows to hide non-pid inodes from procfs. It can be used
in containers and sandboxes, as these are already trying to hide and block
access to procfs inodes anyway.
ChangeLog:
----------
# RFC v6:
*) 'hidepid=' and 'gid=' mount options are moved from pid namespace to superblock.
*) 'newinstance' mount option removed as Eric W. Biederman suggested.
Mount of procfs always creates a new instance.
*) 'limit_pids' renamed to 'hidepid=3'.
*) I took into account the comment of Linus Torvalds [7].
*) Documentation added.
# RFC v5:
*) Fixed a bug that caused a problem with the Fedora boot.
*) The 'pidonly' option is visible among the mount options.
# RFC v2:
*) Renamed mount options to 'newinstance' and 'pids='
Suggested-by: Andy Lutomirski <luto@kernel.org>
*) Fixed order of commit, Suggested-by: Andy Lutomirski <luto@kernel.org>
*) Many bug fixes.
# RFC v1:
*) Removed 'unshared' mount option and replaced it with 'limit_pids'
which is attached to the current procfs mount.
Suggested-by Andy Lutomirski <luto@kernel.org>
*) Do not fill dcache with pid entries that we can not ptrace.
*) Many bug fixes.
References:
-----------
[1] https://lists.linuxfoundation.org/pipermail/ksummit-discuss/2017-January/004215.html
[2] http://www.openwall.com/lists/kernel-hardening/2017/10/05/5
[3] https://lwn.net/Articles/689539/
[4] http://lxr.free-electrons.com/source/Documentation/filesystems/devpts.txt?v=3.14
[5] https://lkml.org/lkml/2017/5/2/407
[6] https://lkml.org/lkml/2017/5/3/357
[7] https://lkml.org/lkml/2018/5/11/505
Alexey Gladkov (10):
proc: Rename struct proc_fs_info to proc_fs_opts
proc: add proc_fs_info struct to store proc information
proc: move /proc/{self|thread-self} dentries to proc_fs_info
proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info
proc: add helpers to set and get proc hidepid and gid mount options
proc: support mounting procfs instances inside same pid namespace
proc: flush task dcache entries from all procfs instances
proc: instantiate only pids that we can ptrace on 'hidepid=3' mount
option
proc: add option to mount only a pids subset
docs: proc: add documentation for "hidepid=3" and "pidonly" options
and new mount behavior
Documentation/filesystems/proc.txt | 53 +++++++++++++++++
fs/locks.c | 6 +-
fs/proc/base.c | 69 +++++++++++++++------
fs/proc/generic.c | 20 +++++++
fs/proc/inode.c | 22 +++++--
fs/proc/root.c | 96 ++++++++++++++++++++++--------
fs/proc/self.c | 4 +-
fs/proc/thread_self.c | 6 +-
fs/proc_namespace.c | 14 ++---
include/linux/pid_namespace.h | 54 +++++++++++++----
include/linux/proc_fs.h | 94 ++++++++++++++++++++++++++++-
11 files changed, 362 insertions(+), 76 deletions(-)
--
2.24.1
^ permalink raw reply
* [PATCH v6 02/10] proc: add proc_fs_info struct to store proc information
From: Alexey Gladkov @ 2019-12-25 12:51 UTC (permalink / raw)
To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
Linux Security Module
Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer,
Stephen Rothwell
In-Reply-To: <20191225125151.1950142-1-gladkov.alexey@gmail.com>
This is a preparation patch that adds proc_fs_info to be able to store
different procfs options and informations. Right now some mount options
are stored inside the pid namespace which makes it hard to change or
modernize procfs without affecting pid namespaces. Plus we do want to
treat proc as more of a real mount point and filesystem. procfs is part
of Linux API where it offers some features using filesystem syscalls and
in order to support some features where we are able to have multiple
instances of procfs, each one with its mount options inside the same pid
namespace, we have to separate these procfs instances.
This is the same feature that was also added to other Linux interfaces
like devpts in order to support containers, sandboxes, and to have
multiple instances of devpts filesystem [1].
[1] https://elixir.bootlin.com/linux/v3.4/source/Documentation/filesystems/devpts.txt
Cc: Kees Cook <keescook@chromium.org>
Suggested-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
fs/locks.c | 6 +++--
fs/proc/base.c | 8 +++++--
fs/proc/inode.c | 4 ++--
fs/proc/root.c | 49 +++++++++++++++++++++++++++--------------
include/linux/proc_fs.h | 16 +++++++++++++-
5 files changed, 59 insertions(+), 24 deletions(-)
diff --git a/fs/locks.c b/fs/locks.c
index 6970f55daf54..21200e3005e4 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2795,7 +2795,8 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
{
struct inode *inode = NULL;
unsigned int fl_pid;
- struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info;
+ struct proc_fs_info *fs_info = proc_sb_info(file_inode(f->file)->i_sb);
+ struct pid_namespace *proc_pidns = fs_info->pid_ns;
fl_pid = locks_translate_pid(fl, proc_pidns);
/*
@@ -2873,7 +2874,8 @@ static int locks_show(struct seq_file *f, void *v)
{
struct locks_iterator *iter = f->private;
struct file_lock *fl, *bfl;
- struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info;
+ struct proc_fs_info *fs_info = proc_sb_info(file_inode(f->file)->i_sb);
+ struct pid_namespace *proc_pidns = fs_info->pid_ns;
fl = hlist_entry(v, struct file_lock, fl_link);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index ebea9501afb8..672e71c52dbd 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3243,6 +3243,7 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
{
struct task_struct *task;
unsigned tgid;
+ struct proc_fs_info *fs_info;
struct pid_namespace *ns;
struct dentry *result = ERR_PTR(-ENOENT);
@@ -3250,7 +3251,8 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
if (tgid == ~0U)
goto out;
- ns = dentry->d_sb->s_fs_info;
+ fs_info = proc_sb_info(dentry->d_sb);
+ ns = fs_info->pid_ns;
rcu_read_lock();
task = find_task_by_pid_ns(tgid, ns);
if (task)
@@ -3538,6 +3540,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
struct task_struct *task;
struct task_struct *leader = get_proc_task(dir);
unsigned tid;
+ struct proc_fs_info *fs_info;
struct pid_namespace *ns;
struct dentry *result = ERR_PTR(-ENOENT);
@@ -3548,7 +3551,8 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
if (tid == ~0U)
goto out;
- ns = dentry->d_sb->s_fs_info;
+ fs_info = proc_sb_info(dentry->d_sb);
+ ns = fs_info->pid_ns;
rcu_read_lock();
task = find_task_by_pid_ns(tid, ns);
if (task)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index dbe43a50caf2..b631608dfbcc 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -104,8 +104,8 @@ void __init proc_init_kmemcache(void)
static int proc_show_options(struct seq_file *seq, struct dentry *root)
{
- struct super_block *sb = root->d_sb;
- struct pid_namespace *pid = sb->s_fs_info;
+ struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
+ struct pid_namespace *pid = fs_info->pid_ns;
if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID))
seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 0b7c8dffc9ae..d449f095f0f7 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -30,7 +30,7 @@
#include "internal.h"
struct proc_fs_context {
- struct pid_namespace *pid_ns;
+ struct proc_fs_info *fs_info;
unsigned int mask;
int hidepid;
int gid;
@@ -97,7 +97,8 @@ static void proc_apply_options(struct super_block *s,
static int proc_fill_super(struct super_block *s, struct fs_context *fc)
{
- struct pid_namespace *pid_ns = get_pid_ns(s->s_fs_info);
+ struct proc_fs_context *ctx = fc->fs_private;
+ struct pid_namespace *pid_ns = get_pid_ns(ctx->fs_info->pid_ns);
struct inode *root_inode;
int ret;
@@ -145,7 +146,8 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
static int proc_reconfigure(struct fs_context *fc)
{
struct super_block *sb = fc->root->d_sb;
- struct pid_namespace *pid = sb->s_fs_info;
+ struct proc_fs_info *fs_info = proc_sb_info(sb);
+ struct pid_namespace *pid = fs_info->pid_ns;
sync_filesystem(sb);
@@ -157,14 +159,14 @@ static int proc_get_tree(struct fs_context *fc)
{
struct proc_fs_context *ctx = fc->fs_private;
- return get_tree_keyed(fc, proc_fill_super, ctx->pid_ns);
+ return get_tree_keyed(fc, proc_fill_super, ctx->fs_info);
}
static void proc_fs_context_free(struct fs_context *fc)
{
struct proc_fs_context *ctx = fc->fs_private;
- put_pid_ns(ctx->pid_ns);
+ put_pid_ns(ctx->fs_info->pid_ns);
kfree(ctx);
}
@@ -178,14 +180,27 @@ static const struct fs_context_operations proc_fs_context_ops = {
static int proc_init_fs_context(struct fs_context *fc)
{
struct proc_fs_context *ctx;
+ struct pid_namespace *pid_ns;
ctx = kzalloc(sizeof(struct proc_fs_context), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
- ctx->pid_ns = get_pid_ns(task_active_pid_ns(current));
+ pid_ns = get_pid_ns(task_active_pid_ns(current));
+
+ if (!pid_ns->proc_mnt) {
+ ctx->fs_info = kzalloc(sizeof(struct proc_fs_info), GFP_KERNEL);
+ if (!ctx->fs_info) {
+ kfree(ctx);
+ return -ENOMEM;
+ }
+ ctx->fs_info->pid_ns = pid_ns;
+ } else {
+ ctx->fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
+ }
+
put_user_ns(fc->user_ns);
- fc->user_ns = get_user_ns(ctx->pid_ns->user_ns);
+ fc->user_ns = get_user_ns(ctx->fs_info->pid_ns->user_ns);
fc->fs_private = ctx;
fc->ops = &proc_fs_context_ops;
return 0;
@@ -193,15 +208,15 @@ static int proc_init_fs_context(struct fs_context *fc)
static void proc_kill_sb(struct super_block *sb)
{
- struct pid_namespace *ns;
+ struct proc_fs_info *fs_info = proc_sb_info(sb);
- ns = (struct pid_namespace *)sb->s_fs_info;
- if (ns->proc_self)
- dput(ns->proc_self);
- if (ns->proc_thread_self)
- dput(ns->proc_thread_self);
+ if (fs_info->pid_ns->proc_self)
+ dput(fs_info->pid_ns->proc_self);
+ if (fs_info->pid_ns->proc_thread_self)
+ dput(fs_info->pid_ns->proc_thread_self);
kill_anon_super(sb);
- put_pid_ns(ns);
+ put_pid_ns(fs_info->pid_ns);
+ kfree(fs_info);
}
static struct file_system_type proc_fs_type = {
@@ -314,10 +329,10 @@ int pid_ns_prepare_proc(struct pid_namespace *ns)
}
ctx = fc->fs_private;
- if (ctx->pid_ns != ns) {
- put_pid_ns(ctx->pid_ns);
+ if (ctx->fs_info->pid_ns != ns) {
+ put_pid_ns(ctx->fs_info->pid_ns);
get_pid_ns(ns);
- ctx->pid_ns = ns;
+ ctx->fs_info->pid_ns = ns;
}
mnt = fc_mount(fc);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index a705aa2d03f9..6ef09e01bf10 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -12,10 +12,19 @@ struct proc_dir_entry;
struct seq_file;
struct seq_operations;
+struct proc_fs_info {
+ struct pid_namespace *pid_ns;
+};
+
#ifdef CONFIG_PROC_FS
typedef int (*proc_write_t)(struct file *, char *, size_t);
+static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+
extern void proc_root_init(void);
extern void proc_flush_task(struct task_struct *);
@@ -86,6 +95,11 @@ int proc_pid_arch_status(struct seq_file *m, struct pid_namespace *ns,
#else /* CONFIG_PROC_FS */
+static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
+{
+ return NULL;
+}
+
static inline void proc_root_init(void)
{
}
@@ -146,7 +160,7 @@ int open_related_ns(struct ns_common *ns,
/* get the associated pid namespace for a file in procfs */
static inline struct pid_namespace *proc_pid_ns(const struct inode *inode)
{
- return inode->i_sb->s_fs_info;
+ return proc_sb_info(inode->i_sb)->pid_ns;
}
#endif /* _LINUX_PROC_FS_H */
--
2.24.1
^ permalink raw reply related
* [PATCH v6 05/10] proc: add helpers to set and get proc hidepid and gid mount options
From: Alexey Gladkov @ 2019-12-25 12:51 UTC (permalink / raw)
To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
Linux Security Module
Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer,
Stephen Rothwell
In-Reply-To: <20191225125151.1950142-1-gladkov.alexey@gmail.com>
This is a cleaning patch to add helpers to set and get proc mount
options instead of directly using them. This make it easy to track
what's happening and easy to update in future.
Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
fs/proc/base.c | 6 +++---
fs/proc/inode.c | 11 +++++++----
fs/proc/root.c | 8 ++++----
include/linux/proc_fs.h | 38 ++++++++++++++++++++++++++++++++++++++
4 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index caca1929fee1..4ccb280a3e79 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -699,9 +699,9 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info,
struct task_struct *task,
int hide_pid_min)
{
- if (fs_info->hide_pid < hide_pid_min)
+ if (proc_fs_hide_pid(fs_info) < hide_pid_min)
return true;
- if (in_group_p(fs_info->pid_gid))
+ if (in_group_p(proc_fs_pid_gid(fs_info)))
return true;
return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
}
@@ -720,7 +720,7 @@ static int proc_pid_permission(struct inode *inode, int mask)
put_task_struct(task);
if (!has_perms) {
- if (fs_info->hide_pid == HIDEPID_INVISIBLE) {
+ if (proc_fs_hide_pid(fs_info) == HIDEPID_INVISIBLE) {
/*
* Let's make getdents(), stat(), and open()
* consistent with each other. If a process
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index b90c233e5968..70b722fb8811 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -105,11 +105,14 @@ void __init proc_init_kmemcache(void)
static int proc_show_options(struct seq_file *seq, struct dentry *root)
{
struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
+ int hidepid = proc_fs_hide_pid(fs_info);
+ kgid_t gid = proc_fs_pid_gid(fs_info);
- if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID))
- seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid));
- if (fs_info->hide_pid != HIDEPID_OFF)
- seq_printf(seq, ",hidepid=%u", fs_info->hide_pid);
+ if (!gid_eq(gid, GLOBAL_ROOT_GID))
+ seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, gid));
+
+ if (hidepid != HIDEPID_OFF)
+ seq_printf(seq, ",hidepid=%u", hidepid);
return 0;
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 1ca47d446aa4..efd76c004e86 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -91,14 +91,14 @@ static void proc_apply_options(struct super_block *s,
if (pid_ns->proc_mnt) {
struct proc_fs_info *fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
- ctx->fs_info->pid_gid = fs_info->pid_gid;
- ctx->fs_info->hide_pid = fs_info->hide_pid;
+ proc_fs_set_pid_gid(ctx->fs_info, proc_fs_pid_gid(fs_info));
+ proc_fs_set_hide_pid(ctx->fs_info, proc_fs_hide_pid(fs_info));
}
if (ctx->mask & (1 << Opt_gid))
- ctx->fs_info->pid_gid = make_kgid(user_ns, ctx->gid);
+ proc_fs_set_pid_gid(ctx->fs_info, make_kgid(user_ns, ctx->gid));
if (ctx->mask & (1 << Opt_hidepid))
- ctx->fs_info->hide_pid = ctx->hidepid;
+ proc_fs_set_hide_pid(ctx->fs_info, ctx->hidepid);
}
static int proc_fill_super(struct super_block *s, struct fs_context *fc)
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 05ecf4e8923f..fd92bf38aa62 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -36,6 +36,26 @@ static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
return sb->s_fs_info;
}
+static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid)
+{
+ fs_info->hide_pid = hide_pid;
+}
+
+static inline void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid)
+{
+ fs_info->pid_gid = gid;
+}
+
+static inline int proc_fs_hide_pid(struct proc_fs_info *fs_info)
+{
+ return fs_info->hide_pid;
+}
+
+static inline kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info)
+{
+ return fs_info->pid_gid;
+}
+
extern void proc_root_init(void);
extern void proc_flush_task(struct task_struct *);
@@ -111,6 +131,24 @@ static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
return NULL;
}
+static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid)
+{
+}
+
+static inline void proc_fs_set_pid_gid(struct proc_info_fs *fs_info, kgid_t gid)
+{
+}
+
+static inline int proc_fs_hide_pid(struct proc_fs_info *fs_info)
+{
+ return 0;
+}
+
+extern kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info)
+{
+ return GLOBAL_ROOT_GID;
+}
+
static inline void proc_root_init(void)
{
}
--
2.24.1
^ permalink raw reply related
* [PATCH v6 07/10] proc: flush task dcache entries from all procfs instances
From: Alexey Gladkov @ 2019-12-25 12:51 UTC (permalink / raw)
To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
Linux Security Module
Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer,
Stephen Rothwell
In-Reply-To: <20191225125151.1950142-1-gladkov.alexey@gmail.com>
This allows to flush dcache entries of a task on multiple procfs mounts
per pid namespace.
Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
fs/proc/base.c | 23 ++++++++++++++-----
fs/proc/root.c | 14 ++++++++++++
include/linux/pid_namespace.h | 42 +++++++++++++++++++++++++++++++++++
include/linux/proc_fs.h | 2 ++
4 files changed, 76 insertions(+), 5 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 4ccb280a3e79..f4f1bcb28603 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3133,7 +3133,7 @@ static const struct inode_operations proc_tgid_base_inode_operations = {
.permission = proc_pid_permission,
};
-static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
+static void proc_flush_task_mnt_root(struct dentry *mnt_root, pid_t pid, pid_t tgid)
{
struct dentry *dentry, *leader, *dir;
char buf[10 + 1];
@@ -3142,7 +3142,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
name.name = buf;
name.len = snprintf(buf, sizeof(buf), "%u", pid);
/* no ->d_hash() rejects on procfs */
- dentry = d_hash_and_lookup(mnt->mnt_root, &name);
+ dentry = d_hash_and_lookup(mnt_root, &name);
if (dentry) {
d_invalidate(dentry);
dput(dentry);
@@ -3153,7 +3153,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
name.name = buf;
name.len = snprintf(buf, sizeof(buf), "%u", tgid);
- leader = d_hash_and_lookup(mnt->mnt_root, &name);
+ leader = d_hash_and_lookup(mnt_root, &name);
if (!leader)
goto out;
@@ -3208,14 +3208,27 @@ void proc_flush_task(struct task_struct *task)
int i;
struct pid *pid, *tgid;
struct upid *upid;
+ struct pid_namespace *pid_ns;
+ struct dentry *mnt_root;
+ struct proc_fs_info *fs_info;
pid = task_pid(task);
tgid = task_tgid(task);
for (i = 0; i <= pid->level; i++) {
upid = &pid->numbers[i];
- proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr,
- tgid->numbers[i].nr);
+
+ pid_ns = upid->ns;
+
+ pidns_proc_lock_shared(pid_ns);
+ list_for_each_entry(fs_info, &pid_ns->proc_mounts, pidns_entry) {
+ mnt_root = fs_info->m_super->s_root;
+ proc_flush_task_mnt_root(mnt_root, upid->nr, tgid->numbers[i].nr);
+ }
+ pidns_proc_unlock_shared(pid_ns);
+
+ mnt_root = pid_ns->proc_mnt->mnt_root;
+ proc_flush_task_mnt_root(mnt_root, upid->nr, tgid->numbers[i].nr);
}
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 5d5cba4c899b..3bb8df360cf7 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -112,6 +112,12 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
proc_apply_options(ctx->fs_info, fc, pid_ns, current_user_ns());
+ ctx->fs_info->m_super = s;
+
+ pidns_proc_lock(pid_ns);
+ list_add_tail(&ctx->fs_info->pidns_entry, &pid_ns->proc_mounts);
+ pidns_proc_unlock(pid_ns);
+
/* User space would break if executables or devices appear on proc */
s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC;
@@ -215,6 +221,11 @@ static void proc_kill_sb(struct super_block *sb)
dput(fs_info->proc_self);
if (fs_info->proc_thread_self)
dput(fs_info->proc_thread_self);
+
+ pidns_proc_lock(fs_info->pid_ns);
+ list_del(&fs_info->pidns_entry);
+ pidns_proc_unlock(fs_info->pid_ns);
+
kill_anon_super(sb);
put_pid_ns(fs_info->pid_ns);
kfree(fs_info);
@@ -336,6 +347,9 @@ int pid_ns_prepare_proc(struct pid_namespace *ns)
ctx->fs_info->pid_ns = ns;
}
+ init_rwsem(&ns->rw_proc_mounts);
+ INIT_LIST_HEAD(&ns->proc_mounts);
+
mnt = fc_mount(fc);
put_fs_context(fc);
if (IS_ERR(mnt))
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 66f47f1afe0d..297b39604312 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -26,6 +26,8 @@ struct pid_namespace {
struct pid_namespace *parent;
#ifdef CONFIG_PROC_FS
struct vfsmount *proc_mnt; /* Internal proc mounted during each new pidns */
+ struct rw_semaphore rw_proc_mounts;
+ struct list_head proc_mounts; /* list of separated procfs mounts */
#endif
#ifdef CONFIG_BSD_PROCESS_ACCT
struct fs_pin *bacct;
@@ -90,4 +92,44 @@ extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk);
void pidhash_init(void);
void pid_idr_init(void);
+#ifdef CONFIG_PROC_FS
+static inline void pidns_proc_lock(struct pid_namespace *pid_ns)
+{
+ down_write(&pid_ns->rw_proc_mounts);
+}
+
+static inline void pidns_proc_unlock(struct pid_namespace *pid_ns)
+{
+ up_write(&pid_ns->rw_proc_mounts);
+}
+
+static inline void pidns_proc_lock_shared(struct pid_namespace *pid_ns)
+{
+ down_read(&pid_ns->rw_proc_mounts);
+}
+
+static inline void pidns_proc_unlock_shared(struct pid_namespace *pid_ns)
+{
+ up_read(&pid_ns->rw_proc_mounts);
+}
+#else /* !CONFIG_PROC_FS */
+
+static inline void pidns_proc_lock(struct pid_namespace *pid_ns)
+{
+}
+
+static inline void pidns_proc_unlock(struct pid_namespace *pid_ns)
+{
+}
+
+static inline void pidns_proc_lock_shared(struct pid_namespace *pid_ns)
+{
+}
+
+static inline void pidns_proc_unlock_shared(struct pid_namespace *pid_ns)
+{
+}
+
+#endif /* CONFIG_PROC_FS */
+
#endif /* _LINUX_PID_NS_H */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index fd92bf38aa62..e349fcafd729 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -20,6 +20,8 @@ enum {
};
struct proc_fs_info {
+ struct list_head pidns_entry; /* Node in procfs_mounts of a pidns */
+ struct super_block *m_super;
struct pid_namespace *pid_ns;
struct dentry *proc_self; /* For /proc/self */
struct dentry *proc_thread_self; /* For /proc/thread-self */
--
2.24.1
^ permalink raw reply related
* [PATCH v6 03/10] proc: move /proc/{self|thread-self} dentries to proc_fs_info
From: Alexey Gladkov @ 2019-12-25 12:51 UTC (permalink / raw)
To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
Linux Security Module
Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer,
Stephen Rothwell
In-Reply-To: <20191225125151.1950142-1-gladkov.alexey@gmail.com>
This is a preparation patch that moves /proc/{self|thread-self} dentries
to be stored inside procfs fs_info struct instead of making them per pid
namespace. Since we want to support multiple procfs instances we need to
make sure that these dentries are also per-superblock instead of
per-pidns, unmounting a private procfs won't clash with other procfs
mounts.
Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
fs/proc/base.c | 5 +++--
fs/proc/root.c | 8 ++++----
fs/proc/self.c | 4 ++--
fs/proc/thread_self.c | 6 +++---
include/linux/pid_namespace.h | 4 +---
include/linux/proc_fs.h | 2 ++
6 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 672e71c52dbd..1eb366ad8b06 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3316,6 +3316,7 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite
int proc_pid_readdir(struct file *file, struct dir_context *ctx)
{
struct tgid_iter iter;
+ struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb);
struct pid_namespace *ns = proc_pid_ns(file_inode(file));
loff_t pos = ctx->pos;
@@ -3323,13 +3324,13 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx)
return 0;
if (pos == TGID_OFFSET - 2) {
- struct inode *inode = d_inode(ns->proc_self);
+ struct inode *inode = d_inode(fs_info->proc_self);
if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
return 0;
ctx->pos = pos = pos + 1;
}
if (pos == TGID_OFFSET - 1) {
- struct inode *inode = d_inode(ns->proc_thread_self);
+ struct inode *inode = d_inode(fs_info->proc_thread_self);
if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK))
return 0;
ctx->pos = pos = pos + 1;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index d449f095f0f7..637e26cc795e 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -210,10 +210,10 @@ static void proc_kill_sb(struct super_block *sb)
{
struct proc_fs_info *fs_info = proc_sb_info(sb);
- if (fs_info->pid_ns->proc_self)
- dput(fs_info->pid_ns->proc_self);
- if (fs_info->pid_ns->proc_thread_self)
- dput(fs_info->pid_ns->proc_thread_self);
+ if (fs_info->proc_self)
+ dput(fs_info->proc_self);
+ if (fs_info->proc_thread_self)
+ dput(fs_info->proc_thread_self);
kill_anon_super(sb);
put_pid_ns(fs_info->pid_ns);
kfree(fs_info);
diff --git a/fs/proc/self.c b/fs/proc/self.c
index 57c0a1047250..846fc2b7c8a8 100644
--- a/fs/proc/self.c
+++ b/fs/proc/self.c
@@ -36,7 +36,7 @@ static unsigned self_inum __ro_after_init;
int proc_setup_self(struct super_block *s)
{
struct inode *root_inode = d_inode(s->s_root);
- struct pid_namespace *ns = proc_pid_ns(root_inode);
+ struct proc_fs_info *fs_info = proc_sb_info(s);
struct dentry *self;
int ret = -ENOMEM;
@@ -62,7 +62,7 @@ int proc_setup_self(struct super_block *s)
if (ret)
pr_err("proc_fill_super: can't allocate /proc/self\n");
else
- ns->proc_self = self;
+ fs_info->proc_self = self;
return ret;
}
diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c
index f61ae53533f5..2493cbbdfa6f 100644
--- a/fs/proc/thread_self.c
+++ b/fs/proc/thread_self.c
@@ -36,7 +36,7 @@ static unsigned thread_self_inum __ro_after_init;
int proc_setup_thread_self(struct super_block *s)
{
struct inode *root_inode = d_inode(s->s_root);
- struct pid_namespace *ns = proc_pid_ns(root_inode);
+ struct proc_fs_info *fs_info = proc_sb_info(s);
struct dentry *thread_self;
int ret = -ENOMEM;
@@ -60,9 +60,9 @@ int proc_setup_thread_self(struct super_block *s)
inode_unlock(root_inode);
if (ret)
- pr_err("proc_fill_super: can't allocate /proc/thread_self\n");
+ pr_err("proc_fill_super: can't allocate /proc/thread-self\n");
else
- ns->proc_thread_self = thread_self;
+ fs_info->proc_thread_self = thread_self;
return ret;
}
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 49538b172483..f91a8bf6e09e 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -31,9 +31,7 @@ struct pid_namespace {
unsigned int level;
struct pid_namespace *parent;
#ifdef CONFIG_PROC_FS
- struct vfsmount *proc_mnt;
- struct dentry *proc_self;
- struct dentry *proc_thread_self;
+ struct vfsmount *proc_mnt; /* Internal proc mounted during each new pidns */
#endif
#ifdef CONFIG_BSD_PROCESS_ACCT
struct fs_pin *bacct;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 6ef09e01bf10..fa44c2348e52 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -14,6 +14,8 @@ struct seq_operations;
struct proc_fs_info {
struct pid_namespace *pid_ns;
+ struct dentry *proc_self; /* For /proc/self */
+ struct dentry *proc_thread_self; /* For /proc/thread-self */
};
#ifdef CONFIG_PROC_FS
--
2.24.1
^ permalink raw reply related
* [PATCH v6 04/10] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info
From: Alexey Gladkov @ 2019-12-25 12:51 UTC (permalink / raw)
To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
Linux Security Module
Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer,
Stephen Rothwell
In-Reply-To: <20191225125151.1950142-1-gladkov.alexey@gmail.com>
This is a preparation patch that moves hide_pid and pid_gid parameters
to be stored inside procfs fs_info struct instead of making them per pid
namespace. Since we want to support multiple procfs instances we need to
make sure that all proc-specific parameters are also per-superblock.
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
fs/proc/base.c | 18 +++++++++---------
fs/proc/inode.c | 9 ++++-----
fs/proc/root.c | 10 ++++++++--
include/linux/pid_namespace.h | 8 --------
include/linux/proc_fs.h | 9 +++++++++
5 files changed, 30 insertions(+), 24 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1eb366ad8b06..caca1929fee1 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -695,13 +695,13 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
* May current process learn task's sched/cmdline info (for hide_pid_min=1)
* or euid/egid (for hide_pid_min=2)?
*/
-static bool has_pid_permissions(struct pid_namespace *pid,
+static bool has_pid_permissions(struct proc_fs_info *fs_info,
struct task_struct *task,
int hide_pid_min)
{
- if (pid->hide_pid < hide_pid_min)
+ if (fs_info->hide_pid < hide_pid_min)
return true;
- if (in_group_p(pid->pid_gid))
+ if (in_group_p(fs_info->pid_gid))
return true;
return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
}
@@ -709,18 +709,18 @@ static bool has_pid_permissions(struct pid_namespace *pid,
static int proc_pid_permission(struct inode *inode, int mask)
{
- struct pid_namespace *pid = proc_pid_ns(inode);
+ struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
struct task_struct *task;
bool has_perms;
task = get_proc_task(inode);
if (!task)
return -ESRCH;
- has_perms = has_pid_permissions(pid, task, HIDEPID_NO_ACCESS);
+ has_perms = has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS);
put_task_struct(task);
if (!has_perms) {
- if (pid->hide_pid == HIDEPID_INVISIBLE) {
+ if (fs_info->hide_pid == HIDEPID_INVISIBLE) {
/*
* Let's make getdents(), stat(), and open()
* consistent with each other. If a process
@@ -1784,7 +1784,7 @@ int pid_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
{
struct inode *inode = d_inode(path->dentry);
- struct pid_namespace *pid = proc_pid_ns(inode);
+ struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
struct task_struct *task;
generic_fillattr(inode, stat);
@@ -1794,7 +1794,7 @@ int pid_getattr(const struct path *path, struct kstat *stat,
rcu_read_lock();
task = pid_task(proc_pid(inode), PIDTYPE_PID);
if (task) {
- if (!has_pid_permissions(pid, task, HIDEPID_INVISIBLE)) {
+ if (!has_pid_permissions(fs_info, task, HIDEPID_INVISIBLE)) {
rcu_read_unlock();
/*
* This doesn't prevent learning whether PID exists,
@@ -3344,7 +3344,7 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx)
unsigned int len;
cond_resched();
- if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE))
+ if (!has_pid_permissions(fs_info, iter.task, HIDEPID_INVISIBLE))
continue;
len = snprintf(name, sizeof(name), "%u", iter.tgid);
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index b631608dfbcc..b90c233e5968 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -105,12 +105,11 @@ void __init proc_init_kmemcache(void)
static int proc_show_options(struct seq_file *seq, struct dentry *root)
{
struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
- struct pid_namespace *pid = fs_info->pid_ns;
- if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID))
- seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));
- if (pid->hide_pid != HIDEPID_OFF)
- seq_printf(seq, ",hidepid=%u", pid->hide_pid);
+ if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID))
+ seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid));
+ if (fs_info->hide_pid != HIDEPID_OFF)
+ seq_printf(seq, ",hidepid=%u", fs_info->hide_pid);
return 0;
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 637e26cc795e..1ca47d446aa4 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -89,10 +89,16 @@ static void proc_apply_options(struct super_block *s,
{
struct proc_fs_context *ctx = fc->fs_private;
+ if (pid_ns->proc_mnt) {
+ struct proc_fs_info *fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
+ ctx->fs_info->pid_gid = fs_info->pid_gid;
+ ctx->fs_info->hide_pid = fs_info->hide_pid;
+ }
+
if (ctx->mask & (1 << Opt_gid))
- pid_ns->pid_gid = make_kgid(user_ns, ctx->gid);
+ ctx->fs_info->pid_gid = make_kgid(user_ns, ctx->gid);
if (ctx->mask & (1 << Opt_hidepid))
- pid_ns->hide_pid = ctx->hidepid;
+ ctx->fs_info->hide_pid = ctx->hidepid;
}
static int proc_fill_super(struct super_block *s, struct fs_context *fc)
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index f91a8bf6e09e..66f47f1afe0d 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -15,12 +15,6 @@
struct fs_pin;
-enum { /* definitions for pid_namespace's hide_pid field */
- HIDEPID_OFF = 0,
- HIDEPID_NO_ACCESS = 1,
- HIDEPID_INVISIBLE = 2,
-};
-
struct pid_namespace {
struct kref kref;
struct idr idr;
@@ -39,8 +33,6 @@ struct pid_namespace {
struct user_namespace *user_ns;
struct ucounts *ucounts;
struct work_struct proc_work;
- kgid_t pid_gid;
- int hide_pid;
int reboot; /* group exit code if this pidns was rebooted */
struct ns_common ns;
} __randomize_layout;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index fa44c2348e52..05ecf4e8923f 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -12,10 +12,19 @@ struct proc_dir_entry;
struct seq_file;
struct seq_operations;
+/* definitions for hide_pid field */
+enum {
+ HIDEPID_OFF = 0,
+ HIDEPID_NO_ACCESS = 1,
+ HIDEPID_INVISIBLE = 2,
+};
+
struct proc_fs_info {
struct pid_namespace *pid_ns;
struct dentry *proc_self; /* For /proc/self */
struct dentry *proc_thread_self; /* For /proc/thread-self */
+ kgid_t pid_gid;
+ int hide_pid;
};
#ifdef CONFIG_PROC_FS
--
2.24.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