mirror of https://github.com/torvalds/linux.git
Patches for 6.19
-----BEGIN PGP SIGNATURE----- iQJLBAABCAA1FiEEC+9tH1YyUwIQzUIeOKUVfIxDyBEFAmkp4M4XHGNhc2V5QHNj aGF1Zmxlci1jYS5jb20ACgkQOKUVfIxDyBFc+BAAq564RJ19Nj7WxV3juDGYLyWR b2P2w4euHo1PvWng058G3WnCzzS14xj6xShLJL711jbuue40lngBqllP+djHIdGM /Mq4I7BnVSJ4z2svvovebiQLoaCiSHN4Uo/b8cdYRz6scueyOQdJUXZvyLwVb4fY CxzfXbcXzsS8MEZikSqyVrjdEZ8yLKzL+uJEqm9FU/suaTUuMNeXudZaXHv5sa8H wxd5iFQhNe2NYCN0EV8Pz57q36ewvzC6UhZLIM+NlIXorfBFWEq54pYpa9OOnNNW 4S+e4KWcNqcWtjxJbzh80Fyui3xv2/b1S73/0Akcf+yqp1mZjPLKZtmsFn83F9b3 SxXGqHNUIZ79U6f656nDYSYYuXzAKkqzmGC94aj7AjABBXNRejPASXqsLLAtm+KY qwqcM2W6WwG1ILEixj5UpfC7qpsBVPYGf5cOi9iPlZD2+/l7OgPOTxNDAe7M5m+E M30eJCqObdl1Uw7QlHvMG5VQT9XkwJFL93OEOADqvE1GqTphIwMb4vJmGuYe/Sgg xqEWMLA6hKBP/B8eQvA7d02WLvzvegwB7C5RTWv1M+QGyzlNxTwqOv+vecm//IVS A3LzfxjadSYyRm9nNbZrYWqdVpvYhVcxHrLwzJ4jBsPjBSZM9QlbJHaCjs/T9Sg5 pK0p5GsXIr3akV2BIvE= =n/1b -----END PGP SIGNATURE----- Merge tag 'Smack-for-6.19' of https://github.com/cschaufler/smack-next Pull smack updates from Casey Schaufler: - fix several cases where labels were treated inconsistently when imported from user space - clean up the assignment of extended attributes - documentation improvements * tag 'Smack-for-6.19' of https://github.com/cschaufler/smack-next: Smack: function parameter 'gfp' not described smack: fix kernel-doc warnings for smk_import_valid_label() smack: fix bug: setting task label silently ignores input garbage smack: fix bug: unprivileged task can create labels smack: fix bug: invalid label of unix socket file smack: always "instantiate" inode in smack_inode_init_security() smack: deduplicate xattr setting in smack_inode_init_security() smack: fix bug: SMACK64TRANSMUTE set on non-directory smack: deduplicate "does access rule request transmutation"
This commit is contained in:
commit
204a920f28
|
|
@ -601,10 +601,15 @@ specification.
|
||||||
Task Attribute
|
Task Attribute
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The Smack label of a process can be read from /proc/<pid>/attr/current. A
|
The Smack label of a process can be read from ``/proc/<pid>/attr/current``. A
|
||||||
process can read its own Smack label from /proc/self/attr/current. A
|
process can read its own Smack label from ``/proc/self/attr/current``. A
|
||||||
privileged process can change its own Smack label by writing to
|
privileged process can change its own Smack label by writing to
|
||||||
/proc/self/attr/current but not the label of another process.
|
``/proc/self/attr/current`` but not the label of another process.
|
||||||
|
|
||||||
|
Format of writing is : only the label or the label followed by one of the
|
||||||
|
3 trailers: ``\n`` (by common agreement for ``/proc/...`` interfaces),
|
||||||
|
``\0`` (because some applications incorrectly include it),
|
||||||
|
``\n\0`` (because we think some applications may incorrectly include it).
|
||||||
|
|
||||||
File Attribute
|
File Attribute
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
@ -696,6 +701,11 @@ sockets.
|
||||||
A privileged program may set this to match the label of another
|
A privileged program may set this to match the label of another
|
||||||
task with which it hopes to communicate.
|
task with which it hopes to communicate.
|
||||||
|
|
||||||
|
UNIX domain socket (UDS) with a BSD address functions both as a file in a
|
||||||
|
filesystem and as a socket. As a file, it carries the SMACK64 attribute. This
|
||||||
|
attribute is not involved in Smack security enforcement and is immutably
|
||||||
|
assigned the label "*".
|
||||||
|
|
||||||
Smack Netlabel Exceptions
|
Smack Netlabel Exceptions
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -300,9 +300,12 @@ int smk_tskacc(struct task_smack *, struct smack_known *,
|
||||||
int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
|
int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
|
||||||
int smack_str_from_perm(char *string, int access);
|
int smack_str_from_perm(char *string, int access);
|
||||||
struct smack_known *smack_from_secid(const u32);
|
struct smack_known *smack_from_secid(const u32);
|
||||||
|
int smk_parse_label_len(const char *string, int len);
|
||||||
char *smk_parse_smack(const char *string, int len);
|
char *smk_parse_smack(const char *string, int len);
|
||||||
int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
|
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);
|
||||||
|
struct smack_known *smk_import_valid_label(const char *label, int label_len,
|
||||||
|
gfp_t gfp);
|
||||||
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 *);
|
||||||
bool smack_privileged(int cap);
|
bool smack_privileged(int cap);
|
||||||
|
|
|
||||||
|
|
@ -443,19 +443,19 @@ struct smack_known *smk_find_entry(const char *string)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_parse_smack - parse smack label from a text string
|
* smk_parse_label_len - calculate the length of the starting segment
|
||||||
* @string: a text string that might contain a Smack label
|
* in the string that constitutes a valid smack label
|
||||||
* @len: the maximum size, or zero if it is NULL terminated.
|
* @string: a text string that might contain a Smack label at the beginning
|
||||||
|
* @len: the maximum size to look into, may be zero if string is null-terminated
|
||||||
*
|
*
|
||||||
* Returns a pointer to the clean label or an error code.
|
* Returns the length of the segment (0 < L < SMK_LONGLABEL) or an error code.
|
||||||
*/
|
*/
|
||||||
char *smk_parse_smack(const char *string, int len)
|
int smk_parse_label_len(const char *string, int len)
|
||||||
{
|
{
|
||||||
char *smack;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0 || len > SMK_LONGLABEL)
|
||||||
len = strlen(string) + 1;
|
len = SMK_LONGLABEL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reserve a leading '-' as an indicator that
|
* Reserve a leading '-' as an indicator that
|
||||||
|
|
@ -463,7 +463,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 ERR_PTR(-EINVAL);
|
return -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] == '/' ||
|
||||||
|
|
@ -471,6 +471,25 @@ char *smk_parse_smack(const char *string, int len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == 0 || i >= SMK_LONGLABEL)
|
if (i == 0 || i >= SMK_LONGLABEL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_parse_smack - copy the starting segment in the string
|
||||||
|
* that constitutes a valid smack label
|
||||||
|
* @string: a text string that might contain a Smack label at the beginning
|
||||||
|
* @len: the maximum size to look into, may be zero if string is null-terminated
|
||||||
|
*
|
||||||
|
* Returns a pointer to the copy of the label or an error code.
|
||||||
|
*/
|
||||||
|
char *smk_parse_smack(const char *string, int len)
|
||||||
|
{
|
||||||
|
char *smack;
|
||||||
|
int i = smk_parse_label_len(string, len);
|
||||||
|
|
||||||
|
if (i < 0)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
smack = kstrndup(string, i, GFP_NOFS);
|
smack = kstrndup(string, i, GFP_NOFS);
|
||||||
|
|
@ -554,31 +573,26 @@ int smack_populate_secattr(struct smack_known *skp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smk_import_entry - import a label, return the list entry
|
* smk_import_valid_allocated_label - import a label, return the list entry
|
||||||
* @string: a text string that might be a Smack label
|
* @smack: a text string that is a valid Smack label and may be kfree()ed.
|
||||||
* @len: the maximum size, or zero if it is NULL terminated.
|
* It is consumed: either becomes a part of the entry or kfree'ed.
|
||||||
|
* @gfp: Allocation type
|
||||||
*
|
*
|
||||||
* Returns a pointer to the entry in the label list that
|
* Returns: see description of smk_import_entry()
|
||||||
* matches the passed string, adding it if necessary,
|
|
||||||
* or an error code.
|
|
||||||
*/
|
*/
|
||||||
struct smack_known *smk_import_entry(const char *string, int len)
|
static struct smack_known *
|
||||||
|
smk_import_allocated_label(char *smack, gfp_t gfp)
|
||||||
{
|
{
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
char *smack;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
smack = smk_parse_smack(string, len);
|
|
||||||
if (IS_ERR(smack))
|
|
||||||
return ERR_CAST(smack);
|
|
||||||
|
|
||||||
mutex_lock(&smack_known_lock);
|
mutex_lock(&smack_known_lock);
|
||||||
|
|
||||||
skp = smk_find_entry(smack);
|
skp = smk_find_entry(smack);
|
||||||
if (skp != NULL)
|
if (skp != NULL)
|
||||||
goto freeout;
|
goto freeout;
|
||||||
|
|
||||||
skp = kzalloc(sizeof(*skp), GFP_NOFS);
|
skp = kzalloc(sizeof(*skp), gfp);
|
||||||
if (skp == NULL) {
|
if (skp == NULL) {
|
||||||
skp = ERR_PTR(-ENOMEM);
|
skp = ERR_PTR(-ENOMEM);
|
||||||
goto freeout;
|
goto freeout;
|
||||||
|
|
@ -608,6 +622,44 @@ struct smack_known *smk_import_entry(const char *string, int len)
|
||||||
return skp;
|
return skp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_import_entry - import a label, return the list entry
|
||||||
|
* @string: a text string that might contain a Smack label at the beginning
|
||||||
|
* @len: the maximum size to look into, may be zero if string is null-terminated
|
||||||
|
*
|
||||||
|
* Returns a pointer to the entry in the label list that
|
||||||
|
* matches the passed string, adding it if necessary,
|
||||||
|
* or an error code.
|
||||||
|
*/
|
||||||
|
struct smack_known *smk_import_entry(const char *string, int len)
|
||||||
|
{
|
||||||
|
char *smack = smk_parse_smack(string, len);
|
||||||
|
|
||||||
|
if (IS_ERR(smack))
|
||||||
|
return ERR_CAST(smack);
|
||||||
|
|
||||||
|
return smk_import_allocated_label(smack, GFP_NOFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_import_valid_label - import a label, return the list entry
|
||||||
|
* @label: a text string that is a valid Smack label, not null-terminated
|
||||||
|
* @label_len: the length of the text string in the @label
|
||||||
|
* @gfp: the GFP mask used for allocating memory for the @label text string copy
|
||||||
|
*
|
||||||
|
* Return: see description of smk_import_entry()
|
||||||
|
*/
|
||||||
|
struct smack_known *
|
||||||
|
smk_import_valid_label(const char *label, int label_len, gfp_t gfp)
|
||||||
|
{
|
||||||
|
char *smack = kstrndup(label, label_len, gfp);
|
||||||
|
|
||||||
|
if (!smack)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
return smk_import_allocated_label(smack, gfp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_from_secid - find the Smack label associated with a secid
|
* smack_from_secid - find the Smack label associated with a secid
|
||||||
* @secid: an integer that might be associated with a Smack label
|
* @secid: an integer that might be associated with a Smack label
|
||||||
|
|
|
||||||
|
|
@ -962,6 +962,42 @@ static int smack_inode_alloc_security(struct inode *inode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* smk_rule_transmutes - does access rule for (subject,object) contain 't'?
|
||||||
|
* @subject: a pointer to the subject's Smack label entry
|
||||||
|
* @object: a pointer to the object's Smack label entry
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
smk_rule_transmutes(struct smack_known *subject,
|
||||||
|
const struct smack_known *object)
|
||||||
|
{
|
||||||
|
int may;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
may = smk_access_entry(subject->smk_known, object->smk_known,
|
||||||
|
&subject->smk_rules);
|
||||||
|
rcu_read_unlock();
|
||||||
|
return (may > 0) && (may & MAY_TRANSMUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xattr_dupval(struct xattr *xattrs, int *xattr_count,
|
||||||
|
const char *name, const void *value, unsigned int vallen)
|
||||||
|
{
|
||||||
|
struct xattr * const xattr = lsm_get_xattr_slot(xattrs, xattr_count);
|
||||||
|
|
||||||
|
if (!xattr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
xattr->value = kmemdup(value, vallen, GFP_NOFS);
|
||||||
|
if (!xattr->value)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
xattr->value_len = vallen;
|
||||||
|
xattr->name = name;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smack_inode_init_security - copy out the smack from an inode
|
* smack_inode_init_security - copy out the smack from an inode
|
||||||
* @inode: the newly created inode
|
* @inode: the newly created inode
|
||||||
|
|
@ -977,23 +1013,30 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
|
||||||
struct xattr *xattrs, int *xattr_count)
|
struct xattr *xattrs, int *xattr_count)
|
||||||
{
|
{
|
||||||
struct task_smack *tsp = smack_cred(current_cred());
|
struct task_smack *tsp = smack_cred(current_cred());
|
||||||
struct inode_smack *issp = smack_inode(inode);
|
struct inode_smack * const issp = smack_inode(inode);
|
||||||
struct smack_known *skp = smk_of_task(tsp);
|
|
||||||
struct smack_known *isp = smk_of_inode(inode);
|
|
||||||
struct smack_known *dsp = smk_of_inode(dir);
|
struct smack_known *dsp = smk_of_inode(dir);
|
||||||
struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
|
int rc = 0;
|
||||||
int may;
|
int transflag = 0;
|
||||||
|
bool trans_cred;
|
||||||
|
bool trans_rule;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UNIX domain sockets use lower level socket data. Let
|
||||||
|
* UDS inode have fixed * label to keep smack_inode_permission() calm
|
||||||
|
* when called from unix_find_bsd()
|
||||||
|
*/
|
||||||
|
if (S_ISSOCK(inode->i_mode)) {
|
||||||
|
/* forced label, no need to save to xattrs */
|
||||||
|
issp->smk_inode = &smack_known_star;
|
||||||
|
goto instant_inode;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* If equal, transmuting already occurred in
|
* If equal, transmuting already occurred in
|
||||||
* smack_dentry_create_files_as(). No need to check again.
|
* smack_dentry_create_files_as(). No need to check again.
|
||||||
*/
|
*/
|
||||||
if (tsp->smk_task != tsp->smk_transmuted) {
|
trans_cred = (tsp->smk_task == tsp->smk_transmuted);
|
||||||
rcu_read_lock();
|
if (!trans_cred)
|
||||||
may = smk_access_entry(skp->smk_known, dsp->smk_known,
|
trans_rule = smk_rule_transmutes(smk_of_task(tsp), dsp);
|
||||||
&skp->smk_rules);
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In addition to having smk_task equal to smk_transmuted,
|
* In addition to having smk_task equal to smk_transmuted,
|
||||||
|
|
@ -1001,47 +1044,38 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
|
||||||
* requests transmutation then by all means transmute.
|
* requests transmutation then by all means transmute.
|
||||||
* Mark the inode as changed.
|
* Mark the inode as changed.
|
||||||
*/
|
*/
|
||||||
if ((tsp->smk_task == tsp->smk_transmuted) ||
|
if (trans_cred || (trans_rule && smk_inode_transmutable(dir))) {
|
||||||
(may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
|
|
||||||
smk_inode_transmutable(dir))) {
|
|
||||||
struct xattr *xattr_transmute;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The caller of smack_dentry_create_files_as()
|
* The caller of smack_dentry_create_files_as()
|
||||||
* should have overridden the current cred, so the
|
* should have overridden the current cred, so the
|
||||||
* inode label was already set correctly in
|
* inode label was already set correctly in
|
||||||
* smack_inode_alloc_security().
|
* smack_inode_alloc_security().
|
||||||
*/
|
*/
|
||||||
if (tsp->smk_task != tsp->smk_transmuted)
|
if (!trans_cred)
|
||||||
isp = issp->smk_inode = dsp;
|
issp->smk_inode = dsp;
|
||||||
|
|
||||||
issp->smk_flags |= SMK_INODE_TRANSMUTE;
|
if (S_ISDIR(inode->i_mode)) {
|
||||||
xattr_transmute = lsm_get_xattr_slot(xattrs,
|
transflag = SMK_INODE_TRANSMUTE;
|
||||||
xattr_count);
|
|
||||||
if (xattr_transmute) {
|
|
||||||
xattr_transmute->value = kmemdup(TRANS_TRUE,
|
|
||||||
TRANS_TRUE_SIZE,
|
|
||||||
GFP_NOFS);
|
|
||||||
if (!xattr_transmute->value)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
xattr_transmute->value_len = TRANS_TRUE_SIZE;
|
if (xattr_dupval(xattrs, xattr_count,
|
||||||
xattr_transmute->name = XATTR_SMACK_TRANSMUTE;
|
XATTR_SMACK_TRANSMUTE,
|
||||||
|
TRANS_TRUE,
|
||||||
|
TRANS_TRUE_SIZE
|
||||||
|
))
|
||||||
|
rc = -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
issp->smk_flags |= SMK_INODE_INSTANT;
|
if (rc == 0)
|
||||||
|
if (xattr_dupval(xattrs, xattr_count,
|
||||||
if (xattr) {
|
XATTR_SMACK_SUFFIX,
|
||||||
xattr->value = kstrdup(isp->smk_known, GFP_NOFS);
|
issp->smk_inode->smk_known,
|
||||||
if (!xattr->value)
|
strlen(issp->smk_inode->smk_known)
|
||||||
return -ENOMEM;
|
))
|
||||||
|
rc = -ENOMEM;
|
||||||
xattr->value_len = strlen(isp->smk_known);
|
instant_inode:
|
||||||
xattr->name = XATTR_SMACK_SUFFIX;
|
issp->smk_flags |= (SMK_INODE_INSTANT | transflag);
|
||||||
}
|
return rc;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1315,12 +1349,22 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
|
||||||
int check_import = 0;
|
int check_import = 0;
|
||||||
int check_star = 0;
|
int check_star = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
umode_t const i_mode = d_backing_inode(dentry)->i_mode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check label validity here so import won't fail in post_setxattr
|
* Check label validity here so import won't fail in post_setxattr
|
||||||
*/
|
*/
|
||||||
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
|
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
|
||||||
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
|
/*
|
||||||
|
* UDS inode has fixed label
|
||||||
|
*/
|
||||||
|
if (S_ISSOCK(i_mode)) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
} else {
|
||||||
|
check_priv = 1;
|
||||||
|
check_import = 1;
|
||||||
|
}
|
||||||
|
} else if (strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
|
||||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
|
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
|
||||||
check_priv = 1;
|
check_priv = 1;
|
||||||
check_import = 1;
|
check_import = 1;
|
||||||
|
|
@ -1331,7 +1375,7 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
|
||||||
check_star = 1;
|
check_star = 1;
|
||||||
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
|
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
|
||||||
check_priv = 1;
|
check_priv = 1;
|
||||||
if (!S_ISDIR(d_backing_inode(dentry)->i_mode) ||
|
if (!S_ISDIR(i_mode) ||
|
||||||
size != TRANS_TRUE_SIZE ||
|
size != TRANS_TRUE_SIZE ||
|
||||||
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
|
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
|
|
@ -1462,12 +1506,15 @@ static int smack_inode_removexattr(struct mnt_idmap *idmap,
|
||||||
* Don't do anything special for these.
|
* Don't do anything special for these.
|
||||||
* XATTR_NAME_SMACKIPIN
|
* XATTR_NAME_SMACKIPIN
|
||||||
* XATTR_NAME_SMACKIPOUT
|
* XATTR_NAME_SMACKIPOUT
|
||||||
|
* XATTR_NAME_SMACK if S_ISSOCK (UDS inode has fixed label)
|
||||||
*/
|
*/
|
||||||
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
|
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
|
||||||
|
if (!S_ISSOCK(d_backing_inode(dentry)->i_mode)) {
|
||||||
struct super_block *sbp = dentry->d_sb;
|
struct super_block *sbp = dentry->d_sb;
|
||||||
struct superblock_smack *sbsp = smack_superblock(sbp);
|
struct superblock_smack *sbsp = smack_superblock(sbp);
|
||||||
|
|
||||||
isp->smk_inode = sbsp->smk_default;
|
isp->smk_inode = sbsp->smk_default;
|
||||||
|
}
|
||||||
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
|
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
|
||||||
isp->smk_task = NULL;
|
isp->smk_task = NULL;
|
||||||
else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
|
else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
|
||||||
|
|
@ -3585,7 +3632,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UNIX domain sockets use lower level socket data.
|
* UDS inode has fixed label (*)
|
||||||
*/
|
*/
|
||||||
if (S_ISSOCK(inode->i_mode)) {
|
if (S_ISSOCK(inode->i_mode)) {
|
||||||
final = &smack_known_star;
|
final = &smack_known_star;
|
||||||
|
|
@ -3663,7 +3710,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||||
* @attr: which attribute to fetch
|
* @attr: which attribute to fetch
|
||||||
* @ctx: buffer to receive the result
|
* @ctx: buffer to receive the result
|
||||||
* @size: available size in, actual size out
|
* @size: available size in, actual size out
|
||||||
* @flags: unused
|
* @flags: reserved, currently zero
|
||||||
*
|
*
|
||||||
* Fill the passed user space @ctx with the details of the requested
|
* Fill the passed user space @ctx with the details of the requested
|
||||||
* attribute.
|
* attribute.
|
||||||
|
|
@ -3724,47 +3771,55 @@ static int smack_getprocattr(struct task_struct *p, const char *name, char **val
|
||||||
* Sets the Smack value of the task. Only setting self
|
* Sets the Smack value of the task. Only setting self
|
||||||
* is permitted and only with privilege
|
* is permitted and only with privilege
|
||||||
*
|
*
|
||||||
* Returns the length of the smack label or an error code
|
* Returns zero on success or an error code
|
||||||
*/
|
*/
|
||||||
static int do_setattr(u64 attr, void *value, size_t size)
|
static int do_setattr(unsigned int attr, void *value, size_t size)
|
||||||
{
|
{
|
||||||
struct task_smack *tsp = smack_cred(current_cred());
|
struct task_smack *tsp = smack_cred(current_cred());
|
||||||
struct cred *new;
|
struct cred *new;
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
struct smack_known_list_elem *sklep;
|
int label_len;
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
|
|
||||||
return -EPERM;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* let unprivileged user validate input, check permissions later
|
||||||
|
*/
|
||||||
if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
|
if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (attr != LSM_ATTR_CURRENT)
|
label_len = smk_parse_label_len(value, size);
|
||||||
return -EOPNOTSUPP;
|
if (label_len < 0 || label_len != size)
|
||||||
|
return -EINVAL;
|
||||||
skp = smk_import_entry(value, size);
|
|
||||||
if (IS_ERR(skp))
|
|
||||||
return PTR_ERR(skp);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No process is ever allowed the web ("@") label
|
* No process is ever allowed the web ("@") label
|
||||||
* and the star ("*") label.
|
* and the star ("*") label.
|
||||||
*/
|
*/
|
||||||
if (skp == &smack_known_web || skp == &smack_known_star)
|
if (label_len == 1 /* '@', '*' */) {
|
||||||
return -EINVAL;
|
const char c = *(const char *)value;
|
||||||
|
|
||||||
|
if (c == *smack_known_web.smk_known ||
|
||||||
|
c == *smack_known_star.smk_known)
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
if (!smack_privileged(CAP_MAC_ADMIN)) {
|
if (!smack_privileged(CAP_MAC_ADMIN)) {
|
||||||
rc = -EPERM;
|
const struct smack_known_list_elem *sklep;
|
||||||
list_for_each_entry(sklep, &tsp->smk_relabel, list)
|
list_for_each_entry(sklep, &tsp->smk_relabel, list) {
|
||||||
if (sklep->smk_label == skp) {
|
const char *cp = sklep->smk_label->smk_known;
|
||||||
rc = 0;
|
|
||||||
break;
|
if (strlen(cp) == label_len &&
|
||||||
|
strncmp(cp, value, label_len) == 0)
|
||||||
|
goto in_relabel;
|
||||||
}
|
}
|
||||||
if (rc)
|
return -EPERM;
|
||||||
return rc;
|
in_relabel:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skp = smk_import_valid_label(value, label_len, GFP_KERNEL);
|
||||||
|
if (IS_ERR(skp))
|
||||||
|
return PTR_ERR(skp);
|
||||||
|
|
||||||
new = prepare_creds();
|
new = prepare_creds();
|
||||||
if (new == NULL)
|
if (new == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
@ -3777,7 +3832,7 @@ static int do_setattr(u64 attr, void *value, size_t size)
|
||||||
smk_destroy_label_list(&tsp->smk_relabel);
|
smk_destroy_label_list(&tsp->smk_relabel);
|
||||||
|
|
||||||
commit_creds(new);
|
commit_creds(new);
|
||||||
return size;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -3785,7 +3840,7 @@ static int do_setattr(u64 attr, void *value, size_t size)
|
||||||
* @attr: which attribute to set
|
* @attr: which attribute to set
|
||||||
* @ctx: buffer containing the data
|
* @ctx: buffer containing the data
|
||||||
* @size: size of @ctx
|
* @size: size of @ctx
|
||||||
* @flags: unused
|
* @flags: reserved, must be zero
|
||||||
*
|
*
|
||||||
* Fill the passed user space @ctx with the details of the requested
|
* Fill the passed user space @ctx with the details of the requested
|
||||||
* attribute.
|
* attribute.
|
||||||
|
|
@ -3795,12 +3850,26 @@ static int do_setattr(u64 attr, void *value, size_t size)
|
||||||
static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
|
static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
|
||||||
u32 size, u32 flags)
|
u32 size, u32 flags)
|
||||||
{
|
{
|
||||||
int rc;
|
if (attr != LSM_ATTR_CURRENT)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
rc = do_setattr(attr, ctx->ctx, ctx->ctx_len);
|
if (ctx->flags)
|
||||||
if (rc > 0)
|
return -EINVAL;
|
||||||
return 0;
|
/*
|
||||||
return rc;
|
* string must have \0 terminator, included in ctx->ctx
|
||||||
|
* (see description of struct lsm_ctx)
|
||||||
|
*/
|
||||||
|
if (ctx->ctx_len == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (ctx->ctx[ctx->ctx_len - 1] != '\0')
|
||||||
|
return -EINVAL;
|
||||||
|
/*
|
||||||
|
* other do_setattr() caller, smack_setprocattr(),
|
||||||
|
* does not count \0 into size, so
|
||||||
|
* decreasing length by 1 to accommodate the divergence.
|
||||||
|
*/
|
||||||
|
return do_setattr(attr, ctx->ctx, ctx->ctx_len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -3812,15 +3881,39 @@ static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
|
||||||
* Sets the Smack value of the task. Only setting self
|
* Sets the Smack value of the task. Only setting self
|
||||||
* is permitted and only with privilege
|
* is permitted and only with privilege
|
||||||
*
|
*
|
||||||
* Returns the length of the smack label or an error code
|
* Returns the size of the input value or an error code
|
||||||
*/
|
*/
|
||||||
static int smack_setprocattr(const char *name, void *value, size_t size)
|
static int smack_setprocattr(const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
int attr = lsm_name_to_attr(name);
|
size_t realsize = size;
|
||||||
|
unsigned int attr = lsm_name_to_attr(name);
|
||||||
|
|
||||||
if (attr != LSM_ATTR_UNDEF)
|
switch (attr) {
|
||||||
return do_setattr(attr, value, size);
|
case LSM_ATTR_UNDEF: return -EINVAL;
|
||||||
return -EINVAL;
|
default: return -EOPNOTSUPP;
|
||||||
|
case LSM_ATTR_CURRENT:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The value for the "current" attribute is the label
|
||||||
|
* followed by one of the 4 trailers: none, \0, \n, \n\0
|
||||||
|
*
|
||||||
|
* I.e. following inputs are accepted as 3-characters long label "foo":
|
||||||
|
*
|
||||||
|
* "foo" (3 characters)
|
||||||
|
* "foo\0" (4 characters)
|
||||||
|
* "foo\n" (4 characters)
|
||||||
|
* "foo\n\0" (5 characters)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (realsize && (((const char *)value)[realsize - 1] == '\0'))
|
||||||
|
--realsize;
|
||||||
|
|
||||||
|
if (realsize && (((const char *)value)[realsize - 1] == '\n'))
|
||||||
|
--realsize;
|
||||||
|
|
||||||
|
return do_setattr(attr, value, realsize) ? : size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -4850,6 +4943,11 @@ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
|
||||||
|
|
||||||
static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
|
static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* UDS inode has fixed label. Ignore nfs label.
|
||||||
|
*/
|
||||||
|
if (S_ISSOCK(inode->i_mode))
|
||||||
|
return 0;
|
||||||
return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx,
|
return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx,
|
||||||
ctxlen, 0);
|
ctxlen, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -4915,7 +5013,6 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
|
||||||
struct task_smack *otsp = smack_cred(old);
|
struct task_smack *otsp = smack_cred(old);
|
||||||
struct task_smack *ntsp = smack_cred(new);
|
struct task_smack *ntsp = smack_cred(new);
|
||||||
struct inode_smack *isp;
|
struct inode_smack *isp;
|
||||||
int may;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use the process credential unless all of
|
* Use the process credential unless all of
|
||||||
|
|
@ -4929,18 +5026,12 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
|
||||||
isp = smack_inode(d_inode(dentry->d_parent));
|
isp = smack_inode(d_inode(dentry->d_parent));
|
||||||
|
|
||||||
if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
|
if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
|
||||||
rcu_read_lock();
|
|
||||||
may = smk_access_entry(otsp->smk_task->smk_known,
|
|
||||||
isp->smk_inode->smk_known,
|
|
||||||
&otsp->smk_task->smk_rules);
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the directory is transmuting and the rule
|
* If the directory is transmuting and the rule
|
||||||
* providing access is transmuting use the containing
|
* providing access is transmuting use the containing
|
||||||
* directory label instead of the process label.
|
* directory label instead of the process label.
|
||||||
*/
|
*/
|
||||||
if (may > 0 && (may & MAY_TRANSMUTE)) {
|
if (smk_rule_transmutes(otsp->smk_task, isp->smk_inode)) {
|
||||||
ntsp->smk_task = isp->smk_inode;
|
ntsp->smk_task = isp->smk_inode;
|
||||||
ntsp->smk_transmuted = ntsp->smk_task;
|
ntsp->smk_transmuted = ntsp->smk_task;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue