Skip to content

Commit

Permalink
smack: limit privilege by label
Browse files Browse the repository at this point in the history
There have been a number of requests to make the Smack LSM
enforce MAC even in the face of privilege, either capability
based or superuser based. This is not universally desired,
however, so it seems desirable to make it optional. Further,
at least one legacy OS implemented a scheme whereby only
processes running with one particular label could be exempt
from MAC. This patch supports these three cases.

If /smack/onlycap is empty (unset or null-string) privilege
is enforced in the normal way.

If /smack/onlycap contains a label only processes running with
that label may be MAC exempt.

If the label in /smack/onlycap is the star label ("*") the
semantics of the star label combine with the privilege
restrictions to prevent any violations of MAC, even in the
presence of privilege.

Again, this will be independent of the privilege scheme.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: James Morris <[email protected]>
  • Loading branch information
cschaufler authored and James Morris committed Aug 5, 2008
1 parent cf9481e commit 1544623
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 1 deletion.
1 change: 1 addition & 0 deletions security/smack/smack.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ u32 smack_to_secid(const char *);
extern int smack_cipso_direct;
extern int smack_net_nltype;
extern char *smack_net_ambient;
extern char *smack_onlycap;

extern struct smack_known *smack_known;
extern struct smack_known smack_known_floor;
Expand Down
10 changes: 9 additions & 1 deletion security/smack/smack_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ int smk_access(char *subject_label, char *object_label, int request)
*
* This function checks the current subject label/object label pair
* in the access rule list and returns 0 if the access is permitted,
* non zero otherwise. It allows that current my have the capability
* non zero otherwise. It allows that current may have the capability
* to override the rules.
*/
int smk_curacc(char *obj_label, u32 mode)
Expand All @@ -168,6 +168,14 @@ int smk_curacc(char *obj_label, u32 mode)
if (rc == 0)
return 0;

/*
* Return if a specific label has been designated as the
* only one that gets privilege and current does not
* have that label.
*/
if (smack_onlycap != NULL && smack_onlycap != current->security)
return rc;

if (capable(CAP_MAC_OVERRIDE))
return 0;

Expand Down
92 changes: 92 additions & 0 deletions security/smack/smackfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum smk_inos {
SMK_DIRECT = 6, /* CIPSO level indicating direct label */
SMK_AMBIENT = 7, /* internet ambient label */
SMK_NLTYPE = 8, /* label scheme to use by default */
SMK_ONLYCAP = 9, /* the only "capable" label */
};

/*
Expand Down Expand Up @@ -68,6 +69,16 @@ int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
*/
int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;

/*
* Unless a process is running with this label even
* having CAP_MAC_OVERRIDE isn't enough to grant
* privilege to violate MAC policy. If no label is
* designated (the NULL case) capabilities apply to
* everyone. It is expected that the hat (^) label
* will be used if any label is used.
*/
char *smack_onlycap;

static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
struct smk_list_entry *smack_list;

Expand Down Expand Up @@ -787,6 +798,85 @@ static const struct file_operations smk_ambient_ops = {
.write = smk_write_ambient,
};

/**
* smk_read_onlycap - read() for /smack/onlycap
* @filp: file pointer, not actually used
* @buf: where to put the result
* @cn: maximum to send along
* @ppos: where to start
*
* Returns number of bytes read or error code, as appropriate
*/
static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
size_t cn, loff_t *ppos)
{
char *smack = "";
ssize_t rc = -EINVAL;
int asize;

if (*ppos != 0)
return 0;

if (smack_onlycap != NULL)
smack = smack_onlycap;

asize = strlen(smack) + 1;

if (cn >= asize)
rc = simple_read_from_buffer(buf, cn, ppos, smack, asize);

return rc;
}

/**
* smk_write_onlycap - write() for /smack/onlycap
* @filp: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
* @ppos: where to start
*
* Returns number of bytes written or error code, as appropriate
*/
static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char in[SMK_LABELLEN];
char *sp = current->security;

if (!capable(CAP_MAC_ADMIN))
return -EPERM;

/*
* This can be done using smk_access() but is done
* explicitly for clarity. The smk_access() implementation
* would use smk_access(smack_onlycap, MAY_WRITE)
*/
if (smack_onlycap != NULL && smack_onlycap != sp)
return -EPERM;

if (count >= SMK_LABELLEN)
return -EINVAL;

if (copy_from_user(in, buf, count) != 0)
return -EFAULT;

/*
* Should the null string be passed in unset the onlycap value.
* This seems like something to be careful with as usually
* smk_import only expects to return NULL for errors. It
* is usually the case that a nullstring or "\n" would be
* bad to pass to smk_import but in fact this is useful here.
*/
smack_onlycap = smk_import(in, count);

return count;
}

static const struct file_operations smk_onlycap_ops = {
.read = smk_read_onlycap,
.write = smk_write_onlycap,
};

struct option_names {
int o_number;
char *o_name;
Expand Down Expand Up @@ -919,6 +1009,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
{"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
[SMK_NLTYPE] =
{"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
[SMK_ONLYCAP] =
{"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
/* last one */ {""}
};

Expand Down

0 comments on commit 1544623

Please sign in to comment.