Skip to content

Commit

Permalink
selinux: wrap AVC state
Browse files Browse the repository at this point in the history
Wrap the AVC state within the selinux_state structure and
pass it explicitly to all AVC functions.  The AVC private state
is encapsulated in a selinux_avc structure that is referenced
from the selinux_state.

This change should have no effect on SELinux behavior or
APIs (userspace or LSM).

Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Reviewed-by: James Morris <james.morris@microsoft.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
  • Loading branch information
Stephen Smalley authored and Paul Moore committed Mar 20, 2018
1 parent 0619f0f commit 6b6bc62
Show file tree
Hide file tree
Showing 9 changed files with 512 additions and 297 deletions.
284 changes: 162 additions & 122 deletions security/selinux/avc.c

Large diffs are not rendered by default.

398 changes: 265 additions & 133 deletions security/selinux/hooks.c

Large diffs are not rendered by default.

32 changes: 21 additions & 11 deletions security/selinux/include/avc.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ struct selinux_audit_data {
u32 audited;
u32 denied;
int result;
struct selinux_state *state;
};

/*
Expand Down Expand Up @@ -96,7 +97,8 @@ static inline u32 avc_audit_required(u32 requested,
return audited;
}

int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
int slow_avc_audit(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
u32 requested, u32 audited, u32 denied, int result,
struct common_audit_data *a,
unsigned flags);
Expand All @@ -121,7 +123,8 @@ int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
* be performed under a lock, to allow the lock to be released
* before calling the auditing code.
*/
static inline int avc_audit(u32 ssid, u32 tsid,
static inline int avc_audit(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd,
int result,
Expand All @@ -132,31 +135,35 @@ static inline int avc_audit(u32 ssid, u32 tsid,
audited = avc_audit_required(requested, avd, result, 0, &denied);
if (likely(!audited))
return 0;
return slow_avc_audit(ssid, tsid, tclass,
return slow_avc_audit(state, ssid, tsid, tclass,
requested, audited, denied, result,
a, flags);
}

#define AVC_STRICT 1 /* Ignore permissive mode. */
#define AVC_EXTENDED_PERMS 2 /* update extended permissions */
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
int avc_has_perm_noaudit(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested,
unsigned flags,
struct av_decision *avd);

int avc_has_perm(u32 ssid, u32 tsid,
int avc_has_perm(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata);
int avc_has_perm_flags(u32 ssid, u32 tsid,
int avc_has_perm_flags(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata,
int flags);

int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
u8 driver, u8 perm, struct common_audit_data *ad);
int avc_has_extended_perms(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass, u32 requested,
u8 driver, u8 perm, struct common_audit_data *ad);


u32 avc_policy_seqno(void);
u32 avc_policy_seqno(struct selinux_state *state);

#define AVC_CALLBACK_GRANT 1
#define AVC_CALLBACK_TRY_REVOKE 2
Expand All @@ -171,8 +178,11 @@ u32 avc_policy_seqno(void);
int avc_add_callback(int (*callback)(u32 event), u32 events);

/* Exported to selinuxfs */
int avc_get_hash_stats(char *page);
extern unsigned int avc_cache_threshold;
struct selinux_avc;
int avc_get_hash_stats(struct selinux_avc *avc, char *page);
unsigned int avc_get_cache_threshold(struct selinux_avc *avc);
void avc_set_cache_threshold(struct selinux_avc *avc,
unsigned int cache_threshold);

/* Attempt to free avc node cache */
void avc_disable(void);
Expand Down
3 changes: 2 additions & 1 deletion security/selinux/include/avc_ss.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

#include "flask.h"

int avc_ss_reset(u32 seqno);
struct selinux_avc;
int avc_ss_reset(struct selinux_avc *avc, u32 seqno);

/* Class/perm mapping support */
struct security_class_mapping {
Expand Down
3 changes: 3 additions & 0 deletions security/selinux/include/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ extern char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
/* limitation of boundary depth */
#define POLICYDB_BOUNDS_MAXDEPTH 4

struct selinux_avc;
struct selinux_ss;

struct selinux_state {
Expand All @@ -103,10 +104,12 @@ struct selinux_state {
bool checkreqprot;
bool initialized;
bool policycap[__POLICYDB_CAPABILITY_MAX];
struct selinux_avc *avc;
struct selinux_ss *ss;
};

void selinux_ss_init(struct selinux_ss **ss);
void selinux_avc_init(struct selinux_avc **avc);

extern struct selinux_state selinux_state;

Expand Down
3 changes: 2 additions & 1 deletion security/selinux/netlabel.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
perm = RAWIP_SOCKET__RECVFROM;
}

rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
rc = avc_has_perm(&selinux_state,
sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
if (rc == 0)
return 0;

Expand Down
60 changes: 41 additions & 19 deletions security/selinux/selinuxfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,

old_value = enforcing_enabled(state);
if (new_value != old_value) {
length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETENFORCE,
NULL);
if (length)
Expand All @@ -173,7 +174,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
audit_get_sessionid(current));
enforcing_set(state, new_value);
if (new_value)
avc_ss_reset(0);
avc_ss_reset(state->avc, 0);
selnl_notify_setenforce(new_value);
selinux_status_update_setenforce(state, new_value);
if (!new_value)
Expand Down Expand Up @@ -375,7 +376,8 @@ static int sel_open_policy(struct inode *inode, struct file *filp)

mutex_lock(&fsi->mutex);

rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
rc = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (rc)
goto err;
Expand Down Expand Up @@ -439,7 +441,8 @@ static ssize_t sel_read_policy(struct file *filp, char __user *buf,

mutex_lock(&fsi->mutex);

ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
ret = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (ret)
goto out;
Expand Down Expand Up @@ -535,7 +538,8 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,

mutex_lock(&fsi->mutex);

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
if (length)
goto out;
Expand Down Expand Up @@ -594,7 +598,8 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
u32 sid, len;
ssize_t length;

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
if (length)
goto out;
Expand Down Expand Up @@ -640,7 +645,8 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
ssize_t length;
unsigned int new_value;

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
NULL);
if (length)
Expand Down Expand Up @@ -685,7 +691,8 @@ static ssize_t sel_write_validatetrans(struct file *file,
u16 tclass;
int rc;

rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
rc = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
if (rc)
goto out;
Expand Down Expand Up @@ -813,7 +820,8 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
struct av_decision avd;
ssize_t length;

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
if (length)
goto out;
Expand Down Expand Up @@ -866,7 +874,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
u32 len;
int nargs;

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
NULL);
if (length)
Expand Down Expand Up @@ -967,7 +976,8 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
NULL);
if (length)
Expand Down Expand Up @@ -1027,7 +1037,8 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
int i, rc;
u32 len, nsids;

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
NULL);
if (length)
Expand Down Expand Up @@ -1091,7 +1102,8 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
NULL);
if (length)
Expand Down Expand Up @@ -1203,7 +1215,8 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,

mutex_lock(&fsi->mutex);

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL,
NULL);
if (length)
Expand Down Expand Up @@ -1263,7 +1276,8 @@ static ssize_t sel_commit_bools_write(struct file *filep,

mutex_lock(&fsi->mutex);

length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL,
NULL);
if (length)
Expand Down Expand Up @@ -1403,10 +1417,13 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char tmpbuf[TMPBUFLEN];
ssize_t length;

length = scnprintf(tmpbuf, TMPBUFLEN, "%u", avc_cache_threshold);
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
avc_get_cache_threshold(state->avc));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

