Merge branch 'master' of git://git.infradead.org/users/eparis/selinux into next
Per pull request, for 3.5.
This commit is contained in:
commit
ff2bb047c4
33 changed files with 422 additions and 350 deletions
|
@ -681,7 +681,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
|
|||
|
||||
f->f_op = fops_get(inode->i_fop);
|
||||
|
||||
error = security_dentry_open(f, cred);
|
||||
error = security_file_open(f, cred);
|
||||
if (error)
|
||||
goto cleanup_all;
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ struct common_audit_data {
|
|||
#define LSM_AUDIT_DATA_KMOD 8
|
||||
#define LSM_AUDIT_DATA_INODE 9
|
||||
#define LSM_AUDIT_DATA_DENTRY 10
|
||||
struct task_struct *tsk;
|
||||
union {
|
||||
struct path path;
|
||||
struct dentry *dentry;
|
||||
|
@ -93,11 +92,6 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb,
|
|||
int ipv6_skb_to_auditdata(struct sk_buff *skb,
|
||||
struct common_audit_data *ad, u8 *proto);
|
||||
|
||||
/* Initialize an LSM audit data structure. */
|
||||
#define COMMON_AUDIT_DATA_INIT(_d, _t) \
|
||||
{ memset((_d), 0, sizeof(struct common_audit_data)); \
|
||||
(_d)->type = LSM_AUDIT_DATA_##_t; }
|
||||
|
||||
void common_lsm_audit(struct common_audit_data *a,
|
||||
void (*pre_audit)(struct audit_buffer *, void *),
|
||||
void (*post_audit)(struct audit_buffer *, void *));
|
||||
|
|
|
@ -640,10 +640,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
|||
* to receive an open file descriptor via socket IPC.
|
||||
* @file contains the file structure being received.
|
||||
* Return 0 if permission is granted.
|
||||
*
|
||||
* Security hook for dentry
|
||||
*
|
||||
* @dentry_open
|
||||
* @file_open
|
||||
* Save open-time permission checking state for later use upon
|
||||
* file_permission, and recheck access if anything has changed
|
||||
* since inode_permission.
|
||||
|
@ -1498,7 +1495,7 @@ struct security_operations {
|
|||
int (*file_send_sigiotask) (struct task_struct *tsk,
|
||||
struct fown_struct *fown, int sig);
|
||||
int (*file_receive) (struct file *file);
|
||||
int (*dentry_open) (struct file *file, const struct cred *cred);
|
||||
int (*file_open) (struct file *file, const struct cred *cred);
|
||||
|
||||
int (*task_create) (unsigned long clone_flags);
|
||||
void (*task_free) (struct task_struct *task);
|
||||
|
@ -1757,7 +1754,7 @@ int security_file_set_fowner(struct file *file);
|
|||
int security_file_send_sigiotask(struct task_struct *tsk,
|
||||
struct fown_struct *fown, int sig);
|
||||
int security_file_receive(struct file *file);
|
||||
int security_dentry_open(struct file *file, const struct cred *cred);
|
||||
int security_file_open(struct file *file, const struct cred *cred);
|
||||
int security_task_create(unsigned long clone_flags);
|
||||
void security_task_free(struct task_struct *task);
|
||||
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
|
||||
|
@ -2228,8 +2225,8 @@ static inline int security_file_receive(struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_dentry_open(struct file *file,
|
||||
const struct cred *cred)
|
||||
static inline int security_file_open(struct file *file,
|
||||
const struct cred *cred)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/cache.h>
|
||||
#include <linux/audit.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/xfrm.h>
|
||||
#include <net/ip.h>
|
||||
#ifdef CONFIG_XFRM_STATISTICS
|
||||
|
|
|
@ -111,7 +111,7 @@ static const char *const aa_audit_type[] = {
|
|||
static void audit_pre(struct audit_buffer *ab, void *ca)
|
||||
{
|
||||
struct common_audit_data *sa = ca;
|
||||
struct task_struct *tsk = sa->tsk ? sa->tsk : current;
|
||||
struct task_struct *tsk = sa->aad->tsk ? sa->aad->tsk : current;
|
||||
|
||||
if (aa_g_audit_header) {
|
||||
audit_log_format(ab, "apparmor=");
|
||||
|
@ -149,6 +149,12 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
|
|||
audit_log_format(ab, " name=");
|
||||
audit_log_untrustedstring(ab, sa->aad->name);
|
||||
}
|
||||
|
||||
if (sa->aad->tsk) {
|
||||
audit_log_format(ab, " pid=%d comm=", tsk->pid);
|
||||
audit_log_untrustedstring(ab, tsk->comm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,7 +211,8 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
|
|||
aa_audit_msg(type, sa, cb);
|
||||
|
||||
if (sa->aad->type == AUDIT_APPARMOR_KILL)
|
||||
(void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
|
||||
(void)send_sig_info(SIGKILL, NULL,
|
||||
sa->aad->tsk ? sa->aad->tsk : current);
|
||||
|
||||
if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
|
||||
return complain_error(sa->aad->error);
|
||||
|
|
|
@ -65,10 +65,10 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task,
|
|||
int type = AUDIT_APPARMOR_AUTO;
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
COMMON_AUDIT_DATA_INIT(&sa, CAP);
|
||||
sa.type = LSM_AUDIT_DATA_CAP;
|
||||
sa.aad = &aad;
|
||||
sa.tsk = task;
|
||||
sa.u.cap = cap;
|
||||
sa.aad->tsk = task;
|
||||
sa.aad->op = OP_CAPABLE;
|
||||
sa.aad->error = error;
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
|
|||
int type = AUDIT_APPARMOR_AUTO;
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
COMMON_AUDIT_DATA_INIT(&sa, NONE);
|
||||
sa.type = LSM_AUDIT_DATA_NONE;
|
||||
sa.aad = &aad;
|
||||
aad.op = op,
|
||||
aad.fs.request = request;
|
||||
|
|
|
@ -110,6 +110,7 @@ struct apparmor_audit_data {
|
|||
void *profile;
|
||||
const char *name;
|
||||
const char *info;
|
||||
struct task_struct *tsk;
|
||||
union {
|
||||
void *target;
|
||||
struct {
|
||||
|
|
|
@ -42,7 +42,7 @@ static int aa_audit_ptrace(struct aa_profile *profile,
|
|||
{
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
COMMON_AUDIT_DATA_INIT(&sa, NONE);
|
||||
sa.type = LSM_AUDIT_DATA_NONE;
|
||||
sa.aad = &aad;
|
||||
aad.op = OP_PTRACE;
|
||||
aad.target = target;
|
||||
|
|
|
@ -66,7 +66,7 @@ void aa_info_message(const char *str)
|
|||
if (audit_enabled) {
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
COMMON_AUDIT_DATA_INIT(&sa, NONE);
|
||||
sa.type = LSM_AUDIT_DATA_NONE;
|
||||
sa.aad = &aad;
|
||||
aad.info = str;
|
||||
aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
|
||||
|
|
|
@ -373,7 +373,7 @@ static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
|
|||
AA_MAY_META_READ);
|
||||
}
|
||||
|
||||
static int apparmor_dentry_open(struct file *file, const struct cred *cred)
|
||||
static int apparmor_file_open(struct file *file, const struct cred *cred)
|
||||
{
|
||||
struct aa_file_cxt *fcxt = file->f_security;
|
||||
struct aa_profile *profile;
|
||||
|
@ -589,7 +589,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
|
|||
} else {
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
COMMON_AUDIT_DATA_INIT(&sa, NONE);
|
||||
sa.type = LSM_AUDIT_DATA_NONE;
|
||||
sa.aad = &aad;
|
||||
aad.op = OP_SETPROCATTR;
|
||||
aad.info = name;
|
||||
|
@ -640,9 +640,9 @@ static struct security_operations apparmor_ops = {
|
|||
.path_chmod = apparmor_path_chmod,
|
||||
.path_chown = apparmor_path_chown,
|
||||
.path_truncate = apparmor_path_truncate,
|
||||
.dentry_open = apparmor_dentry_open,
|
||||
.inode_getattr = apparmor_inode_getattr,
|
||||
|
||||
.file_open = apparmor_file_open,
|
||||
.file_permission = apparmor_file_permission,
|
||||
.file_alloc_security = apparmor_file_alloc_security,
|
||||
.file_free_security = apparmor_file_free_security,
|
||||
|
|
|
@ -969,7 +969,7 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
|
|||
{
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
COMMON_AUDIT_DATA_INIT(&sa, NONE);
|
||||
sa.type = LSM_AUDIT_DATA_NONE;
|
||||
sa.aad = &aad;
|
||||
aad.op = op;
|
||||
aad.name = name;
|
||||
|
|
|
@ -95,7 +95,7 @@ static int audit_iface(struct aa_profile *new, const char *name,
|
|||
struct aa_profile *profile = __aa_current_profile();
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
COMMON_AUDIT_DATA_INIT(&sa, NONE);
|
||||
sa.type = LSM_AUDIT_DATA_NONE;
|
||||
sa.aad = &aad;
|
||||
if (e)
|
||||
aad.iface.pos = e->pos - e->start;
|
||||
|
|
|
@ -52,7 +52,7 @@ static int audit_resource(struct aa_profile *profile, unsigned int resource,
|
|||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&sa, NONE);
|
||||
sa.type = LSM_AUDIT_DATA_NONE;
|
||||
sa.aad = &aad;
|
||||
aad.op = OP_SETRLIMIT,
|
||||
aad.rlim.rlim = resource;
|
||||
|
|
|
@ -348,7 +348,7 @@ static int cap_file_receive(struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cap_dentry_open(struct file *file, const struct cred *cred)
|
||||
static int cap_file_open(struct file *file, const struct cred *cred)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -956,7 +956,7 @@ void __init security_fixup_ops(struct security_operations *ops)
|
|||
set_to_cap_if_null(ops, file_set_fowner);
|
||||
set_to_cap_if_null(ops, file_send_sigiotask);
|
||||
set_to_cap_if_null(ops, file_receive);
|
||||
set_to_cap_if_null(ops, dentry_open);
|
||||
set_to_cap_if_null(ops, file_open);
|
||||
set_to_cap_if_null(ops, task_create);
|
||||
set_to_cap_if_null(ops, task_free);
|
||||
set_to_cap_if_null(ops, cred_alloc_blank);
|
||||
|
|
|
@ -213,12 +213,15 @@ static void dump_common_audit_data(struct audit_buffer *ab,
|
|||
{
|
||||
struct task_struct *tsk = current;
|
||||
|
||||
if (a->tsk)
|
||||
tsk = a->tsk;
|
||||
if (tsk && tsk->pid) {
|
||||
audit_log_format(ab, " pid=%d comm=", tsk->pid);
|
||||
audit_log_untrustedstring(ab, tsk->comm);
|
||||
}
|
||||
/*
|
||||
* To keep stack sizes in check force programers to notice if they
|
||||
* start making this union too large! See struct lsm_network_audit
|
||||
* as an example of how to deal with large data.
|
||||
*/
|
||||
BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2);
|
||||
|
||||
audit_log_format(ab, " pid=%d comm=", tsk->pid);
|
||||
audit_log_untrustedstring(ab, tsk->comm);
|
||||
|
||||
switch (a->type) {
|
||||
case LSM_AUDIT_DATA_NONE:
|
||||
|
|
|
@ -701,11 +701,11 @@ int security_file_receive(struct file *file)
|
|||
return security_ops->file_receive(file);
|
||||
}
|
||||
|
||||
int security_dentry_open(struct file *file, const struct cred *cred)
|
||||
int security_file_open(struct file *file, const struct cred *cred)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = security_ops->dentry_open(file, cred);
|
||||
ret = security_ops->file_open(file, cred);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -65,14 +65,8 @@ struct avc_cache {
|
|||
};
|
||||
|
||||
struct avc_callback_node {
|
||||
int (*callback) (u32 event, u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 perms,
|
||||
u32 *out_retained);
|
||||
int (*callback) (u32 event);
|
||||
u32 events;
|
||||
u32 ssid;
|
||||
u32 tsid;
|
||||
u16 tclass;
|
||||
u32 perms;
|
||||
struct avc_callback_node *next;
|
||||
};
|
||||
|
||||
|
@ -436,9 +430,9 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
|
|||
{
|
||||
struct common_audit_data *ad = a;
|
||||
audit_log_format(ab, "avc: %s ",
|
||||
ad->selinux_audit_data->slad->denied ? "denied" : "granted");
|
||||
avc_dump_av(ab, ad->selinux_audit_data->slad->tclass,
|
||||
ad->selinux_audit_data->slad->audited);
|
||||
ad->selinux_audit_data->denied ? "denied" : "granted");
|
||||
avc_dump_av(ab, ad->selinux_audit_data->tclass,
|
||||
ad->selinux_audit_data->audited);
|
||||
audit_log_format(ab, " for ");
|
||||
}
|
||||
|
||||
|
@ -452,25 +446,23 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
|
|||
{
|
||||
struct common_audit_data *ad = a;
|
||||
audit_log_format(ab, " ");
|
||||
avc_dump_query(ab, ad->selinux_audit_data->slad->ssid,
|
||||
ad->selinux_audit_data->slad->tsid,
|
||||
ad->selinux_audit_data->slad->tclass);
|
||||
avc_dump_query(ab, ad->selinux_audit_data->ssid,
|
||||
ad->selinux_audit_data->tsid,
|
||||
ad->selinux_audit_data->tclass);
|
||||
}
|
||||
|
||||
/* This is the slow part of avc audit with big stack footprint */
|
||||
static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
||||
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
||||
u32 requested, u32 audited, u32 denied,
|
||||
struct common_audit_data *a,
|
||||
unsigned flags)
|
||||
{
|
||||
struct common_audit_data stack_data;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct selinux_late_audit_data slad;
|
||||
struct selinux_audit_data sad;
|
||||
|
||||
if (!a) {
|
||||
a = &stack_data;
|
||||
COMMON_AUDIT_DATA_INIT(a, NONE);
|
||||
a->selinux_audit_data = &sad;
|
||||
a->type = LSM_AUDIT_DATA_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -484,104 +476,34 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
|||
(flags & MAY_NOT_BLOCK))
|
||||
return -ECHILD;
|
||||
|
||||
slad.tclass = tclass;
|
||||
slad.requested = requested;
|
||||
slad.ssid = ssid;
|
||||
slad.tsid = tsid;
|
||||
slad.audited = audited;
|
||||
slad.denied = denied;
|
||||
sad.tclass = tclass;
|
||||
sad.requested = requested;
|
||||
sad.ssid = ssid;
|
||||
sad.tsid = tsid;
|
||||
sad.audited = audited;
|
||||
sad.denied = denied;
|
||||
|
||||
a->selinux_audit_data = &sad;
|
||||
|
||||
a->selinux_audit_data->slad = &slad;
|
||||
common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* avc_audit - Audit the granting or denial of permissions.
|
||||
* @ssid: source security identifier
|
||||
* @tsid: target security identifier
|
||||
* @tclass: target security class
|
||||
* @requested: requested permissions
|
||||
* @avd: access vector decisions
|
||||
* @result: result from avc_has_perm_noaudit
|
||||
* @a: auxiliary audit data
|
||||
* @flags: VFS walk flags
|
||||
*
|
||||
* Audit the granting or denial of permissions in accordance
|
||||
* with the policy. This function is typically called by
|
||||
* avc_has_perm() after a permission check, but can also be
|
||||
* called directly by callers who use avc_has_perm_noaudit()
|
||||
* in order to separate the permission check from the auditing.
|
||||
* For example, this separation is useful when the permission check must
|
||||
* be performed under a lock, to allow the lock to be released
|
||||
* before calling the auditing code.
|
||||
*/
|
||||
inline int avc_audit(u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 requested,
|
||||
struct av_decision *avd, int result, struct common_audit_data *a,
|
||||
unsigned flags)
|
||||
{
|
||||
u32 denied, audited;
|
||||
denied = requested & ~avd->allowed;
|
||||
if (unlikely(denied)) {
|
||||
audited = denied & avd->auditdeny;
|
||||
/*
|
||||
* a->selinux_audit_data->auditdeny is TRICKY! Setting a bit in
|
||||
* this field means that ANY denials should NOT be audited if
|
||||
* the policy contains an explicit dontaudit rule for that
|
||||
* permission. Take notice that this is unrelated to the
|
||||
* actual permissions that were denied. As an example lets
|
||||
* assume:
|
||||
*
|
||||
* denied == READ
|
||||
* avd.auditdeny & ACCESS == 0 (not set means explicit rule)
|
||||
* selinux_audit_data->auditdeny & ACCESS == 1
|
||||
*
|
||||
* We will NOT audit the denial even though the denied
|
||||
* permission was READ and the auditdeny checks were for
|
||||
* ACCESS
|
||||
*/
|
||||
if (a &&
|
||||
a->selinux_audit_data->auditdeny &&
|
||||
!(a->selinux_audit_data->auditdeny & avd->auditdeny))
|
||||
audited = 0;
|
||||
} else if (result)
|
||||
audited = denied = requested;
|
||||
else
|
||||
audited = requested & avd->auditallow;
|
||||
if (likely(!audited))
|
||||
return 0;
|
||||
|
||||
return slow_avc_audit(ssid, tsid, tclass,
|
||||
requested, audited, denied,
|
||||
a, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* avc_add_callback - Register a callback for security events.
|
||||
* @callback: callback function
|
||||
* @events: security events
|
||||
* @ssid: source security identifier or %SECSID_WILD
|
||||
* @tsid: target security identifier or %SECSID_WILD
|
||||
* @tclass: target security class
|
||||
* @perms: permissions
|
||||
*
|
||||
* Register a callback function for events in the set @events
|
||||
* related to the SID pair (@ssid, @tsid)
|
||||
* and the permissions @perms, interpreting
|
||||
* @perms based on @tclass. Returns %0 on success or
|
||||
* -%ENOMEM if insufficient memory exists to add the callback.
|
||||
* Register a callback function for events in the set @events.
|
||||
* Returns %0 on success or -%ENOMEM if insufficient memory
|
||||
* exists to add the callback.
|
||||
*/
|
||||
int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 perms,
|
||||
u32 *out_retained),
|
||||
u32 events, u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 perms)
|
||||
int __init avc_add_callback(int (*callback)(u32 event), u32 events)
|
||||
{
|
||||
struct avc_callback_node *c;
|
||||
int rc = 0;
|
||||
|
||||
c = kmalloc(sizeof(*c), GFP_ATOMIC);
|
||||
c = kmalloc(sizeof(*c), GFP_KERNEL);
|
||||
if (!c) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
|
@ -589,9 +511,6 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
|
|||
|
||||
c->callback = callback;
|
||||
c->events = events;
|
||||
c->ssid = ssid;
|
||||
c->tsid = tsid;
|
||||
c->perms = perms;
|
||||
c->next = avc_callbacks;
|
||||
avc_callbacks = c;
|
||||
out:
|
||||
|
@ -731,8 +650,7 @@ int avc_ss_reset(u32 seqno)
|
|||
|
||||
for (c = avc_callbacks; c; c = c->next) {
|
||||
if (c->events & AVC_CALLBACK_RESET) {
|
||||
tmprc = c->callback(AVC_CALLBACK_RESET,
|
||||
0, 0, 0, 0, NULL);
|
||||
tmprc = c->callback(AVC_CALLBACK_RESET);
|
||||
/* save the first error encountered for the return
|
||||
value and continue processing the callbacks */
|
||||
if (!rc)
|
||||
|
|
|
@ -1420,16 +1420,13 @@ static int cred_has_capability(const struct cred *cred,
|
|||
int cap, int audit)
|
||||
{
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct av_decision avd;
|
||||
u16 sclass;
|
||||
u32 sid = cred_sid(cred);
|
||||
u32 av = CAP_TO_MASK(cap);
|
||||
int rc;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, CAP);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.tsk = current;
|
||||
ad.type = LSM_AUDIT_DATA_CAP;
|
||||
ad.u.cap = cap;
|
||||
|
||||
switch (CAP_TO_INDEX(cap)) {
|
||||
|
@ -1488,20 +1485,6 @@ static int inode_has_perm(const struct cred *cred,
|
|||
return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
|
||||
}
|
||||
|
||||
static int inode_has_perm_noadp(const struct cred *cred,
|
||||
struct inode *inode,
|
||||
u32 perms,
|
||||
unsigned flags)
|
||||
{
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, INODE);
|
||||
ad.u.inode = inode;
|
||||
ad.selinux_audit_data = &sad;
|
||||
return inode_has_perm(cred, inode, perms, &ad, flags);
|
||||
}
|
||||
|
||||
/* Same as inode_has_perm, but pass explicit audit data containing
|
||||
the dentry to help the auditing code to more easily generate the
|
||||
pathname if needed. */
|
||||
|
@ -1511,11 +1494,9 @@ static inline int dentry_has_perm(const struct cred *cred,
|
|||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
|
||||
ad.type = LSM_AUDIT_DATA_DENTRY;
|
||||
ad.u.dentry = dentry;
|
||||
ad.selinux_audit_data = &sad;
|
||||
return inode_has_perm(cred, inode, av, &ad, 0);
|
||||
}
|
||||
|
||||
|
@ -1528,11 +1509,9 @@ static inline int path_has_perm(const struct cred *cred,
|
|||
{
|
||||
struct inode *inode = path->dentry->d_inode;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, PATH);
|
||||
ad.type = LSM_AUDIT_DATA_PATH;
|
||||
ad.u.path = *path;
|
||||
ad.selinux_audit_data = &sad;
|
||||
return inode_has_perm(cred, inode, av, &ad, 0);
|
||||
}
|
||||
|
||||
|
@ -1551,13 +1530,11 @@ static int file_has_perm(const struct cred *cred,
|
|||
struct file_security_struct *fsec = file->f_security;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = cred_sid(cred);
|
||||
int rc;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, PATH);
|
||||
ad.type = LSM_AUDIT_DATA_PATH;
|
||||
ad.u.path = file->f_path;
|
||||
ad.selinux_audit_data = &sad;
|
||||
|
||||
if (sid != fsec->sid) {
|
||||
rc = avc_has_perm(sid, fsec->sid,
|
||||
|
@ -1587,7 +1564,6 @@ static int may_create(struct inode *dir,
|
|||
struct superblock_security_struct *sbsec;
|
||||
u32 sid, newsid;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
int rc;
|
||||
|
||||
dsec = dir->i_security;
|
||||
|
@ -1596,9 +1572,8 @@ static int may_create(struct inode *dir,
|
|||
sid = tsec->sid;
|
||||
newsid = tsec->create_sid;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
|
||||
ad.type = LSM_AUDIT_DATA_DENTRY;
|
||||
ad.u.dentry = dentry;
|
||||
ad.selinux_audit_data = &sad;
|
||||
|
||||
rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
|
||||
DIR__ADD_NAME | DIR__SEARCH,
|
||||
|
@ -1643,7 +1618,6 @@ static int may_link(struct inode *dir,
|
|||
{
|
||||
struct inode_security_struct *dsec, *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
u32 av;
|
||||
int rc;
|
||||
|
@ -1651,9 +1625,8 @@ static int may_link(struct inode *dir,
|
|||
dsec = dir->i_security;
|
||||
isec = dentry->d_inode->i_security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
|
||||
ad.type = LSM_AUDIT_DATA_DENTRY;
|
||||
ad.u.dentry = dentry;
|
||||
ad.selinux_audit_data = &sad;
|
||||
|
||||
av = DIR__SEARCH;
|
||||
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
|
||||
|
@ -1688,7 +1661,6 @@ static inline int may_rename(struct inode *old_dir,
|
|||
{
|
||||
struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
u32 av;
|
||||
int old_is_dir, new_is_dir;
|
||||
|
@ -1699,8 +1671,7 @@ static inline int may_rename(struct inode *old_dir,
|
|||
old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
|
||||
new_dsec = new_dir->i_security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_DENTRY;
|
||||
|
||||
ad.u.dentry = old_dentry;
|
||||
rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
|
||||
|
@ -1986,7 +1957,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
|
|||
struct task_security_struct *new_tsec;
|
||||
struct inode_security_struct *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct inode *inode = bprm->file->f_path.dentry->d_inode;
|
||||
int rc;
|
||||
|
||||
|
@ -2032,8 +2002,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
|
|||
return rc;
|
||||
}
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, PATH);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_PATH;
|
||||
ad.u.path = bprm->file->f_path;
|
||||
|
||||
if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
|
||||
|
@ -2123,8 +2092,6 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
|
|||
static inline void flush_unauthorized_files(const struct cred *cred,
|
||||
struct files_struct *files)
|
||||
{
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct file *file, *devnull = NULL;
|
||||
struct tty_struct *tty;
|
||||
struct fdtable *fdt;
|
||||
|
@ -2136,21 +2103,17 @@ static inline void flush_unauthorized_files(const struct cred *cred,
|
|||
spin_lock(&tty_files_lock);
|
||||
if (!list_empty(&tty->tty_files)) {
|
||||
struct tty_file_private *file_priv;
|
||||
struct inode *inode;
|
||||
|
||||
/* Revalidate access to controlling tty.
|
||||
Use inode_has_perm on the tty inode directly rather
|
||||
Use path_has_perm on the tty path directly rather
|
||||
than using file_has_perm, as this particular open
|
||||
file may belong to another process and we are only
|
||||
interested in the inode-based check here. */
|
||||
file_priv = list_first_entry(&tty->tty_files,
|
||||
struct tty_file_private, list);
|
||||
file = file_priv->file;
|
||||
inode = file->f_path.dentry->d_inode;
|
||||
if (inode_has_perm_noadp(cred, inode,
|
||||
FILE__READ | FILE__WRITE, 0)) {
|
||||
if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE))
|
||||
drop_tty = 1;
|
||||
}
|
||||
}
|
||||
spin_unlock(&tty_files_lock);
|
||||
tty_kref_put(tty);
|
||||
|
@ -2160,10 +2123,6 @@ static inline void flush_unauthorized_files(const struct cred *cred,
|
|||
no_tty();
|
||||
|
||||
/* Revalidate access to inherited open files. */
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, INODE);
|
||||
ad.selinux_audit_data = &sad;
|
||||
|
||||
spin_lock(&files->file_lock);
|
||||
for (;;) {
|
||||
unsigned long set, i;
|
||||
|
@ -2500,7 +2459,6 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
|||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
int rc;
|
||||
|
||||
rc = superblock_doinit(sb, data);
|
||||
|
@ -2511,8 +2469,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
|||
if (flags & MS_KERNMOUNT)
|
||||
return 0;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_DENTRY;
|
||||
ad.u.dentry = sb->s_root;
|
||||
return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
|
||||
}
|
||||
|
@ -2521,10 +2478,8 @@ static int selinux_sb_statfs(struct dentry *dentry)
|
|||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_DENTRY;
|
||||
ad.u.dentry = dentry->d_sb->s_root;
|
||||
return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
|
||||
}
|
||||
|
@ -2684,14 +2639,35 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
|
|||
return dentry_has_perm(cred, dentry, FILE__READ);
|
||||
}
|
||||
|
||||
static noinline int audit_inode_permission(struct inode *inode,
|
||||
u32 perms, u32 audited, u32 denied,
|
||||
unsigned flags)
|
||||
{
|
||||
struct common_audit_data ad;
|
||||
struct inode_security_struct *isec = inode->i_security;
|
||||
int rc;
|
||||
|
||||
ad.type = LSM_AUDIT_DATA_INODE;
|
||||
ad.u.inode = inode;
|
||||
|
||||
rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
|
||||
audited, denied, &ad, flags);
|
||||
if (rc)
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int selinux_inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 perms;
|
||||
bool from_access;
|
||||
unsigned flags = mask & MAY_NOT_BLOCK;
|
||||
struct inode_security_struct *isec;
|
||||
u32 sid;
|
||||
struct av_decision avd;
|
||||
int rc, rc2;
|
||||
u32 audited, denied;
|
||||
|
||||
from_access = mask & MAY_ACCESS;
|
||||
mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
|
||||
|
@ -2700,22 +2676,34 @@ static int selinux_inode_permission(struct inode *inode, int mask)
|
|||
if (!mask)
|
||||
return 0;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, INODE);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.u.inode = inode;
|
||||
validate_creds(cred);
|
||||
|
||||
if (from_access)
|
||||
ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS;
|
||||
if (unlikely(IS_PRIVATE(inode)))
|
||||
return 0;
|
||||
|
||||
perms = file_mask_to_av(inode->i_mode, mask);
|
||||
|
||||
return inode_has_perm(cred, inode, perms, &ad, flags);
|
||||
sid = cred_sid(cred);
|
||||
isec = inode->i_security;
|
||||
|
||||
rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
|
||||
audited = avc_audit_required(perms, &avd, rc,
|
||||
from_access ? FILE__AUDIT_ACCESS : 0,
|
||||
&denied);
|
||||
if (likely(!audited))
|
||||
return rc;
|
||||
|
||||
rc2 = audit_inode_permission(inode, perms, audited, denied, flags);
|
||||
if (rc2)
|
||||
return rc2;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
unsigned int ia_valid = iattr->ia_valid;
|
||||
__u32 av = FILE__WRITE;
|
||||
|
||||
/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
|
||||
if (ia_valid & ATTR_FORCE) {
|
||||
|
@ -2729,7 +2717,10 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
|||
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
|
||||
return dentry_has_perm(cred, dentry, FILE__SETATTR);
|
||||
|
||||
return dentry_has_perm(cred, dentry, FILE__WRITE);
|
||||
if (ia_valid & ATTR_SIZE)
|
||||
av |= FILE__OPEN;
|
||||
|
||||
return dentry_has_perm(cred, dentry, av);
|
||||
}
|
||||
|
||||
static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
|
||||
|
@ -2771,7 +2762,6 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
|
|||
struct inode_security_struct *isec = inode->i_security;
|
||||
struct superblock_security_struct *sbsec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 newsid, sid = current_sid();
|
||||
int rc = 0;
|
||||
|
||||
|
@ -2785,8 +2775,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
|
|||
if (!inode_owner_or_capable(inode))
|
||||
return -EPERM;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_DENTRY;
|
||||
ad.u.dentry = dentry;
|
||||
|
||||
rc = avc_has_perm(sid, isec->sid, isec->sclass,
|
||||
|
@ -2796,8 +2785,25 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
|
|||
|
||||
rc = security_context_to_sid(value, size, &newsid);
|
||||
if (rc == -EINVAL) {
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
if (!capable(CAP_MAC_ADMIN)) {
|
||||
struct audit_buffer *ab;
|
||||
size_t audit_size;
|
||||
const char *str;
|
||||
|
||||
/* We strip a nul only if it is at the end, otherwise the
|
||||
* context contains a nul and we should audit that */
|
||||
str = value;
|
||||
if (str[size - 1] == '\0')
|
||||
audit_size = size - 1;
|
||||
else
|
||||
audit_size = size;
|
||||
ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
|
||||
audit_log_format(ab, "op=setxattr invalid_context=");
|
||||
audit_log_n_untrustedstring(ab, value, audit_size);
|
||||
audit_log_end(ab);
|
||||
|
||||
return rc;
|
||||
}
|
||||
rc = security_context_to_sid_force(value, size, &newsid);
|
||||
}
|
||||
if (rc)
|
||||
|
@ -2977,7 +2983,7 @@ static int selinux_file_permission(struct file *file, int mask)
|
|||
|
||||
if (sid == fsec->sid && fsec->isid == isec->sid &&
|
||||
fsec->pseqno == avc_policy_seqno())
|
||||
/* No change since dentry_open check. */
|
||||
/* No change since file_open check. */
|
||||
return 0;
|
||||
|
||||
return selinux_revalidate_file_permission(file, mask);
|
||||
|
@ -3236,15 +3242,13 @@ static int selinux_file_receive(struct file *file)
|
|||
return file_has_perm(cred, file, file_to_av(file));
|
||||
}
|
||||
|
||||
static int selinux_dentry_open(struct file *file, const struct cred *cred)
|
||||
static int selinux_file_open(struct file *file, const struct cred *cred)
|
||||
{
|
||||
struct file_security_struct *fsec;
|
||||
struct inode *inode;
|
||||
struct inode_security_struct *isec;
|
||||
|
||||
inode = file->f_path.dentry->d_inode;
|
||||
fsec = file->f_security;
|
||||
isec = inode->i_security;
|
||||
isec = file->f_path.dentry->d_inode->i_security;
|
||||
/*
|
||||
* Save inode label and policy sequence number
|
||||
* at open-time so that selinux_file_permission
|
||||
|
@ -3262,7 +3266,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
|
|||
* new inode label or new policy.
|
||||
* This check is not redundant - do not remove.
|
||||
*/
|
||||
return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
|
||||
return path_has_perm(cred, &file->f_path, open_file_to_av(file));
|
||||
}
|
||||
|
||||
/* task security operations */
|
||||
|
@ -3381,12 +3385,10 @@ static int selinux_kernel_module_request(char *kmod_name)
|
|||
{
|
||||
u32 sid;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
|
||||
sid = task_sid(current);
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, KMOD);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_KMOD;
|
||||
ad.u.kmod_name = kmod_name;
|
||||
|
||||
return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
|
||||
|
@ -3759,15 +3761,13 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
|
|||
{
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
u32 tsid = task_sid(task);
|
||||
|
||||
if (sksec->sid == SECINITSID_KERNEL)
|
||||
return 0;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->sk = sk;
|
||||
|
||||
|
@ -3847,7 +3847,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
|
|||
char *addrp;
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
struct sockaddr_in *addr4 = NULL;
|
||||
struct sockaddr_in6 *addr6 = NULL;
|
||||
|
@ -3874,8 +3873,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
|
|||
snum, &sid);
|
||||
if (err)
|
||||
goto out;
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->sport = htons(snum);
|
||||
ad.u.net->family = family;
|
||||
|
@ -3909,8 +3907,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->sport = htons(snum);
|
||||
ad.u.net->family = family;
|
||||
|
@ -3945,7 +3942,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
|
|||
if (sksec->sclass == SECCLASS_TCP_SOCKET ||
|
||||
sksec->sclass == SECCLASS_DCCP_SOCKET) {
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
struct sockaddr_in *addr4 = NULL;
|
||||
struct sockaddr_in6 *addr6 = NULL;
|
||||
|
@ -3971,8 +3967,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
|
|||
perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
|
||||
TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->dport = htons(snum);
|
||||
ad.u.net->family = sk->sk_family;
|
||||
|
@ -4064,12 +4059,10 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
|
|||
struct sk_security_struct *sksec_other = other->sk_security;
|
||||
struct sk_security_struct *sksec_new = newsk->sk_security;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
int err;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->sk = other;
|
||||
|
||||
|
@ -4098,11 +4091,9 @@ static int selinux_socket_unix_may_send(struct socket *sock,
|
|||
struct sk_security_struct *ssec = sock->sk->sk_security;
|
||||
struct sk_security_struct *osec = other->sk->sk_security;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->sk = other->sk;
|
||||
|
||||
|
@ -4140,12 +4131,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
|
|||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
u32 sk_sid = sksec->sid;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
char *addrp;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->netif = skb->skb_iif;
|
||||
ad.u.net->family = family;
|
||||
|
@ -4175,7 +4164,6 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||
u16 family = sk->sk_family;
|
||||
u32 sk_sid = sksec->sid;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
char *addrp;
|
||||
u8 secmark_active;
|
||||
|
@ -4200,8 +4188,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||
if (!secmark_active && !peerlbl_active)
|
||||
return 0;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->netif = skb->skb_iif;
|
||||
ad.u.net->family = family;
|
||||
|
@ -4539,7 +4526,6 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
|
|||
char *addrp;
|
||||
u32 peer_sid;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
u8 secmark_active;
|
||||
u8 netlbl_active;
|
||||
|
@ -4557,8 +4543,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
|
|||
if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
|
||||
return NF_DROP;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->netif = ifindex;
|
||||
ad.u.net->family = family;
|
||||
|
@ -4648,7 +4633,6 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
|||
struct sock *sk = skb->sk;
|
||||
struct sk_security_struct *sksec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
char *addrp;
|
||||
u8 proto;
|
||||
|
@ -4657,8 +4641,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
|||
return NF_ACCEPT;
|
||||
sksec = sk->sk_security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->netif = ifindex;
|
||||
ad.u.net->family = family;
|
||||
|
@ -4683,7 +4666,6 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
|||
u32 peer_sid;
|
||||
struct sock *sk;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
struct lsm_network_audit net = {0,};
|
||||
char *addrp;
|
||||
u8 secmark_active;
|
||||
|
@ -4730,8 +4712,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
|||
secmark_perm = PACKET__SEND;
|
||||
}
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->netif = ifindex;
|
||||
ad.u.net->family = family;
|
||||
|
@ -4849,13 +4830,11 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
|
|||
{
|
||||
struct ipc_security_struct *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
|
||||
isec = ipc_perms->security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = ipc_perms->key;
|
||||
|
||||
return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
|
||||
|
@ -4876,7 +4855,6 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
|
|||
{
|
||||
struct ipc_security_struct *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
int rc;
|
||||
|
||||
|
@ -4886,8 +4864,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
|
|||
|
||||
isec = msq->q_perm.security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = msq->q_perm.key;
|
||||
|
||||
rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
|
||||
|
@ -4908,13 +4885,11 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
|
|||
{
|
||||
struct ipc_security_struct *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
|
||||
isec = msq->q_perm.security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = msq->q_perm.key;
|
||||
|
||||
return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
|
||||
|
@ -4954,7 +4929,6 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
|
|||
struct ipc_security_struct *isec;
|
||||
struct msg_security_struct *msec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
int rc;
|
||||
|
||||
|
@ -4975,8 +4949,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
|
|||
return rc;
|
||||
}
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = msq->q_perm.key;
|
||||
|
||||
/* Can this process write to the queue? */
|
||||
|
@ -5001,15 +4974,13 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
|
|||
struct ipc_security_struct *isec;
|
||||
struct msg_security_struct *msec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = task_sid(target);
|
||||
int rc;
|
||||
|
||||
isec = msq->q_perm.security;
|
||||
msec = msg->security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = msq->q_perm.key;
|
||||
|
||||
rc = avc_has_perm(sid, isec->sid,
|
||||
|
@ -5025,7 +4996,6 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
|
|||
{
|
||||
struct ipc_security_struct *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
int rc;
|
||||
|
||||
|
@ -5035,8 +5005,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
|
|||
|
||||
isec = shp->shm_perm.security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = shp->shm_perm.key;
|
||||
|
||||
rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
|
||||
|
@ -5057,13 +5026,11 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
|
|||
{
|
||||
struct ipc_security_struct *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
|
||||
isec = shp->shm_perm.security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = shp->shm_perm.key;
|
||||
|
||||
return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
|
||||
|
@ -5121,7 +5088,6 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
|
|||
{
|
||||
struct ipc_security_struct *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
int rc;
|
||||
|
||||
|
@ -5131,8 +5097,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
|
|||
|
||||
isec = sma->sem_perm.security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = sma->sem_perm.key;
|
||||
|
||||
rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
|
||||
|
@ -5153,13 +5118,11 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg)
|
|||
{
|
||||
struct ipc_security_struct *isec;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
u32 sid = current_sid();
|
||||
|
||||
isec = sma->sem_perm.security;
|
||||
|
||||
COMMON_AUDIT_DATA_INIT(&ad, IPC);
|
||||
ad.selinux_audit_data = &sad;
|
||||
ad.type = LSM_AUDIT_DATA_IPC;
|
||||
ad.u.ipc_id = sma->sem_perm.key;
|
||||
|
||||
return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
|
||||
|
@ -5339,8 +5302,23 @@ static int selinux_setprocattr(struct task_struct *p,
|
|||
}
|
||||
error = security_context_to_sid(value, size, &sid);
|
||||
if (error == -EINVAL && !strcmp(name, "fscreate")) {
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
if (!capable(CAP_MAC_ADMIN)) {
|
||||
struct audit_buffer *ab;
|
||||
size_t audit_size;
|
||||
|
||||
/* We strip a nul only if it is at the end, otherwise the
|
||||
* context contains a nul and we should audit that */
|
||||
if (str[size - 1] == '\0')
|
||||
audit_size = size - 1;
|
||||
else
|
||||
audit_size = size;
|
||||
ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR);
|
||||
audit_log_format(ab, "op=fscreate invalid_context=");
|
||||
audit_log_n_untrustedstring(ab, value, audit_size);
|
||||
audit_log_end(ab);
|
||||
|
||||
return error;
|
||||
}
|
||||
error = security_context_to_sid_force(value, size,
|
||||
&sid);
|
||||
}
|
||||
|
@ -5600,7 +5578,7 @@ static struct security_operations selinux_ops = {
|
|||
.file_send_sigiotask = selinux_file_send_sigiotask,
|
||||
.file_receive = selinux_file_receive,
|
||||
|
||||
.dentry_open = selinux_dentry_open,
|
||||
.file_open = selinux_file_open,
|
||||
|
||||
.task_create = selinux_task_create,
|
||||
.cred_alloc_blank = selinux_cred_alloc_blank,
|
||||
|
|
|
@ -49,7 +49,7 @@ struct avc_cache_stats {
|
|||
/*
|
||||
* We only need this data after we have decided to send an audit message.
|
||||
*/
|
||||
struct selinux_late_audit_data {
|
||||
struct selinux_audit_data {
|
||||
u32 ssid;
|
||||
u32 tsid;
|
||||
u16 tclass;
|
||||
|
@ -59,29 +59,87 @@ struct selinux_late_audit_data {
|
|||
int result;
|
||||
};
|
||||
|
||||
/*
|
||||
* We collect this at the beginning or during an selinux security operation
|
||||
*/
|
||||
struct selinux_audit_data {
|
||||
/*
|
||||
* auditdeny is a bit tricky and unintuitive. See the
|
||||
* comments in avc.c for it's meaning and usage.
|
||||
*/
|
||||
u32 auditdeny;
|
||||
struct selinux_late_audit_data *slad;
|
||||
};
|
||||
|
||||
/*
|
||||
* AVC operations
|
||||
*/
|
||||
|
||||
void __init avc_init(void);
|
||||
|
||||
int avc_audit(u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 requested,
|
||||
struct av_decision *avd,
|
||||
int result,
|
||||
struct common_audit_data *a, unsigned flags);
|
||||
static inline u32 avc_audit_required(u32 requested,
|
||||
struct av_decision *avd,
|
||||
int result,
|
||||
u32 auditdeny,
|
||||
u32 *deniedp)
|
||||
{
|
||||
u32 denied, audited;
|
||||
denied = requested & ~avd->allowed;
|
||||
if (unlikely(denied)) {
|
||||
audited = denied & avd->auditdeny;
|
||||
/*
|
||||
* auditdeny is TRICKY! Setting a bit in
|
||||
* this field means that ANY denials should NOT be audited if
|
||||
* the policy contains an explicit dontaudit rule for that
|
||||
* permission. Take notice that this is unrelated to the
|
||||
* actual permissions that were denied. As an example lets
|
||||
* assume:
|
||||
*
|
||||
* denied == READ
|
||||
* avd.auditdeny & ACCESS == 0 (not set means explicit rule)
|
||||
* auditdeny & ACCESS == 1
|
||||
*
|
||||
* We will NOT audit the denial even though the denied
|
||||
* permission was READ and the auditdeny checks were for
|
||||
* ACCESS
|
||||
*/
|
||||
if (auditdeny && !(auditdeny & avd->auditdeny))
|
||||
audited = 0;
|
||||
} else if (result)
|
||||
audited = denied = requested;
|
||||
else
|
||||
audited = requested & avd->auditallow;
|
||||
*deniedp = denied;
|
||||
return audited;
|
||||
}
|
||||
|
||||
int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
|
||||
u32 requested, u32 audited, u32 denied,
|
||||
struct common_audit_data *a,
|
||||
unsigned flags);
|
||||
|
||||
/**
|
||||
* avc_audit - Audit the granting or denial of permissions.
|
||||
* @ssid: source security identifier
|
||||
* @tsid: target security identifier
|
||||
* @tclass: target security class
|
||||
* @requested: requested permissions
|
||||
* @avd: access vector decisions
|
||||
* @result: result from avc_has_perm_noaudit
|
||||
* @a: auxiliary audit data
|
||||
* @flags: VFS walk flags
|
||||
*
|
||||
* Audit the granting or denial of permissions in accordance
|
||||
* with the policy. This function is typically called by
|
||||
* avc_has_perm() after a permission check, but can also be
|
||||
* called directly by callers who use avc_has_perm_noaudit()
|
||||
* in order to separate the permission check from the auditing.
|
||||
* For example, this separation is useful when the permission check must
|
||||
* 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,
|
||||
u16 tclass, u32 requested,
|
||||
struct av_decision *avd,
|
||||
int result,
|
||||
struct common_audit_data *a, unsigned flags)
|
||||
{
|
||||
u32 audited, denied;
|
||||
audited = avc_audit_required(requested, avd, result, 0, &denied);
|
||||
if (likely(!audited))
|
||||
return 0;
|
||||
return slow_avc_audit(ssid, tsid, tclass,
|
||||
requested, audited, denied,
|
||||
a, flags);
|
||||
}
|
||||
|
||||
#define AVC_STRICT 1 /* Ignore permissive mode. */
|
||||
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
|
||||
|
@ -112,11 +170,7 @@ u32 avc_policy_seqno(void);
|
|||
#define AVC_CALLBACK_AUDITDENY_ENABLE 64
|
||||
#define AVC_CALLBACK_AUDITDENY_DISABLE 128
|
||||
|
||||
int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 perms,
|
||||
u32 *out_retained),
|
||||
u32 events, u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 perms);
|
||||
int avc_add_callback(int (*callback)(u32 event), u32 events);
|
||||
|
||||
/* Exported to selinuxfs */
|
||||
int avc_get_hash_stats(char *page);
|
||||
|
|
|
@ -31,13 +31,15 @@
|
|||
#define POLICYDB_VERSION_BOUNDARY 24
|
||||
#define POLICYDB_VERSION_FILENAME_TRANS 25
|
||||
#define POLICYDB_VERSION_ROLETRANS 26
|
||||
#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
|
||||
#define POLICYDB_VERSION_DEFAULT_TYPE 28
|
||||
|
||||
/* Range of policy versions we understand*/
|
||||
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
||||
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
|
||||
#else
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE
|
||||
#endif
|
||||
|
||||
/* Mask for just the mount related flags */
|
||||
|
|
|
@ -252,8 +252,7 @@ static void sel_netif_flush(void)
|
|||
spin_unlock_bh(&sel_netif_lock);
|
||||
}
|
||||
|
||||
static int sel_netif_avc_callback(u32 event, u32 ssid, u32 tsid,
|
||||
u16 class, u32 perms, u32 *retained)
|
||||
static int sel_netif_avc_callback(u32 event)
|
||||
{
|
||||
if (event == AVC_CALLBACK_RESET) {
|
||||
sel_netif_flush();
|
||||
|
@ -292,8 +291,7 @@ static __init int sel_netif_init(void)
|
|||
|
||||
register_netdevice_notifier(&sel_netif_netdev_notifier);
|
||||
|
||||
err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET,
|
||||
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
|
||||
err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET);
|
||||
if (err)
|
||||
panic("avc_add_callback() failed, error %d\n", err);
|
||||
|
||||
|
|
|
@ -297,8 +297,7 @@ static void sel_netnode_flush(void)
|
|||
spin_unlock_bh(&sel_netnode_lock);
|
||||
}
|
||||
|
||||
static int sel_netnode_avc_callback(u32 event, u32 ssid, u32 tsid,
|
||||
u16 class, u32 perms, u32 *retained)
|
||||
static int sel_netnode_avc_callback(u32 event)
|
||||
{
|
||||
if (event == AVC_CALLBACK_RESET) {
|
||||
sel_netnode_flush();
|
||||
|
@ -320,8 +319,7 @@ static __init int sel_netnode_init(void)
|
|||
sel_netnode_hash[iter].size = 0;
|
||||
}
|
||||
|
||||
ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET,
|
||||
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
|
||||
ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET);
|
||||
if (ret != 0)
|
||||
panic("avc_add_callback() failed, error %d\n", ret);
|
||||
|
||||
|
|
|
@ -234,8 +234,7 @@ static void sel_netport_flush(void)
|
|||
spin_unlock_bh(&sel_netport_lock);
|
||||
}
|
||||
|
||||
static int sel_netport_avc_callback(u32 event, u32 ssid, u32 tsid,
|
||||
u16 class, u32 perms, u32 *retained)
|
||||
static int sel_netport_avc_callback(u32 event)
|
||||
{
|
||||
if (event == AVC_CALLBACK_RESET) {
|
||||
sel_netport_flush();
|
||||
|
@ -257,8 +256,7 @@ static __init int sel_netport_init(void)
|
|||
sel_netport_hash[iter].size = 0;
|
||||
}
|
||||
|
||||
ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET,
|
||||
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
|
||||
ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET);
|
||||
if (ret != 0)
|
||||
panic("avc_add_callback() failed, error %d\n", ret);
|
||||
|
||||
|
|
|
@ -496,6 +496,7 @@ static const struct file_operations sel_policy_ops = {
|
|||
.read = sel_read_policy,
|
||||
.mmap = sel_mmap_policy,
|
||||
.release = sel_release_policy,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
static ssize_t sel_write_load(struct file *file, const char __user *buf,
|
||||
|
@ -1232,6 +1233,7 @@ static int sel_make_bools(void)
|
|||
kfree(bool_pending_names[i]);
|
||||
kfree(bool_pending_names);
|
||||
kfree(bool_pending_values);
|
||||
bool_num = 0;
|
||||
bool_pending_names = NULL;
|
||||
bool_pending_values = NULL;
|
||||
|
||||
|
@ -1532,11 +1534,6 @@ static int sel_make_initcon_files(struct dentry *dir)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int sel_div(unsigned long a, unsigned long b)
|
||||
{
|
||||
return a / b - (a % b < 0);
|
||||
}
|
||||
|
||||
static inline unsigned long sel_class_to_ino(u16 class)
|
||||
{
|
||||
return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;
|
||||
|
@ -1544,7 +1541,7 @@ static inline unsigned long sel_class_to_ino(u16 class)
|
|||
|
||||
static inline u16 sel_ino_to_class(unsigned long ino)
|
||||
{
|
||||
return sel_div(ino & SEL_INO_MASK, SEL_VEC_MAX + 1);
|
||||
return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1);
|
||||
}
|
||||
|
||||
static inline unsigned long sel_perm_to_ino(u16 class, u32 perm)
|
||||
|
@ -1831,7 +1828,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
|
|||
[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
|
||||
[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
|
||||
[SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
|
||||
[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR},
|
||||
[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
|
||||
/* last one */ {""}
|
||||
};
|
||||
ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
|
||||
|
|
|
@ -74,6 +74,26 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets both levels in the MLS range of 'dst' to the high level of 'src'.
|
||||
*/
|
||||
static inline int mls_context_cpy_high(struct context *dst, struct context *src)
|
||||
{
|
||||
int rc;
|
||||
|
||||
dst->range.level[0].sens = src->range.level[1].sens;
|
||||
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[1].cat);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
dst->range.level[1].sens = src->range.level[1].sens;
|
||||
rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
|
||||
if (rc)
|
||||
ebitmap_destroy(&dst->range.level[0].cat);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int mls_context_cmp(struct context *c1, struct context *c2)
|
||||
{
|
||||
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
|
||||
|
|
|
@ -517,6 +517,8 @@ int mls_compute_sid(struct context *scontext,
|
|||
{
|
||||
struct range_trans rtr;
|
||||
struct mls_range *r;
|
||||
struct class_datum *cladatum;
|
||||
int default_range = 0;
|
||||
|
||||
if (!policydb.mls_enabled)
|
||||
return 0;
|
||||
|
@ -530,6 +532,28 @@ int mls_compute_sid(struct context *scontext,
|
|||
r = hashtab_search(policydb.range_tr, &rtr);
|
||||
if (r)
|
||||
return mls_range_set(newcontext, r);
|
||||
|
||||
if (tclass && tclass <= policydb.p_classes.nprim) {
|
||||
cladatum = policydb.class_val_to_struct[tclass - 1];
|
||||
if (cladatum)
|
||||
default_range = cladatum->default_range;
|
||||
}
|
||||
|
||||
switch (default_range) {
|
||||
case DEFAULT_SOURCE_LOW:
|
||||
return mls_context_cpy_low(newcontext, scontext);
|
||||
case DEFAULT_SOURCE_HIGH:
|
||||
return mls_context_cpy_high(newcontext, scontext);
|
||||
case DEFAULT_SOURCE_LOW_HIGH:
|
||||
return mls_context_cpy(newcontext, scontext);
|
||||
case DEFAULT_TARGET_LOW:
|
||||
return mls_context_cpy_low(newcontext, tcontext);
|
||||
case DEFAULT_TARGET_HIGH:
|
||||
return mls_context_cpy_high(newcontext, tcontext);
|
||||
case DEFAULT_TARGET_LOW_HIGH:
|
||||
return mls_context_cpy(newcontext, tcontext);
|
||||
}
|
||||
|
||||
/* Fallthrough */
|
||||
case AVTAB_CHANGE:
|
||||
if ((tclass == policydb.process_class) || (sock == true))
|
||||
|
|
|
@ -133,6 +133,16 @@ static struct policydb_compat_info policydb_compat[] = {
|
|||
.sym_num = SYM_NUM,
|
||||
.ocon_num = OCON_NUM,
|
||||
},
|
||||
{
|
||||
.version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
|
||||
.sym_num = SYM_NUM,
|
||||
.ocon_num = OCON_NUM,
|
||||
},
|
||||
{
|
||||
.version = POLICYDB_VERSION_DEFAULT_TYPE,
|
||||
.sym_num = SYM_NUM,
|
||||
.ocon_num = OCON_NUM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct policydb_compat_info *policydb_lookup_compat(int version)
|
||||
|
@ -1306,6 +1316,23 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
|||
goto bad;
|
||||
}
|
||||
|
||||
if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
|
||||
rc = next_entry(buf, fp, sizeof(u32) * 3);
|
||||
if (rc)
|
||||
goto bad;
|
||||
|
||||
cladatum->default_user = le32_to_cpu(buf[0]);
|
||||
cladatum->default_role = le32_to_cpu(buf[1]);
|
||||
cladatum->default_range = le32_to_cpu(buf[2]);
|
||||
}
|
||||
|
||||
if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) {
|
||||
rc = next_entry(buf, fp, sizeof(u32) * 1);
|
||||
if (rc)
|
||||
goto bad;
|
||||
cladatum->default_type = le32_to_cpu(buf[0]);
|
||||
}
|
||||
|
||||
rc = hashtab_insert(h, key, cladatum);
|
||||
if (rc)
|
||||
goto bad;
|
||||
|
@ -2832,6 +2859,23 @@ static int class_write(void *vkey, void *datum, void *ptr)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) {
|
||||
buf[0] = cpu_to_le32(cladatum->default_user);
|
||||
buf[1] = cpu_to_le32(cladatum->default_role);
|
||||
buf[2] = cpu_to_le32(cladatum->default_range);
|
||||
|
||||
rc = put_entry(buf, sizeof(uint32_t), 3, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) {
|
||||
buf[0] = cpu_to_le32(cladatum->default_type);
|
||||
rc = put_entry(buf, sizeof(uint32_t), 1, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,20 @@ struct class_datum {
|
|||
struct symtab permissions; /* class-specific permission symbol table */
|
||||
struct constraint_node *constraints; /* constraints on class permissions */
|
||||
struct constraint_node *validatetrans; /* special transition rules */
|
||||
/* Options how a new object user, role, and type should be decided */
|
||||
#define DEFAULT_SOURCE 1
|
||||
#define DEFAULT_TARGET 2
|
||||
char default_user;
|
||||
char default_role;
|
||||
char default_type;
|
||||
/* Options how a new object range should be decided */
|
||||
#define DEFAULT_SOURCE_LOW 1
|
||||
#define DEFAULT_SOURCE_HIGH 2
|
||||
#define DEFAULT_SOURCE_LOW_HIGH 3
|
||||
#define DEFAULT_TARGET_LOW 4
|
||||
#define DEFAULT_TARGET_HIGH 5
|
||||
#define DEFAULT_TARGET_LOW_HIGH 6
|
||||
char default_range;
|
||||
};
|
||||
|
||||
/* Role attributes */
|
||||
|
|
|
@ -1018,9 +1018,11 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
|
|||
|
||||
if (context->len) {
|
||||
*scontext_len = context->len;
|
||||
*scontext = kstrdup(context->str, GFP_ATOMIC);
|
||||
if (!(*scontext))
|
||||
return -ENOMEM;
|
||||
if (scontext) {
|
||||
*scontext = kstrdup(context->str, GFP_ATOMIC);
|
||||
if (!(*scontext))
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1389,6 +1391,7 @@ static int security_compute_sid(u32 ssid,
|
|||
u32 *out_sid,
|
||||
bool kern)
|
||||
{
|
||||
struct class_datum *cladatum = NULL;
|
||||
struct context *scontext = NULL, *tcontext = NULL, newcontext;
|
||||
struct role_trans *roletr = NULL;
|
||||
struct avtab_key avkey;
|
||||
|
@ -1437,12 +1440,20 @@ static int security_compute_sid(u32 ssid,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (tclass && tclass <= policydb.p_classes.nprim)
|
||||
cladatum = policydb.class_val_to_struct[tclass - 1];
|
||||
|
||||
/* Set the user identity. */
|
||||
switch (specified) {
|
||||
case AVTAB_TRANSITION:
|
||||
case AVTAB_CHANGE:
|
||||
/* Use the process user identity. */
|
||||
newcontext.user = scontext->user;
|
||||
if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
|
||||
newcontext.user = tcontext->user;
|
||||
} else {
|
||||
/* notice this gets both DEFAULT_SOURCE and unset */
|
||||
/* Use the process user identity. */
|
||||
newcontext.user = scontext->user;
|
||||
}
|
||||
break;
|
||||
case AVTAB_MEMBER:
|
||||
/* Use the related object owner. */
|
||||
|
@ -1450,16 +1461,31 @@ static int security_compute_sid(u32 ssid,
|
|||
break;
|
||||
}
|
||||
|
||||
/* Set the role and type to default values. */
|
||||
if ((tclass == policydb.process_class) || (sock == true)) {
|
||||
/* Use the current role and type of process. */
|
||||
/* Set the role to default values. */
|
||||
if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
|
||||
newcontext.role = scontext->role;
|
||||
newcontext.type = scontext->type;
|
||||
} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
|
||||
newcontext.role = tcontext->role;
|
||||
} else {
|
||||
/* Use the well-defined object role. */
|
||||
newcontext.role = OBJECT_R_VAL;
|
||||
/* Use the type of the related object. */
|
||||
if ((tclass == policydb.process_class) || (sock == true))
|
||||
newcontext.role = scontext->role;
|
||||
else
|
||||
newcontext.role = OBJECT_R_VAL;
|
||||
}
|
||||
|
||||
/* Set the type to default values. */
|
||||
if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
|
||||
newcontext.type = scontext->type;
|
||||
} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
|
||||
newcontext.type = tcontext->type;
|
||||
} else {
|
||||
if ((tclass == policydb.process_class) || (sock == true)) {
|
||||
/* Use the type of process. */
|
||||
newcontext.type = scontext->type;
|
||||
} else {
|
||||
/* Use the type of the related object. */
|
||||
newcontext.type = tcontext->type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for a type transition/member/change rule. */
|
||||
|
@ -3018,8 +3044,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
|
|||
|
||||
static int (*aurule_callback)(void) = audit_update_lsm_rules;
|
||||
|
||||
static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
|
||||
u16 class, u32 perms, u32 *retained)
|
||||
static int aurule_avc_callback(u32 event)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
|
@ -3032,8 +3057,7 @@ static int __init aurule_init(void)
|
|||
{
|
||||
int err;
|
||||
|
||||
err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET,
|
||||
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
|
||||
err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
|
||||
if (err)
|
||||
panic("avc_add_callback() failed, error %d\n", err);
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@ void smack_log(char *subject_label, char *object_label,
|
|||
static inline void smk_ad_init(struct smk_audit_info *a, const char *func,
|
||||
char type)
|
||||
{
|
||||
memset(a, 0, sizeof(*a));
|
||||
memset(&a->sad, 0, sizeof(a->sad));
|
||||
a->a.type = type;
|
||||
a->a.smack_audit_data = &a->sad;
|
||||
a->a.smack_audit_data->function = func;
|
||||
|
|
|
@ -1359,7 +1359,7 @@ static int smack_file_receive(struct file *file)
|
|||
}
|
||||
|
||||
/**
|
||||
* smack_dentry_open - Smack dentry open processing
|
||||
* smack_file_open - Smack dentry open processing
|
||||
* @file: the object
|
||||
* @cred: unused
|
||||
*
|
||||
|
@ -1367,7 +1367,7 @@ static int smack_file_receive(struct file *file)
|
|||
*
|
||||
* Returns 0
|
||||
*/
|
||||
static int smack_dentry_open(struct file *file, const struct cred *cred)
|
||||
static int smack_file_open(struct file *file, const struct cred *cred)
|
||||
{
|
||||
struct inode_smack *isp = file->f_path.dentry->d_inode->i_security;
|
||||
|
||||
|
@ -3487,7 +3487,7 @@ struct security_operations smack_ops = {
|
|||
.file_send_sigiotask = smack_file_send_sigiotask,
|
||||
.file_receive = smack_file_receive,
|
||||
|
||||
.dentry_open = smack_dentry_open,
|
||||
.file_open = smack_file_open,
|
||||
|
||||
.cred_alloc_blank = smack_cred_alloc_blank,
|
||||
.cred_free = smack_cred_free,
|
||||
|
|
|
@ -319,14 +319,14 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
|
|||
}
|
||||
|
||||
/**
|
||||
* tomoyo_dentry_open - Target for security_dentry_open().
|
||||
* tomoyo_file_open - Target for security_file_open().
|
||||
*
|
||||
* @f: Pointer to "struct file".
|
||||
* @cred: Pointer to "struct cred".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
|
||||
static int tomoyo_file_open(struct file *f, const struct cred *cred)
|
||||
{
|
||||
int flags = f->f_flags;
|
||||
/* Don't check read permission here if called from do_execve(). */
|
||||
|
@ -510,7 +510,7 @@ static struct security_operations tomoyo_security_ops = {
|
|||
.bprm_set_creds = tomoyo_bprm_set_creds,
|
||||
.bprm_check_security = tomoyo_bprm_check_security,
|
||||
.file_fcntl = tomoyo_file_fcntl,
|
||||
.dentry_open = tomoyo_dentry_open,
|
||||
.file_open = tomoyo_file_open,
|
||||
.path_truncate = tomoyo_path_truncate,
|
||||
.path_unlink = tomoyo_path_unlink,
|
||||
.path_mkdir = tomoyo_path_mkdir,
|
||||
|
|
Loading…
Reference in a new issue