Commit e6e29a4e authored by James Morris's avatar James Morris

Merge branch 'smack-for-4.2-stacked' of https://github.com/cschaufler/smack-next into next

parents 8d94eb9b c0d77c88
...@@ -206,11 +206,11 @@ netlabel ...@@ -206,11 +206,11 @@ netlabel
label. The format accepted on write is: label. The format accepted on write is:
"%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label".
onlycap onlycap
This contains the label processes must have for CAP_MAC_ADMIN This contains labels processes must have for CAP_MAC_ADMIN
and CAP_MAC_OVERRIDE to be effective. If this file is empty and CAP_MAC_OVERRIDE to be effective. If this file is empty
these capabilities are effective at for processes with any these capabilities are effective at for processes with any
label. The value is set by writing the desired label to the label. The values are set by writing the desired labels, separated
file or cleared by writing "-" to the file. by spaces, to the file or cleared by writing "-" to the file.
ptrace ptrace
This is used to define the current ptrace policy This is used to define the current ptrace policy
0 - default: this is the policy that relies on Smack access rules. 0 - default: this is the policy that relies on Smack access rules.
......
...@@ -138,6 +138,11 @@ struct smk_port_label { ...@@ -138,6 +138,11 @@ struct smk_port_label {
struct smack_known *smk_out; /* outgoing label */ struct smack_known *smk_out; /* outgoing label */
}; };
struct smack_onlycap {
struct list_head list;
struct smack_known *smk_label;
};
/* /*
* Mount options * Mount options
*/ */
...@@ -249,6 +254,7 @@ int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); ...@@ -249,6 +254,7 @@ int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
struct smack_known *smk_import_entry(const char *, int); struct smack_known *smk_import_entry(const char *, int);
void smk_insert_entry(struct smack_known *skp); void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *); struct smack_known *smk_find_entry(const char *);
int smack_privileged(int cap);
/* /*
* Shared data. * Shared data.
...@@ -257,7 +263,6 @@ extern int smack_enabled; ...@@ -257,7 +263,6 @@ extern int smack_enabled;
extern int smack_cipso_direct; extern int smack_cipso_direct;
extern int smack_cipso_mapped; extern int smack_cipso_mapped;
extern struct smack_known *smack_net_ambient; extern struct smack_known *smack_net_ambient;
extern struct smack_known *smack_onlycap;
extern struct smack_known *smack_syslog_label; extern struct smack_known *smack_syslog_label;
#ifdef CONFIG_SECURITY_SMACK_BRINGUP #ifdef CONFIG_SECURITY_SMACK_BRINGUP
extern struct smack_known *smack_unconfined; extern struct smack_known *smack_unconfined;
...@@ -276,6 +281,9 @@ extern struct mutex smack_known_lock; ...@@ -276,6 +281,9 @@ extern struct mutex smack_known_lock;
extern struct list_head smack_known_list; extern struct list_head smack_known_list;
extern struct list_head smk_netlbladdr_list; extern struct list_head smk_netlbladdr_list;
extern struct mutex smack_onlycap_lock;
extern struct list_head smack_onlycap_list;
#define SMACK_HASH_SLOTS 16 #define SMACK_HASH_SLOTS 16
extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
...@@ -331,21 +339,6 @@ static inline struct smack_known *smk_of_current(void) ...@@ -331,21 +339,6 @@ static inline struct smack_known *smk_of_current(void)
return smk_of_task(current_security()); return smk_of_task(current_security());
} }
/*
* Is the task privileged and allowed to be privileged
* by the onlycap rule.
*/
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 == skp)
return 1;
return 0;
}
/* /*
* logging functions * logging functions
*/ */
......
...@@ -425,7 +425,7 @@ void smk_insert_entry(struct smack_known *skp) ...@@ -425,7 +425,7 @@ void smk_insert_entry(struct smack_known *skp)
* @string: a text string that might be a Smack label * @string: a text string that might be a Smack label
* *
* Returns a pointer to the entry in the label list that * Returns a pointer to the entry in the label list that
* matches the passed string. * matches the passed string or NULL if not found.
*/ */
struct smack_known *smk_find_entry(const char *string) struct smack_known *smk_find_entry(const char *string)
{ {
...@@ -448,7 +448,7 @@ struct smack_known *smk_find_entry(const char *string) ...@@ -448,7 +448,7 @@ struct smack_known *smk_find_entry(const char *string)
* @string: a text string that might contain a Smack label * @string: a text string that might contain a Smack label
* @len: the maximum size, or zero if it is NULL terminated. * @len: the maximum size, or zero if it is NULL terminated.
* *
* Returns a pointer to the clean label, or NULL * Returns a pointer to the clean label or an error code.
*/ */
char *smk_parse_smack(const char *string, int len) char *smk_parse_smack(const char *string, int len)
{ {
...@@ -464,7 +464,7 @@ char *smk_parse_smack(const char *string, int len) ...@@ -464,7 +464,7 @@ char *smk_parse_smack(const char *string, int len)
* including /smack/cipso and /smack/cipso2 * including /smack/cipso and /smack/cipso2
*/ */
if (string[0] == '-') if (string[0] == '-')
return NULL; return ERR_PTR(-EINVAL);
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
...@@ -472,10 +472,12 @@ char *smk_parse_smack(const char *string, int len) ...@@ -472,10 +472,12 @@ char *smk_parse_smack(const char *string, int len)
break; break;
if (i == 0 || i >= SMK_LONGLABEL) if (i == 0 || i >= SMK_LONGLABEL)
return NULL; return ERR_PTR(-EINVAL);
smack = kzalloc(i + 1, GFP_KERNEL); smack = kzalloc(i + 1, GFP_KERNEL);
if (smack != NULL) if (smack == NULL)
return ERR_PTR(-ENOMEM);
strncpy(smack, string, i); strncpy(smack, string, i);
return smack; return smack;
...@@ -523,7 +525,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, ...@@ -523,7 +525,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
* @len: the maximum size, or zero if it is NULL terminated. * @len: the maximum size, or zero if it is NULL terminated.
* *
* Returns a pointer to the entry in the label list that * Returns a pointer to the entry in the label list that
* matches the passed string, adding it if necessary. * matches the passed string, adding it if necessary,
* or an error code.
*/ */
struct smack_known *smk_import_entry(const char *string, int len) struct smack_known *smk_import_entry(const char *string, int len)
{ {
...@@ -533,8 +536,8 @@ struct smack_known *smk_import_entry(const char *string, int len) ...@@ -533,8 +536,8 @@ struct smack_known *smk_import_entry(const char *string, int len)
int rc; int rc;
smack = smk_parse_smack(string, len); smack = smk_parse_smack(string, len);
if (smack == NULL) if (IS_ERR(smack))
return NULL; return ERR_CAST(smack);
mutex_lock(&smack_known_lock); mutex_lock(&smack_known_lock);
...@@ -543,8 +546,10 @@ struct smack_known *smk_import_entry(const char *string, int len) ...@@ -543,8 +546,10 @@ struct smack_known *smk_import_entry(const char *string, int len)
goto freeout; goto freeout;
skp = kzalloc(sizeof(*skp), GFP_KERNEL); skp = kzalloc(sizeof(*skp), GFP_KERNEL);
if (skp == NULL) if (skp == NULL) {
skp = ERR_PTR(-ENOMEM);
goto freeout; goto freeout;
}
skp->smk_known = smack; skp->smk_known = smack;
skp->smk_secid = smack_next_secid++; skp->smk_secid = smack_next_secid++;
...@@ -577,7 +582,7 @@ struct smack_known *smk_import_entry(const char *string, int len) ...@@ -577,7 +582,7 @@ struct smack_known *smk_import_entry(const char *string, int len)
* smk_netlbl_mls failed. * smk_netlbl_mls failed.
*/ */
kfree(skp); kfree(skp);
skp = NULL; skp = ERR_PTR(rc);
freeout: freeout:
kfree(smack); kfree(smack);
unlockout: unlockout:
...@@ -612,3 +617,44 @@ struct smack_known *smack_from_secid(const u32 secid) ...@@ -612,3 +617,44 @@ struct smack_known *smack_from_secid(const u32 secid)
rcu_read_unlock(); rcu_read_unlock();
return &smack_known_invalid; return &smack_known_invalid;
} }
/*
* Unless a process is running with one of these labels
* even having CAP_MAC_OVERRIDE isn't enough to grant
* privilege to violate MAC policy. If no labels are
* designated (the empty list case) capabilities apply to
* everyone.
*/
LIST_HEAD(smack_onlycap_list);
DEFINE_MUTEX(smack_onlycap_lock);
/*
* Is the task privileged and allowed to be privileged
* by the onlycap rule.
*
* Returns 1 if the task is allowed to be privileged, 0 if it's not.
*/
int smack_privileged(int cap)
{
struct smack_known *skp = smk_of_current();
struct smack_onlycap *sop;
if (!capable(cap))
return 0;
rcu_read_lock();
if (list_empty(&smack_onlycap_list)) {
rcu_read_unlock();
return 1;
}
list_for_each_entry_rcu(sop, &smack_onlycap_list, list) {
if (sop->smk_label == skp) {
rcu_read_unlock();
return 1;
}
}
rcu_read_unlock();
return 0;
}
...@@ -245,8 +245,8 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file, ...@@ -245,8 +245,8 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
* @ip: a pointer to the inode * @ip: a pointer to the inode
* @dp: a pointer to the dentry * @dp: a pointer to the dentry
* *
* Returns a pointer to the master list entry for the Smack label * Returns a pointer to the master list entry for the Smack label,
* or NULL if there was no label to fetch. * NULL if there was no label to fetch, or an error code.
*/ */
static struct smack_known *smk_fetch(const char *name, struct inode *ip, static struct smack_known *smk_fetch(const char *name, struct inode *ip,
struct dentry *dp) struct dentry *dp)
...@@ -256,14 +256,18 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip, ...@@ -256,14 +256,18 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
struct smack_known *skp = NULL; struct smack_known *skp = NULL;
if (ip->i_op->getxattr == NULL) if (ip->i_op->getxattr == NULL)
return NULL; return ERR_PTR(-EOPNOTSUPP);
buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL);
if (buffer == NULL) if (buffer == NULL)
return NULL; return ERR_PTR(-ENOMEM);
rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL);
if (rc > 0) if (rc < 0)
skp = ERR_PTR(rc);
else if (rc == 0)
skp = NULL;
else
skp = smk_import_entry(buffer, rc); skp = smk_import_entry(buffer, rc);
kfree(buffer); kfree(buffer);
...@@ -605,42 +609,46 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) ...@@ -605,42 +609,46 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
op += strlen(SMK_FSHAT); op += strlen(SMK_FSHAT);
skp = smk_import_entry(op, 0); skp = smk_import_entry(op, 0);
if (skp != NULL) { if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_hat = skp; sp->smk_hat = skp;
specified = 1; specified = 1;
}
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
op += strlen(SMK_FSFLOOR); op += strlen(SMK_FSFLOOR);
skp = smk_import_entry(op, 0); skp = smk_import_entry(op, 0);
if (skp != NULL) { if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_floor = skp; sp->smk_floor = skp;
specified = 1; specified = 1;
}
} else if (strncmp(op, SMK_FSDEFAULT, } else if (strncmp(op, SMK_FSDEFAULT,
strlen(SMK_FSDEFAULT)) == 0) { strlen(SMK_FSDEFAULT)) == 0) {
op += strlen(SMK_FSDEFAULT); op += strlen(SMK_FSDEFAULT);
skp = smk_import_entry(op, 0); skp = smk_import_entry(op, 0);
if (skp != NULL) { if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_default = skp; sp->smk_default = skp;
specified = 1; specified = 1;
}
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
op += strlen(SMK_FSROOT); op += strlen(SMK_FSROOT);
skp = smk_import_entry(op, 0); skp = smk_import_entry(op, 0);
if (skp != NULL) { if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_root = skp; sp->smk_root = skp;
specified = 1; specified = 1;
}
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
op += strlen(SMK_FSTRANS); op += strlen(SMK_FSTRANS);
skp = smk_import_entry(op, 0); skp = smk_import_entry(op, 0);
if (skp != NULL) { if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_root = skp; sp->smk_root = skp;
transmute = 1; transmute = 1;
specified = 1; specified = 1;
} }
} }
}
if (!smack_privileged(CAP_MAC_ADMIN)) { if (!smack_privileged(CAP_MAC_ADMIN)) {
/* /*
...@@ -1118,7 +1126,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -1118,7 +1126,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
if (rc == 0 && check_import) { if (rc == 0 && check_import) {
skp = size ? smk_import_entry(value, size) : NULL; skp = size ? smk_import_entry(value, size) : NULL;
if (skp == NULL || (check_star && if (IS_ERR(skp))
rc = PTR_ERR(skp);
else if (skp == NULL || (check_star &&
(skp == &smack_known_star || skp == &smack_known_web))) (skp == &smack_known_star || skp == &smack_known_web)))
rc = -EINVAL; rc = -EINVAL;
} }
...@@ -1158,19 +1168,19 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, ...@@ -1158,19 +1168,19 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
if (strcmp(name, XATTR_NAME_SMACK) == 0) { if (strcmp(name, XATTR_NAME_SMACK) == 0) {
skp = smk_import_entry(value, size); skp = smk_import_entry(value, size);
if (skp != NULL) if (!IS_ERR(skp))
isp->smk_inode = skp; isp->smk_inode = skp;
else else
isp->smk_inode = &smack_known_invalid; isp->smk_inode = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
skp = smk_import_entry(value, size); skp = smk_import_entry(value, size);
if (skp != NULL) if (!IS_ERR(skp))
isp->smk_task = skp; isp->smk_task = skp;
else else
isp->smk_task = &smack_known_invalid; isp->smk_task = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
skp = smk_import_entry(value, size); skp = smk_import_entry(value, size);
if (skp != NULL) if (!IS_ERR(skp))
isp->smk_mmap = skp; isp->smk_mmap = skp;
else else
isp->smk_mmap = &smack_known_invalid; isp->smk_mmap = &smack_known_invalid;
...@@ -1658,6 +1668,9 @@ static int smack_file_receive(struct file *file) ...@@ -1658,6 +1668,9 @@ static int smack_file_receive(struct file *file)
struct smk_audit_info ad; struct smk_audit_info ad;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
if (unlikely(IS_PRIVATE(inode)))
return 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path); smk_ad_setfield_u_fs_path(&ad, file->f_path);
/* /*
...@@ -2400,8 +2413,8 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ...@@ -2400,8 +2413,8 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
return -EINVAL; return -EINVAL;
skp = smk_import_entry(value, size); skp = smk_import_entry(value, size);
if (skp == NULL) if (IS_ERR(skp))
return -EINVAL; return PTR_ERR(skp);
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
nsp->smk_inode = skp; nsp->smk_inode = skp;
...@@ -3174,7 +3187,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) ...@@ -3174,7 +3187,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/ */
dp = dget(opt_dentry); dp = dget(opt_dentry);
skp = smk_fetch(XATTR_NAME_SMACK, inode, dp); skp = smk_fetch(XATTR_NAME_SMACK, inode, dp);
if (skp != NULL) if (!IS_ERR_OR_NULL(skp))
final = skp; final = skp;
/* /*
...@@ -3211,11 +3224,14 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) ...@@ -3211,11 +3224,14 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* Don't let the exec or mmap label be "*" or "@". * Don't let the exec or mmap label be "*" or "@".
*/ */
skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
if (skp == &smack_known_star || skp == &smack_known_web) if (IS_ERR(skp) || skp == &smack_known_star ||
skp == &smack_known_web)
skp = NULL; skp = NULL;
isp->smk_task = skp; isp->smk_task = skp;
skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp);
if (skp == &smack_known_star || skp == &smack_known_web) if (IS_ERR(skp) || skp == &smack_known_star ||
skp == &smack_known_web)
skp = NULL; skp = NULL;
isp->smk_mmap = skp; isp->smk_mmap = skp;
...@@ -3299,8 +3315,8 @@ static int smack_setprocattr(struct task_struct *p, char *name, ...@@ -3299,8 +3315,8 @@ static int smack_setprocattr(struct task_struct *p, char *name,
return -EINVAL; return -EINVAL;
skp = smk_import_entry(value, size); skp = smk_import_entry(value, size);
if (skp == NULL) if (IS_ERR(skp))
return -EINVAL; return PTR_ERR(skp);
/* /*
* No process is ever allowed the web ("@") label. * No process is ever allowed the web ("@") label.
...@@ -4075,7 +4091,9 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) ...@@ -4075,7 +4091,9 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
return -EINVAL; return -EINVAL;
skp = smk_import_entry(rulestr, 0); skp = smk_import_entry(rulestr, 0);
if (skp) if (IS_ERR(skp))
return PTR_ERR(skp);
*rule = skp->smk_known; *rule = skp->smk_known;
return 0; return 0;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment