summaryrefslogtreecommitdiff
path: root/security/smack
diff options
context:
space:
mode:
Diffstat (limited to 'security/smack')
-rw-r--r--security/smack/Kconfig12
-rw-r--r--security/smack/smack.h18
-rw-r--r--security/smack/smack_access.c4
-rw-r--r--security/smack/smack_lsm.c55
-rw-r--r--security/smack/smack_netfilter.c4
-rw-r--r--security/smack/smackfs.c11
6 files changed, 79 insertions, 25 deletions
diff --git a/security/smack/Kconfig b/security/smack/Kconfig
index 271adae81796..923b120e0fa5 100644
--- a/security/smack/Kconfig
+++ b/security/smack/Kconfig
@@ -40,3 +40,15 @@ config SECURITY_SMACK_NETFILTER
This enables security marking of network packets using
Smack labels.
If you are unsure how to answer this question, answer N.
+
+config SECURITY_SMACK_APPEND_SIGNALS
+ bool "Treat delivering signals as an append operation"
+ depends on SECURITY_SMACK
+ default n
+ help
+ Sending a signal has been treated as a write operation to the
+ receiving process. If this option is selected, the delivery
+ will be an append operation instead. This makes it possible
+ to differentiate between delivering a network packet and
+ delivering a signal in the Smack rules.
+ If you are unsure how to answer this question, answer N.
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 6c91156ae225..51fd30192c08 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -90,9 +90,15 @@ struct superblock_smack {
struct smack_known *smk_floor;
struct smack_known *smk_hat;
struct smack_known *smk_default;
- int smk_initialized;
+ int smk_flags;
};
+/*
+ * Superblock flags
+ */
+#define SMK_SB_INITIALIZED 0x01
+#define SMK_SB_UNTRUSTED 0x02
+
struct socket_smack {
struct smack_known *smk_out; /* outbound label */
struct smack_known *smk_in; /* inbound label */
@@ -250,6 +256,16 @@ enum {
#define MAY_LOCK 0x00002000 /* Locks should be writes, but ... */
#define MAY_BRINGUP 0x00004000 /* Report use of this rule */
+/*
+ * The policy for delivering signals is configurable.
+ * It is usually "write", but can be "append".
+ */
+#ifdef CONFIG_SECURITY_SMACK_APPEND_SIGNALS
+#define MAY_DELIVER MAY_APPEND /* Signal delivery requires append */
+#else
+#define MAY_DELIVER MAY_WRITE /* Signal delivery requires write */
+#endif
+
#define SMACK_BRINGUP_ALLOW 1 /* Allow bringup mode */
#define SMACK_UNCONFINED_SUBJECT 2 /* Allow unconfined label */
#define SMACK_UNCONFINED_OBJECT 3 /* Allow unconfined label */
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index a283f9e796c1..23e5808a0970 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -413,7 +413,7 @@ void smk_insert_entry(struct smack_known *skp)
unsigned int hash;
struct hlist_head *head;
- hash = full_name_hash(skp->smk_known, strlen(skp->smk_known));
+ hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known));
head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
hlist_add_head_rcu(&skp->smk_hashed, head);
@@ -433,7 +433,7 @@ struct smack_known *smk_find_entry(const char *string)
struct hlist_head *head;
struct smack_known *skp;
- hash = full_name_hash(string, strlen(string));
+ hash = full_name_hash(NULL, string, strlen(string));
head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
hlist_for_each_entry_rcu(skp, head, smk_hashed)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index ff2b8c3cf7a9..caec2256ab22 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -549,7 +549,7 @@ static int smack_sb_alloc_security(struct super_block *sb)
sbsp->smk_floor = &smack_known_floor;
sbsp->smk_hat = &smack_known_hat;
/*
- * smk_initialized will be zero from kzalloc.
+ * SMK_SB_INITIALIZED will be zero from kzalloc.
*/
sb->s_security = sbsp;
@@ -766,10 +766,10 @@ static int smack_set_mnt_opts(struct super_block *sb,
int num_opts = opts->num_mnt_opts;
int transmute = 0;
- if (sp->smk_initialized)
+ if (sp->smk_flags & SMK_SB_INITIALIZED)
return 0;
- sp->smk_initialized = 1;
+ sp->smk_flags |= SMK_SB_INITIALIZED;
for (i = 0; i < num_opts; i++) {
switch (opts->mnt_opts_flags[i]) {
@@ -821,6 +821,17 @@ static int smack_set_mnt_opts(struct super_block *sb,
skp = smk_of_current();
sp->smk_root = skp;
sp->smk_default = skp;
+ /*
+ * For a handful of fs types with no user-controlled
+ * backing store it's okay to trust security labels
+ * in the filesystem. The rest are untrusted.
+ */
+ if (sb->s_user_ns != &init_user_ns &&
+ sb->s_magic != SYSFS_MAGIC && sb->s_magic != TMPFS_MAGIC &&
+ sb->s_magic != RAMFS_MAGIC) {
+ transmute = 1;
+ sp->smk_flags |= SMK_SB_UNTRUSTED;
+ }
}
/*
@@ -908,6 +919,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
struct inode *inode = file_inode(bprm->file);
struct task_smack *bsp = bprm->cred->security;
struct inode_smack *isp;
+ struct superblock_smack *sbsp;
int rc;
if (bprm->cred_prepared)
@@ -917,6 +929,11 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
return 0;
+ sbsp = inode->i_sb->s_security;
+ if ((sbsp->smk_flags & SMK_SB_UNTRUSTED) &&
+ isp->smk_task != sbsp->smk_root)
+ return 0;
+
if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
struct task_struct *tracer;
rc = 0;
@@ -1203,6 +1220,7 @@ static int smack_inode_rename(struct inode *old_inode,
*/
static int smack_inode_permission(struct inode *inode, int mask)
{
+ struct superblock_smack *sbsp = inode->i_sb->s_security;
struct smk_audit_info ad;
int no_block = mask & MAY_NOT_BLOCK;
int rc;
@@ -1214,6 +1232,11 @@ static int smack_inode_permission(struct inode *inode, int mask)
if (mask == 0)
return 0;
+ if (sbsp->smk_flags & SMK_SB_UNTRUSTED) {
+ if (smk_of_inode(inode) != sbsp->smk_root)
+ return -EACCES;
+ }
+
/* May be droppable after audit */
if (no_block)
return -ECHILD;
@@ -1708,6 +1731,7 @@ static int smack_mmap_file(struct file *file,
struct task_smack *tsp;
struct smack_known *okp;
struct inode_smack *isp;
+ struct superblock_smack *sbsp;
int may;
int mmay;
int tmay;
@@ -1719,6 +1743,10 @@ static int smack_mmap_file(struct file *file,
isp = file_inode(file)->i_security;
if (isp->smk_mmap == NULL)
return 0;
+ sbsp = file_inode(file)->i_sb->s_security;
+ if (sbsp->smk_flags & SMK_SB_UNTRUSTED &&
+ isp->smk_mmap != sbsp->smk_root)
+ return -EACCES;
mkp = isp->smk_mmap;
tsp = current_security();
@@ -1829,14 +1857,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
/* we don't log here as rc can be overriden */
skp = file->f_security;
- rc = smk_access(skp, tkp, MAY_WRITE, NULL);
- rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc);
+ rc = smk_access(skp, tkp, MAY_DELIVER, NULL);
+ rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc);
if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
rc = 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, tsk);
- smack_log(skp->smk_known, tkp->smk_known, MAY_WRITE, rc, &ad);
+ smack_log(skp->smk_known, tkp->smk_known, MAY_DELIVER, rc, &ad);
return rc;
}
@@ -2227,6 +2255,9 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
struct smack_known *tkp = smk_of_task_struct(p);
int rc;
+ if (!sig)
+ return 0; /* null signal; existence test */
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p);
/*
@@ -2234,8 +2265,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* can write the receiver.
*/
if (secid == 0) {
- rc = smk_curacc(tkp, MAY_WRITE, &ad);
- rc = smk_bu_task(p, MAY_WRITE, rc);
+ rc = smk_curacc(tkp, MAY_DELIVER, &ad);
+ rc = smk_bu_task(p, MAY_DELIVER, rc);
return rc;
}
/*
@@ -2244,8 +2275,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* we can't take privilege into account.
*/
skp = smack_from_secid(secid);
- rc = smk_access(skp, tkp, MAY_WRITE, &ad);
- rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc);
+ rc = smk_access(skp, tkp, MAY_DELIVER, &ad);
+ rc = smk_bu_note("USB signal", skp, tkp, MAY_DELIVER, rc);
return rc;
}
@@ -3514,7 +3545,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
if (isp->smk_flags & SMK_INODE_CHANGED) {
isp->smk_flags &= ~SMK_INODE_CHANGED;
- rc = inode->i_op->setxattr(dp,
+ rc = inode->i_op->setxattr(dp, inode,
XATTR_NAME_SMACKTRANSMUTE,
TRANS_TRUE, TRANS_TRUE_SIZE,
0);
@@ -3992,7 +4023,7 @@ access_check:
rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
MAY_WRITE, rc);
if (rc != 0)
- netlbl_skbuff_err(skb, rc, 0);
+ netlbl_skbuff_err(skb, sk->sk_family, rc, 0);
break;
#if IS_ENABLED(CONFIG_IPV6)
case PF_INET6:
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index aa6bf1b22ec5..205b785fb400 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -20,7 +20,7 @@
#include <net/inet_sock.h>
#include "smack.h"
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
static unsigned int smack_ipv6_output(void *priv,
struct sk_buff *skb,
@@ -64,7 +64,7 @@ static struct nf_hook_ops smack_nf_ops[] = {
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_SELINUX_FIRST,
},
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
{
.hook = smack_ipv6_output,
.pf = NFPROTO_IPV6,
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index e249a66db533..6492fe96cae4 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -2523,14 +2523,9 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
if (count == 0 || count > SMK_LONGLABEL)
return -EINVAL;
- data = kzalloc(count, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- rc = -EFAULT;
- goto out_data;
- }
+ data = memdup_user(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
cp = smk_parse_smack(data, count);
if (IS_ERR(cp)) {