summaryrefslogtreecommitdiff
path: root/security/smack
diff options
context:
space:
mode:
Diffstat (limited to 'security/smack')
-rw-r--r--security/smack/smack.h110
-rw-r--r--security/smack/smack_access.c43
-rw-r--r--security/smack/smack_lsm.c684
-rw-r--r--security/smack/smackfs.c53
4 files changed, 610 insertions, 280 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 8ad30955e15d..339614c76e63 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -29,6 +29,38 @@
#define SMK_LONGLABEL 256
/*
+ * This is the repository for labels seen so that it is
+ * not necessary to keep allocating tiny chuncks of memory
+ * and so that they can be shared.
+ *
+ * Labels are never modified in place. Anytime a label
+ * is imported (e.g. xattrset on a file) the list is checked
+ * for it and it is added if it doesn't exist. The address
+ * is passed out in either case. Entries are added, but
+ * never deleted.
+ *
+ * Since labels are hanging around anyway it doesn't
+ * hurt to maintain a secid for those awkward situations
+ * where kernel components that ought to use LSM independent
+ * interfaces don't. The secid should go away when all of
+ * these components have been repaired.
+ *
+ * The cipso value associated with the label gets stored here, too.
+ *
+ * Keep the access rules for this subject label here so that
+ * the entire set of rules does not need to be examined every
+ * time.
+ */
+struct smack_known {
+ struct list_head list;
+ char *smk_known;
+ u32 smk_secid;
+ struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */
+ struct list_head smk_rules; /* access rules */
+ struct mutex smk_rules_lock; /* lock for rules */
+};
+
+/*
* Maximum number of bytes for the levels in a CIPSO IP option.
* Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
* bigger than can be used, and 24 is the next lower multiple
@@ -46,25 +78,25 @@ struct superblock_smack {
};
struct socket_smack {
- char *smk_out; /* outbound label */
- char *smk_in; /* inbound label */
- char *smk_packet; /* TCP peer label */
+ struct smack_known *smk_out; /* outbound label */
+ char *smk_in; /* inbound label */
+ char *smk_packet; /* TCP peer label */
};
/*
* Inode smack data
*/
struct inode_smack {
- char *smk_inode; /* label of the fso */
- char *smk_task; /* label of the task */
- char *smk_mmap; /* label of the mmap domain */
- struct mutex smk_lock; /* initialization lock */
- int smk_flags; /* smack inode flags */
+ char *smk_inode; /* label of the fso */
+ struct smack_known *smk_task; /* label of the task */
+ struct smack_known *smk_mmap; /* label of the mmap domain */
+ struct mutex smk_lock; /* initialization lock */
+ int smk_flags; /* smack inode flags */
};
struct task_smack {
- char *smk_task; /* label for access control */
- char *smk_forked; /* label when forked */
+ struct smack_known *smk_task; /* label for access control */
+ struct smack_known *smk_forked; /* label when forked */
struct list_head smk_rules; /* per task access rules */
struct mutex smk_rules_lock; /* lock for the rules */
};
@@ -78,7 +110,7 @@ struct task_smack {
*/
struct smack_rule {
struct list_head list;
- char *smk_subject;
+ struct smack_known *smk_subject;
char *smk_object;
int smk_access;
};
@@ -94,35 +126,14 @@ struct smk_netlbladdr {
};
/*
- * This is the repository for labels seen so that it is
- * not necessary to keep allocating tiny chuncks of memory
- * and so that they can be shared.
- *
- * Labels are never modified in place. Anytime a label
- * is imported (e.g. xattrset on a file) the list is checked
- * for it and it is added if it doesn't exist. The address
- * is passed out in either case. Entries are added, but
- * never deleted.
- *
- * Since labels are hanging around anyway it doesn't
- * hurt to maintain a secid for those awkward situations
- * where kernel components that ought to use LSM independent
- * interfaces don't. The secid should go away when all of
- * these components have been repaired.
- *
- * The cipso value associated with the label gets stored here, too.
- *
- * Keep the access rules for this subject label here so that
- * the entire set of rules does not need to be examined every
- * time.
+ * An entry in the table identifying ports.
*/
-struct smack_known {
- struct list_head list;
- char *smk_known;
- u32 smk_secid;
- struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */
- struct list_head smk_rules; /* access rules */
- struct mutex smk_rules_lock; /* lock for rules */
+struct smk_port_label {
+ struct list_head list;
+ struct sock *smk_sock; /* socket initialized on */
+ unsigned short smk_port; /* the port number */
+ char *smk_in; /* incoming label */
+ struct smack_known *smk_out; /* outgoing label */
};
/*
@@ -132,6 +143,7 @@ struct smack_known {
#define SMK_FSFLOOR "smackfsfloor="
#define SMK_FSHAT "smackfshat="
#define SMK_FSROOT "smackfsroot="
+#define SMK_FSTRANS "smackfstransmute="
#define SMACK_CIPSO_OPTION "-CIPSO"
@@ -203,9 +215,9 @@ struct inode_smack *new_inode_smack(char *);
* These functions are in smack_access.c
*/
int smk_access_entry(char *, char *, struct list_head *);
-int smk_access(char *, char *, int, struct smk_audit_info *);
+int smk_access(struct smack_known *, char *, int, struct smk_audit_info *);
int smk_curacc(char *, u32, struct smk_audit_info *);
-char *smack_from_secid(const u32);
+struct smack_known *smack_from_secid(const u32);
char *smk_parse_smack(const char *string, int len);
int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
char *smk_import(const char *, int);
@@ -218,7 +230,7 @@ u32 smack_to_secid(const char *);
*/
extern int smack_cipso_direct;
extern int smack_cipso_mapped;
-extern char *smack_net_ambient;
+extern struct smack_known *smack_net_ambient;
extern char *smack_onlycap;
extern const char *smack_cipso_option;
@@ -254,17 +266,17 @@ static inline char *smk_of_inode(const struct inode *isp)
}
/*
- * Present a pointer to the smack label in an task blob.
+ * Present a pointer to the smack label entry in an task blob.
*/
-static inline char *smk_of_task(const struct task_smack *tsp)
+static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
{
return tsp->smk_task;
}
/*
- * Present a pointer to the forked smack label in an task blob.
+ * Present a pointer to the forked smack label entry in an task blob.
*/
-static inline char *smk_of_forked(const struct task_smack *tsp)
+static inline struct smack_known *smk_of_forked(const struct task_smack *tsp)
{
return tsp->smk_forked;
}
@@ -272,7 +284,7 @@ static inline char *smk_of_forked(const struct task_smack *tsp)
/*
* Present a pointer to the smack label in the current task blob.
*/
-static inline char *smk_of_current(void)
+static inline struct smack_known *smk_of_current(void)
{
return smk_of_task(current_security());
}
@@ -283,9 +295,11 @@ static inline char *smk_of_current(void)
*/
static inline int smack_privileged(int cap)
{
+ struct smack_known *skp = smk_of_current();
+
if (!capable(cap))
return 0;
- if (smack_onlycap == NULL || smack_onlycap == smk_of_current())
+ if (smack_onlycap == NULL || smack_onlycap == skp->smk_known)
return 1;
return 0;
}
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 2e397a88d410..6a0377f38620 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -93,7 +93,7 @@ int smk_access_entry(char *subject_label, char *object_label,
list_for_each_entry_rcu(srp, rule_list, list) {
if (srp->smk_object == object_label &&
- srp->smk_subject == subject_label) {
+ srp->smk_subject->smk_known == subject_label) {
may = srp->smk_access;
break;
}
@@ -104,7 +104,7 @@ int smk_access_entry(char *subject_label, char *object_label,
/**
* smk_access - determine if a subject has a specific access to an object
- * @subject_label: a pointer to the subject's Smack label
+ * @subject_known: a pointer to the subject's Smack label entry
* @object_label: a pointer to the object's Smack label
* @request: the access requested, in "MAY" format
* @a : a pointer to the audit data
@@ -115,10 +115,9 @@ int smk_access_entry(char *subject_label, char *object_label,
*
* Smack labels are shared on smack_list
*/
-int smk_access(char *subject_label, char *object_label, int request,
- struct smk_audit_info *a)
+int smk_access(struct smack_known *subject_known, char *object_label,
+ int request, struct smk_audit_info *a)
{
- struct smack_known *skp;
int may = MAY_NOT;
int rc = 0;
@@ -127,7 +126,7 @@ int smk_access(char *subject_label, char *object_label, int request,
*
* A star subject can't access any object.
*/
- if (subject_label == smack_known_star.smk_known) {
+ if (subject_known == &smack_known_star) {
rc = -EACCES;
goto out_audit;
}
@@ -137,7 +136,7 @@ int smk_access(char *subject_label, char *object_label, int request,
* An internet subject can access any object.
*/
if (object_label == smack_known_web.smk_known ||
- subject_label == smack_known_web.smk_known)
+ subject_known == &smack_known_web)
goto out_audit;
/*
* A star object can be accessed by any subject.
@@ -148,7 +147,7 @@ int smk_access(char *subject_label, char *object_label, int request,
* An object can be accessed in any way by a subject
* with the same label.
*/
- if (subject_label == object_label)
+ if (subject_known->smk_known == object_label)
goto out_audit;
/*
* A hat subject can read any object.
@@ -157,7 +156,7 @@ int smk_access(char *subject_label, char *object_label, int request,
if ((request & MAY_ANYREAD) == request) {
if (object_label == smack_known_floor.smk_known)
goto out_audit;
- if (subject_label == smack_known_hat.smk_known)
+ if (subject_known == &smack_known_hat)
goto out_audit;
}
/*
@@ -167,9 +166,9 @@ int smk_access(char *subject_label, char *object_label, int request,
* good. A negative response from smk_access_entry()
* indicates there is no entry for this pair.
*/
- skp = smk_find_entry(subject_label);
rcu_read_lock();
- may = smk_access_entry(subject_label, object_label, &skp->smk_rules);
+ may = smk_access_entry(subject_known->smk_known, object_label,
+ &subject_known->smk_rules);
rcu_read_unlock();
if (may > 0 && (request & may) == request)
@@ -179,7 +178,8 @@ int smk_access(char *subject_label, char *object_label, int request,
out_audit:
#ifdef CONFIG_AUDIT
if (a)
- smack_log(subject_label, object_label, request, rc, a);
+ smack_log(subject_known->smk_known, object_label, request,
+ rc, a);
#endif
return rc;
}
@@ -198,20 +198,21 @@ out_audit:
int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
{
struct task_smack *tsp = current_security();
- char *sp = smk_of_task(tsp);
+ struct smack_known *skp = smk_of_task(tsp);
int may;
int rc;
/*
* Check the global rule list
*/
- rc = smk_access(sp, obj_label, mode, NULL);
+ rc = smk_access(skp, obj_label, mode, NULL);
if (rc == 0) {
/*
* If there is an entry in the task's rule list
* it can further restrict access.
*/
- may = smk_access_entry(sp, obj_label, &tsp->smk_rules);
+ may = smk_access_entry(skp->smk_known, obj_label,
+ &tsp->smk_rules);
if (may < 0)
goto out_audit;
if ((mode & may) == mode)
@@ -228,7 +229,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
out_audit:
#ifdef CONFIG_AUDIT
if (a)
- smack_log(sp, obj_label, mode, rc, a);
+ smack_log(skp->smk_known, obj_label, mode, rc, a);
#endif
return rc;
}
@@ -402,6 +403,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
sap->flags |= NETLBL_SECATTR_MLS_CAT;
sap->attr.mls.lvl = level;
sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+ if (!sap->attr.mls.cat)
+ return -ENOMEM;
sap->attr.mls.cat->startbit = 0;
for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
@@ -513,10 +516,10 @@ char *smk_import(const char *string, int len)
* smack_from_secid - find the Smack label associated with a secid
* @secid: an integer that might be associated with a Smack label
*
- * Returns a pointer to the appropriate Smack label if there is one,
+ * Returns a pointer to the appropriate Smack label entry if there is one,
* otherwise a pointer to the invalid Smack label.
*/
-char *smack_from_secid(const u32 secid)
+struct smack_known *smack_from_secid(const u32 secid)
{
struct smack_known *skp;
@@ -524,7 +527,7 @@ char *smack_from_secid(const u32 secid)
list_for_each_entry_rcu(skp, &smack_known_list, list) {
if (skp->smk_secid == secid) {
rcu_read_unlock();
- return skp->smk_known;
+ return skp;
}
}
@@ -533,7 +536,7 @@ char *smack_from_secid(const u32 secid)
* of a secid that is not on the list.
*/
rcu_read_unlock();
- return smack_known_invalid.smk_known;
+ return &smack_known_invalid;
}
/**
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index d52c780bdb78..6a083303501d 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -27,10 +27,13 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
+#include <linux/dccp.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/pipe_fs_i.h>
#include <net/cipso_ipv4.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
#include <linux/audit.h>
#include <linux/magic.h>
#include <linux/dcache.h>
@@ -45,6 +48,12 @@
#define TRANS_TRUE "TRUE"
#define TRANS_TRUE_SIZE 4
+#define SMK_CONNECTING 0
+#define SMK_RECEIVING 1
+#define SMK_SENDING 2
+
+LIST_HEAD(smk_ipv6_port_list);
+
/**
* smk_fetch - Fetch the smack label from a file.
* @ip: a pointer to the inode
@@ -53,11 +62,12 @@
* Returns a pointer to the master list entry for the Smack label
* or NULL if there was no label to fetch.
*/
-static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
+static struct smack_known *smk_fetch(const char *name, struct inode *ip,
+ struct dentry *dp)
{
int rc;
char *buffer;
- char *result = NULL;
+ struct smack_known *skp = NULL;
if (ip->i_op->getxattr == NULL)
return NULL;
@@ -68,11 +78,11 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL);
if (rc > 0)
- result = smk_import(buffer, rc);
+ skp = smk_import_entry(buffer, rc);
kfree(buffer);
- return result;
+ return skp;
}
/**
@@ -102,7 +112,8 @@ struct inode_smack *new_inode_smack(char *smack)
*
* Returns the new blob or NULL if there's no memory available
*/
-static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp)
+static struct task_smack *new_task_smack(struct smack_known *task,
+ struct smack_known *forked, gfp_t gfp)
{
struct task_smack *tsp;
@@ -164,17 +175,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
int rc;
struct smk_audit_info ad;
- char *tsp;
+ struct smack_known *skp;
rc = cap_ptrace_access_check(ctp, mode);
if (rc != 0)
return rc;
- tsp = smk_of_task(task_security(ctp));
+ skp = smk_of_task(task_security(ctp));
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, ctp);
- rc = smk_curacc(tsp, MAY_READWRITE, &ad);
+ rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad);
return rc;
}
@@ -190,17 +201,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
{
int rc;
struct smk_audit_info ad;
- char *tsp;
+ struct smack_known *skp;
rc = cap_ptrace_traceme(ptp);
if (rc != 0)
return rc;
- tsp = smk_of_task(task_security(ptp));
+ skp = smk_of_task(task_security(ptp));
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, ptp);
- rc = smk_curacc(tsp, MAY_READWRITE, &ad);
+ rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad);
return rc;
}
@@ -215,12 +226,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
static int smack_syslog(int typefrom_file)
{
int rc = 0;
- char *sp = smk_of_current();
+ struct smack_known *skp = smk_of_current();
if (smack_privileged(CAP_MAC_OVERRIDE))
return 0;
- if (sp != smack_known_floor.smk_known)
+ if (skp != &smack_known_floor)
rc = -EACCES;
return rc;
@@ -250,8 +261,9 @@ static int smack_sb_alloc_security(struct super_block *sb)
sbsp->smk_default = smack_known_floor.smk_known;
sbsp->smk_floor = smack_known_floor.smk_known;
sbsp->smk_hat = smack_known_hat.smk_known;
- sbsp->smk_initialized = 0;
-
+ /*
+ * smk_initialized will be zero from kzalloc.
+ */
sb->s_security = sbsp;
return 0;
@@ -295,6 +307,8 @@ static int smack_sb_copy_data(char *orig, char *smackopts)
dp = smackopts;
else if (strstr(cp, SMK_FSROOT) == cp)
dp = smackopts;
+ else if (strstr(cp, SMK_FSTRANS) == cp)
+ dp = smackopts;
else
dp = otheropts;
@@ -330,8 +344,9 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
char *op;
char *commap;
char *nsp;
+ int transmute = 0;
- if (sp->smk_initialized != 0)
+ if (sp->smk_initialized)
return 0;
sp->smk_initialized = 1;
@@ -362,6 +377,13 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
nsp = smk_import(op, 0);
if (nsp != NULL)
sp->smk_root = nsp;
+ } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
+ op += strlen(SMK_FSTRANS);
+ nsp = smk_import(op, 0);
+ if (nsp != NULL) {
+ sp->smk_root = nsp;
+ transmute = 1;
+ }
}
}
@@ -369,11 +391,15 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
* Initialize the root inode.
*/
isp = inode->i_security;
- if (isp == NULL)
+ if (inode->i_security == NULL) {
inode->i_security = new_inode_smack(sp->smk_root);
- else
+ isp = inode->i_security;
+ } else
isp->smk_inode = sp->smk_root;
+ if (transmute)
+ isp->smk_flags |= SMK_INODE_TRANSMUTE;
+
return 0;
}
@@ -524,7 +550,9 @@ static int smack_bprm_secureexec(struct linux_binprm *bprm)
*/
static int smack_inode_alloc_security(struct inode *inode)
{
- inode->i_security = new_inode_smack(smk_of_current());
+ struct smack_known *skp = smk_of_current();
+
+ inode->i_security = new_inode_smack(skp->smk_known);
if (inode->i_security == NULL)
return -ENOMEM;
return 0;
@@ -557,9 +585,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, char **name,
void **value, size_t *len)
{
- struct smack_known *skp;
struct inode_smack *issp = inode->i_security;
- char *csp = smk_of_current();
+ struct smack_known *skp = smk_of_current();
char *isp = smk_of_inode(inode);
char *dsp = smk_of_inode(dir);
int may;
@@ -571,9 +598,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
}
if (value) {
- skp = smk_find_entry(csp);
rcu_read_lock();
- may = smk_access_entry(csp, dsp, &skp->smk_rules);
+ may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules);
rcu_read_unlock();
/*
@@ -862,29 +888,31 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
- char *nsp;
+ struct smack_known *skp;
struct inode_smack *isp = dentry->d_inode->i_security;
+ if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
+ isp->smk_flags |= SMK_INODE_TRANSMUTE;
+ return;
+ }
+
+ skp = smk_import_entry(value, size);
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
- nsp = smk_import(value, size);
- if (nsp != NULL)
- isp->smk_inode = nsp;
+ if (skp != NULL)
+ isp->smk_inode = skp->smk_known;
else
isp->smk_inode = smack_known_invalid.smk_known;
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
- nsp = smk_import(value, size);
- if (nsp != NULL)
- isp->smk_task = nsp;
+ if (skp != NULL)
+ isp->smk_task = skp;
else
- isp->smk_task = smack_known_invalid.smk_known;
+ isp->smk_task = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
- nsp = smk_import(value, size);
- if (nsp != NULL)
- isp->smk_mmap = nsp;
+ if (skp != NULL)
+ isp->smk_mmap = skp;
else
- isp->smk_mmap = smack_known_invalid.smk_known;
- } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
- isp->smk_flags |= SMK_INODE_TRANSMUTE;
+ isp->smk_mmap = &smack_known_invalid;
+ }
return;
}
@@ -990,7 +1018,7 @@ static int smack_inode_getsecurity(const struct inode *inode,
if (strcmp(name, XATTR_SMACK_IPIN) == 0)
isp = ssp->smk_in;
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
- isp = ssp->smk_out;
+ isp = ssp->smk_out->smk_known;
else
return -EOPNOTSUPP;
@@ -1070,7 +1098,9 @@ static int smack_file_permission(struct file *file, int mask)
*/
static int smack_file_alloc_security(struct file *file)
{
- file->f_security = smk_of_current();
+ struct smack_known *skp = smk_of_current();
+
+ file->f_security = skp->smk_known;
return 0;
}
@@ -1181,10 +1211,9 @@ static int smack_mmap_file(struct file *file,
unsigned long flags)
{
struct smack_known *skp;
+ struct smack_known *mkp;
struct smack_rule *srp;
struct task_smack *tsp;
- char *sp;
- char *msmack;
char *osmack;
struct inode_smack *isp;
int may;
@@ -1198,11 +1227,10 @@ static int smack_mmap_file(struct file *file,
isp = file_inode(file)->i_security;
if (isp->smk_mmap == NULL)
return 0;
- msmack = isp->smk_mmap;
+ mkp = isp->smk_mmap;
tsp = current_security();
- sp = smk_of_current();
- skp = smk_find_entry(sp);
+ skp = smk_of_current();
rc = 0;
rcu_read_lock();
@@ -1216,13 +1244,13 @@ static int smack_mmap_file(struct file *file,
/*
* Matching labels always allows access.
*/
- if (msmack == osmack)
+ if (mkp->smk_known == osmack)
continue;
/*
* If there is a matching local rule take
* that into account as well.
*/
- may = smk_access_entry(srp->smk_subject, osmack,
+ may = smk_access_entry(srp->smk_subject->smk_known, osmack,
&tsp->smk_rules);
if (may == -ENOENT)
may = srp->smk_access;
@@ -1240,8 +1268,8 @@ static int smack_mmap_file(struct file *file,
* If there isn't one a SMACK64MMAP subject
* can't have as much access as current.
*/
- skp = smk_find_entry(msmack);
- mmay = smk_access_entry(msmack, osmack, &skp->smk_rules);
+ mmay = smk_access_entry(mkp->smk_known, osmack,
+ &mkp->smk_rules);
if (mmay == -ENOENT) {
rc = -EACCES;
break;
@@ -1250,7 +1278,8 @@ static int smack_mmap_file(struct file *file,
* If there is a local entry it modifies the
* potential access, too.
*/
- tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules);
+ tmay = smk_access_entry(mkp->smk_known, osmack,
+ &tsp->smk_rules);
if (tmay != -ENOENT)
mmay &= tmay;
@@ -1279,7 +1308,9 @@ static int smack_mmap_file(struct file *file,
*/
static int smack_file_set_fowner(struct file *file)
{
- file->f_security = smk_of_current();
+ struct smack_known *skp = smk_of_current();
+
+ file->f_security = skp->smk_known;
return 0;
}
@@ -1297,9 +1328,10 @@ static int smack_file_set_fowner(struct file *file)
static int smack_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
+ struct smack_known *skp;
+ struct smack_known *tkp = smk_of_task(tsk->cred->security);
struct file *file;
int rc;
- char *tsp = smk_of_task(tsk->cred->security);
struct smk_audit_info ad;
/*
@@ -1308,13 +1340,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
file = container_of(fown, struct file, f_owner);
/* we don't log here as rc can be overriden */
- rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL);
+ skp = smk_find_entry(file->f_security);
+ rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL);
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(file->f_security, tsp, MAY_WRITE, rc, &ad);
+ smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad);
return rc;
}
@@ -1469,12 +1502,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
static int smack_kernel_act_as(struct cred *new, u32 secid)
{
struct task_smack *new_tsp = new->security;
- char *smack = smack_from_secid(secid);
+ struct smack_known *skp = smack_from_secid(secid);
- if (smack == NULL)
+ if (skp == NULL)
return -EINVAL;
- new_tsp->smk_task = smack;
+ new_tsp->smk_task = skp;
return 0;
}
@@ -1492,8 +1525,8 @@ static int smack_kernel_create_files_as(struct cred *new,
struct inode_smack *isp = inode->i_security;
struct task_smack *tsp = new->security;
- tsp->smk_forked = isp->smk_inode;
- tsp->smk_task = isp->smk_inode;
+ tsp->smk_forked = smk_find_entry(isp->smk_inode);
+ tsp->smk_task = tsp->smk_forked;
return 0;
}
@@ -1509,10 +1542,11 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
const char *caller)
{
struct smk_audit_info ad;
+ struct smack_known *skp = smk_of_task(task_security(p));
smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p);
- return smk_curacc(smk_of_task(task_security(p)), access, &ad);
+ return smk_curacc(skp->smk_known, access, &ad);
}
/**
@@ -1558,7 +1592,9 @@ static int smack_task_getsid(struct task_struct *p)
*/
static void smack_task_getsecid(struct task_struct *p, u32 *secid)
{
- *secid = smack_to_secid(smk_of_task(task_security(p)));
+ struct smack_known *skp = smk_of_task(task_security(p));
+
+ *secid = skp->smk_secid;
}
/**
@@ -1662,6 +1698,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
int sig, u32 secid)
{
struct smk_audit_info ad;
+ struct smack_known *skp;
+ struct smack_known *tkp = smk_of_task(task_security(p));
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p);
@@ -1670,15 +1708,14 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* can write the receiver.
*/
if (secid == 0)
- return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE,
- &ad);
+ return smk_curacc(tkp->smk_known, MAY_WRITE, &ad);
/*
* If the secid isn't 0 we're dealing with some USB IO
* specific behavior. This is not clean. For one thing
* we can't take privilege into account.
*/
- return smk_access(smack_from_secid(secid),
- smk_of_task(task_security(p)), MAY_WRITE, &ad);
+ skp = smack_from_secid(secid);
+ return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad);
}
/**
@@ -1710,7 +1747,9 @@ static int smack_task_wait(struct task_struct *p)
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
{
struct inode_smack *isp = inode->i_security;
- isp->smk_inode = smk_of_task(task_security(p));
+ struct smack_known *skp = smk_of_task(task_security(p));
+
+ isp->smk_inode = skp->smk_known;
}
/*
@@ -1729,15 +1768,15 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
*/
static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
{
- char *csp = smk_of_current();
+ struct smack_known *skp = smk_of_current();
struct socket_smack *ssp;
ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
if (ssp == NULL)
return -ENOMEM;
- ssp->smk_in = csp;
- ssp->smk_out = csp;
+ ssp->smk_in = skp->smk_known;
+ ssp->smk_out = skp;
ssp->smk_packet = NULL;
sk->sk_security = ssp;
@@ -1824,7 +1863,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
labeled == SMACK_UNLABELED_SOCKET)
netlbl_sock_delattr(sk);
else {
- skp = smk_find_entry(ssp->smk_out);
+ skp = ssp->smk_out;
rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel);
}
@@ -1847,6 +1886,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
*/
static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
{
+ struct smack_known *skp;
int rc;
int sk_lbl;
char *hostsp;
@@ -1865,7 +1905,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr;
#endif
sk_lbl = SMACK_UNLABELED_SOCKET;
- rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad);
+ skp = ssp->smk_out;
+ rc = smk_access(skp, hostsp, MAY_WRITE, &ad);
} else {
sk_lbl = SMACK_CIPSO_SOCKET;
rc = 0;
@@ -1878,6 +1919,155 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
}
/**
+ * smk_ipv6_port_label - Smack port access table management
+ * @sock: socket
+ * @address: address
+ *
+ * Create or update the port list entry
+ */
+static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_in6 *addr6;
+ struct socket_smack *ssp = sock->sk->sk_security;
+ struct smk_port_label *spp;
+ unsigned short port = 0;
+
+ if (address == NULL) {
+ /*
+ * This operation is changing the Smack information
+ * on the bound socket. Take the changes to the port
+ * as well.
+ */
+ list_for_each_entry(spp, &smk_ipv6_port_list, list) {
+ if (sk != spp->smk_sock)
+ continue;
+ spp->smk_in = ssp->smk_in;
+ spp->smk_out = ssp->smk_out;
+ return;
+ }
+ /*
+ * A NULL address is only used for updating existing
+ * bound entries. If there isn't one, it's OK.
+ */
+ return;
+ }
+
+ addr6 = (struct sockaddr_in6 *)address;
+ port = ntohs(addr6->sin6_port);
+ /*
+ * This is a special case that is safely ignored.
+ */
+ if (port == 0)
+ return;
+
+ /*
+ * Look for an existing port list entry.
+ * This is an indication that a port is getting reused.
+ */
+ list_for_each_entry(spp, &smk_ipv6_port_list, list) {
+ if (spp->smk_port != port)
+ continue;
+ spp->smk_port = port;
+ spp->smk_sock = sk;
+ spp->smk_in = ssp->smk_in;
+ spp->smk_out = ssp->smk_out;
+ return;
+ }
+
+ /*
+ * A new port entry is required.
+ */
+ spp = kzalloc(sizeof(*spp), GFP_KERNEL);
+ if (spp == NULL)
+ return;
+
+ spp->smk_port = port;
+ spp->smk_sock = sk;
+ spp->smk_in = ssp->smk_in;
+ spp->smk_out = ssp->smk_out;
+
+ list_add(&spp->list, &smk_ipv6_port_list);
+ return;
+}
+
+/**
+ * smk_ipv6_port_check - check Smack port access
+ * @sock: socket
+ * @address: address
+ *
+ * Create or update the port list entry
+ */
+static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address,
+ int act)
+{
+ __be16 *bep;
+ __be32 *be32p;
+ struct sockaddr_in6 *addr6;
+ struct smk_port_label *spp;
+ struct socket_smack *ssp = sk->sk_security;
+ struct smack_known *skp;
+ unsigned short port = 0;
+ char *object;
+ struct smk_audit_info ad;
+#ifdef CONFIG_AUDIT
+ struct lsm_network_audit net;
+#endif
+
+ if (act == SMK_RECEIVING) {
+ skp = smack_net_ambient;
+ object = ssp->smk_in;
+ } else {
+ skp = ssp->smk_out;
+ object = smack_net_ambient->smk_known;
+ }
+
+ /*
+ * Get the IP address and port from the address.
+ */
+ addr6 = (struct sockaddr_in6 *)address;
+ port = ntohs(addr6->sin6_port);
+ bep = (__be16 *)(&addr6->sin6_addr);
+ be32p = (__be32 *)(&addr6->sin6_addr);
+
+ /*
+ * It's remote, so port lookup does no good.
+ */
+ if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1)
+ goto auditout;
+
+ /*
+ * It's local so the send check has to have passed.
+ */
+ if (act == SMK_RECEIVING) {
+ skp = &smack_known_web;
+ goto auditout;
+ }
+
+ list_for_each_entry(spp, &smk_ipv6_port_list, list) {
+ if (spp->smk_port != port)
+ continue;
+ object = spp->smk_in;
+ if (act == SMK_CONNECTING)
+ ssp->smk_packet = spp->smk_out->smk_known;
+ break;
+ }
+
+auditout:
+
+#ifdef CONFIG_AUDIT
+ smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+ ad.a.u.net->family = sk->sk_family;
+ ad.a.u.net->dport = port;
+ if (act == SMK_RECEIVING)
+ ad.a.u.net->v6info.saddr = addr6->sin6_addr;
+ else
+ ad.a.u.net->v6info.daddr = addr6->sin6_addr;
+#endif
+ return smk_access(skp, object, MAY_WRITE, &ad);
+}
+
+/**
* smack_inode_setsecurity - set smack xattrs
* @inode: the object
* @name: attribute name
@@ -1892,7 +2082,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
static int smack_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
- char *sp;
+ struct smack_known *skp;
struct inode_smack *nsp = inode->i_security;
struct socket_smack *ssp;
struct socket *sock;
@@ -1901,12 +2091,12 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
if (value == NULL || size > SMK_LONGLABEL || size == 0)
return -EACCES;
- sp = smk_import(value, size);
- if (sp == NULL)
+ skp = smk_import_entry(value, size);
+ if (skp == NULL)
return -EINVAL;
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
- nsp->smk_inode = sp;
+ nsp->smk_inode = skp->smk_known;
nsp->smk_flags |= SMK_INODE_INSTANT;
return 0;
}
@@ -1923,10