Expand All @@ -1415,11 +1432,14 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
size_t count, loff_t *ppos)

{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *page;
ssize_t ret;
unsigned int new_value;

ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
ret = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETSECPARAM,
NULL);
if (ret)
Expand All @@ -1440,7 +1460,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
if (sscanf(page, "%u", &new_value) != 1)
goto out;

avc_cache_threshold = new_value;
avc_set_cache_threshold(state->avc, new_value);

ret = count;
out:
Expand All @@ -1451,14 +1471,16 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *page;
ssize_t length;

page = (char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;

length = avc_get_hash_stats(page);
length = avc_get_hash_stats(state->avc, page);
if (length >= 0)
length = simple_read_from_buffer(buf, count, ppos, page, length);
free_page((unsigned long)page);
Expand Down
9 changes: 5 additions & 4 deletions security/selinux/ss/services.c
Original file line number Diff line number Diff line change
Expand Up @@ -2151,7 +2151,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
state->initialized = 1;
seqno = ++state->ss->latest_granting;
selinux_complete_init();
avc_ss_reset(seqno);
avc_ss_reset(state->avc, seqno);
selnl_notify_policyload(seqno);
selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate();
Expand Down Expand Up @@ -2233,7 +2233,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
sidtab_destroy(&oldsidtab);
kfree(oldmapping);

avc_ss_reset(seqno);
avc_ss_reset(state->avc, seqno);
selnl_notify_policyload(seqno);
selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate();
Expand Down Expand Up @@ -2649,7 +2649,8 @@ int security_get_user_sids(struct selinux_state *state,
}
for (i = 0, j = 0; i < mynel; i++) {
struct av_decision dummy_avd;
rc = avc_has_perm_noaudit(fromsid, mysids[i],
rc = avc_has_perm_noaudit(state,
fromsid, mysids[i],
SECCLASS_PROCESS, /* kernel value */
PROCESS__TRANSITION, AVC_STRICT,
&dummy_avd);
Expand Down Expand Up @@ -2907,7 +2908,7 @@ int security_set_bools(struct selinux_state *state, int len, int *values)
out:
write_unlock_irq(&state->ss->policy_rwlock);
if (!rc) {
avc_ss_reset(seqno);
avc_ss_reset(state->avc, seqno);
selnl_notify_policyload(seqno);
selinux_status_update_policyload(state, seqno);
selinux_xfrm_notify_policyload();
Expand Down
Loading

0 comments on commit 6b6bc62

Please sign in to comment.