Commit 3b3b0e4f authored by Eric Paris's avatar Eric Paris Committed by Linus Torvalds

LSM: shrink sizeof LSM specific portion of common_audit_data

Linus found that the gigantic size of the common audit data caused a big
perf hit on something as simple as running stat() in a loop.  This patch
requires LSMs to declare the LSM specific portion separately rather than
doing it in a union.  Thus each LSM can be responsible for shrinking their
portion and don't have to pay a penalty just because other LSMs have a
bigger space requirement.
Signed-off-by: default avatarEric Paris <eparis@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 95694129
...@@ -72,61 +72,15 @@ struct common_audit_data { ...@@ -72,61 +72,15 @@ struct common_audit_data {
/* this union contains LSM specific data */ /* this union contains LSM specific data */
union { union {
#ifdef CONFIG_SECURITY_SMACK #ifdef CONFIG_SECURITY_SMACK
/* SMACK data */ struct smack_audit_data *smack_audit_data;
struct smack_audit_data {
const char *function;
char *subject;
char *object;
char *request;
int result;
} smack_audit_data;
#endif #endif
#ifdef CONFIG_SECURITY_SELINUX #ifdef CONFIG_SECURITY_SELINUX
/* SELinux data */ struct selinux_audit_data *selinux_audit_data;
struct {
u32 ssid;
u32 tsid;
u16 tclass;
u32 requested;
u32 audited;
u32 denied;
/*
* auditdeny is a bit tricky and unintuitive. See the
* comments in avc.c for it's meaning and usage.
*/
u32 auditdeny;
struct av_decision *avd;
int result;
} selinux_audit_data;
#endif #endif
#ifdef CONFIG_SECURITY_APPARMOR #ifdef CONFIG_SECURITY_APPARMOR
struct { struct apparmor_audit_data *apparmor_audit_data;
int error;
int op;
int type;
void *profile;
const char *name;
const char *info;
union {
void *target;
struct {
long pos;
void *target;
} iface;
struct {
int rlim;
unsigned long max;
} rlim;
struct {
const char *target;
u32 request;
u32 denied;
uid_t ouid;
} fs;
};
} apparmor_audit_data;
#endif #endif
}; }; /* per LSM data pointer union */
/* these callback will be implemented by a specific LSM */ /* these callback will be implemented by a specific LSM */
void (*lsm_pre_audit)(struct audit_buffer *, void *); void (*lsm_pre_audit)(struct audit_buffer *, void *);
void (*lsm_post_audit)(struct audit_buffer *, void *); void (*lsm_post_audit)(struct audit_buffer *, void *);
......
...@@ -115,23 +115,23 @@ static void audit_pre(struct audit_buffer *ab, void *ca) ...@@ -115,23 +115,23 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
if (aa_g_audit_header) { if (aa_g_audit_header) {
audit_log_format(ab, "apparmor="); audit_log_format(ab, "apparmor=");
audit_log_string(ab, aa_audit_type[sa->aad.type]); audit_log_string(ab, aa_audit_type[sa->aad->type]);
} }
if (sa->aad.op) { if (sa->aad->op) {
audit_log_format(ab, " operation="); audit_log_format(ab, " operation=");
audit_log_string(ab, op_table[sa->aad.op]); audit_log_string(ab, op_table[sa->aad->op]);
} }
if (sa->aad.info) { if (sa->aad->info) {
audit_log_format(ab, " info="); audit_log_format(ab, " info=");
audit_log_string(ab, sa->aad.info); audit_log_string(ab, sa->aad->info);
if (sa->aad.error) if (sa->aad->error)
audit_log_format(ab, " error=%d", sa->aad.error); audit_log_format(ab, " error=%d", sa->aad->error);
} }
if (sa->aad.profile) { if (sa->aad->profile) {
struct aa_profile *profile = sa->aad.profile; struct aa_profile *profile = sa->aad->profile;
pid_t pid; pid_t pid;
rcu_read_lock(); rcu_read_lock();
pid = rcu_dereference(tsk->real_parent)->pid; pid = rcu_dereference(tsk->real_parent)->pid;
...@@ -145,9 +145,9 @@ static void audit_pre(struct audit_buffer *ab, void *ca) ...@@ -145,9 +145,9 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
audit_log_untrustedstring(ab, profile->base.hname); audit_log_untrustedstring(ab, profile->base.hname);
} }
if (sa->aad.name) { if (sa->aad->name) {
audit_log_format(ab, " name="); audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, sa->aad.name); audit_log_untrustedstring(ab, sa->aad->name);
} }
} }
...@@ -159,7 +159,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca) ...@@ -159,7 +159,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
void aa_audit_msg(int type, struct common_audit_data *sa, void aa_audit_msg(int type, struct common_audit_data *sa,
void (*cb) (struct audit_buffer *, void *)) void (*cb) (struct audit_buffer *, void *))
{ {
sa->aad.type = type; sa->aad->type = type;
sa->lsm_pre_audit = audit_pre; sa->lsm_pre_audit = audit_pre;
sa->lsm_post_audit = cb; sa->lsm_post_audit = cb;
common_lsm_audit(sa); common_lsm_audit(sa);
...@@ -184,7 +184,7 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, ...@@ -184,7 +184,7 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
BUG_ON(!profile); BUG_ON(!profile);
if (type == AUDIT_APPARMOR_AUTO) { if (type == AUDIT_APPARMOR_AUTO) {
if (likely(!sa->aad.error)) { if (likely(!sa->aad->error)) {
if (AUDIT_MODE(profile) != AUDIT_ALL) if (AUDIT_MODE(profile) != AUDIT_ALL)
return 0; return 0;
type = AUDIT_APPARMOR_AUDIT; type = AUDIT_APPARMOR_AUDIT;
...@@ -196,21 +196,21 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, ...@@ -196,21 +196,21 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
if (AUDIT_MODE(profile) == AUDIT_QUIET || if (AUDIT_MODE(profile) == AUDIT_QUIET ||
(type == AUDIT_APPARMOR_DENIED && (type == AUDIT_APPARMOR_DENIED &&
AUDIT_MODE(profile) == AUDIT_QUIET)) AUDIT_MODE(profile) == AUDIT_QUIET))
return sa->aad.error; return sa->aad->error;
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
type = AUDIT_APPARMOR_KILL; type = AUDIT_APPARMOR_KILL;
if (!unconfined(profile)) if (!unconfined(profile))
sa->aad.profile = profile; sa->aad->profile = profile;
aa_audit_msg(type, sa, cb); aa_audit_msg(type, sa, cb);
if (sa->aad.type == AUDIT_APPARMOR_KILL) 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->tsk ? sa->tsk : current);
if (sa->aad.type == AUDIT_APPARMOR_ALLOWED) if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
return complain_error(sa->aad.error); return complain_error(sa->aad->error);
return sa->aad.error; return sa->aad->error;
} }
...@@ -64,11 +64,13 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task, ...@@ -64,11 +64,13 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task,
struct audit_cache *ent; struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO; int type = AUDIT_APPARMOR_AUTO;
struct common_audit_data sa; struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
COMMON_AUDIT_DATA_INIT(&sa, CAP); COMMON_AUDIT_DATA_INIT(&sa, CAP);
sa.aad = &aad;
sa.tsk = task; sa.tsk = task;
sa.u.cap = cap; sa.u.cap = cap;
sa.aad.op = OP_CAPABLE; sa.aad->op = OP_CAPABLE;
sa.aad.error = error; sa.aad->error = error;
if (likely(!error)) { if (likely(!error)) {
/* test if auditing is being forced */ /* test if auditing is being forced */
......
...@@ -67,22 +67,22 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) ...@@ -67,22 +67,22 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
struct common_audit_data *sa = va; struct common_audit_data *sa = va;
uid_t fsuid = current_fsuid(); uid_t fsuid = current_fsuid();
if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) { if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
audit_log_format(ab, " requested_mask="); audit_log_format(ab, " requested_mask=");
audit_file_mask(ab, sa->aad.fs.request); audit_file_mask(ab, sa->aad->fs.request);
} }
if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) { if (sa->aad->fs.denied & AA_AUDIT_FILE_MASK) {
audit_log_format(ab, " denied_mask="); audit_log_format(ab, " denied_mask=");
audit_file_mask(ab, sa->aad.fs.denied); audit_file_mask(ab, sa->aad->fs.denied);
} }
if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) { if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
audit_log_format(ab, " fsuid=%d", fsuid); audit_log_format(ab, " fsuid=%d", fsuid);
audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid); audit_log_format(ab, " ouid=%d", sa->aad->fs.ouid);
} }
if (sa->aad.fs.target) { if (sa->aad->fs.target) {
audit_log_format(ab, " target="); audit_log_format(ab, " target=");
audit_log_untrustedstring(ab, sa->aad.fs.target); audit_log_untrustedstring(ab, sa->aad->fs.target);
} }
} }
...@@ -107,45 +107,47 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, ...@@ -107,45 +107,47 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
{ {
int type = AUDIT_APPARMOR_AUTO; int type = AUDIT_APPARMOR_AUTO;
struct common_audit_data sa; struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
COMMON_AUDIT_DATA_INIT(&sa, NONE); COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = op, sa.aad = &aad;
sa.aad.fs.request = request; aad.op = op,
sa.aad.name = name; aad.fs.request = request;
sa.aad.fs.target = target; aad.name = name;
sa.aad.fs.ouid = ouid; aad.fs.target = target;
sa.aad.info = info; aad.fs.ouid = ouid;
sa.aad.error = error; aad.info = info;
aad.error = error;
if (likely(!sa.aad.error)) {
if (likely(!sa.aad->error)) {
u32 mask = perms->audit; u32 mask = perms->audit;
if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
mask = 0xffff; mask = 0xffff;
/* mask off perms that are not being force audited */ /* mask off perms that are not being force audited */
sa.aad.fs.request &= mask; sa.aad->fs.request &= mask;
if (likely(!sa.aad.fs.request)) if (likely(!sa.aad->fs.request))
return 0; return 0;
type = AUDIT_APPARMOR_AUDIT; type = AUDIT_APPARMOR_AUDIT;
} else { } else {
/* only report permissions that were denied */ /* only report permissions that were denied */
sa.aad.fs.request = sa.aad.fs.request & ~perms->allow; sa.aad->fs.request = sa.aad->fs.request & ~perms->allow;
if (sa.aad.fs.request & perms->kill) if (sa.aad->fs.request & perms->kill)
type = AUDIT_APPARMOR_KILL; type = AUDIT_APPARMOR_KILL;
/* quiet known rejects, assumes quiet and kill do not overlap */ /* quiet known rejects, assumes quiet and kill do not overlap */
if ((sa.aad.fs.request & perms->quiet) && if ((sa.aad->fs.request & perms->quiet) &&
AUDIT_MODE(profile) != AUDIT_NOQUIET && AUDIT_MODE(profile) != AUDIT_NOQUIET &&
AUDIT_MODE(profile) != AUDIT_ALL) AUDIT_MODE(profile) != AUDIT_ALL)
sa.aad.fs.request &= ~perms->quiet; sa.aad->fs.request &= ~perms->quiet;
if (!sa.aad.fs.request) if (!sa.aad->fs.request)
return COMPLAIN_MODE(profile) ? 0 : sa.aad.error; return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
} }
sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow; sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow;
return aa_audit(type, profile, gfp, &sa, file_audit_cb); return aa_audit(type, profile, gfp, &sa, file_audit_cb);
} }
......
...@@ -103,7 +103,33 @@ enum aa_ops { ...@@ -103,7 +103,33 @@ enum aa_ops {
}; };
/* define a short hand for apparmor_audit_data portion of common_audit_data */ struct apparmor_audit_data {
int error;
int op;
int type;
void *profile;
const char *name;
const char *info;
union {
void *target;
struct {
long pos;
void *target;
} iface;
struct {
int rlim;
unsigned long max;
} rlim;
struct {
const char *target;
u32 request;
u32 denied;
uid_t ouid;
} fs;
};
};
/* define a short hand for apparmor_audit_data structure */
#define aad apparmor_audit_data #define aad apparmor_audit_data
void aa_audit_msg(int type, struct common_audit_data *sa, void aa_audit_msg(int type, struct common_audit_data *sa,
......
...@@ -26,7 +26,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) ...@@ -26,7 +26,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = va; struct common_audit_data *sa = va;
audit_log_format(ab, " target="); audit_log_format(ab, " target=");
audit_log_untrustedstring(ab, sa->aad.target); audit_log_untrustedstring(ab, sa->aad->target);
} }
/** /**
...@@ -41,10 +41,12 @@ static int aa_audit_ptrace(struct aa_profile *profile, ...@@ -41,10 +41,12 @@ static int aa_audit_ptrace(struct aa_profile *profile,
struct aa_profile *target, int error) struct aa_profile *target, int error)
{ {
struct common_audit_data sa; struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
COMMON_AUDIT_DATA_INIT(&sa, NONE); COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = OP_PTRACE; sa.aad = &aad;
sa.aad.target = target; aad.op = OP_PTRACE;
sa.aad.error = error; aad.target = target;
aad.error = error;
return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa, return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
audit_cb); audit_cb);
......
...@@ -65,8 +65,10 @@ void aa_info_message(const char *str) ...@@ -65,8 +65,10 @@ void aa_info_message(const char *str)
{ {
if (audit_enabled) { if (audit_enabled) {
struct common_audit_data sa; struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
COMMON_AUDIT_DATA_INIT(&sa, NONE); COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.info = str; sa.aad = &aad;
aad.info = str;
aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
} }
printk(KERN_INFO "AppArmor: %s\n", str); printk(KERN_INFO "AppArmor: %s\n", str);
......
...@@ -588,10 +588,12 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, ...@@ -588,10 +588,12 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
error = aa_setprocattr_permipc(args); error = aa_setprocattr_permipc(args);
} else { } else {
struct common_audit_data sa; struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
COMMON_AUDIT_DATA_INIT(&sa, NONE); COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = OP_SETPROCATTR; sa.aad = &aad;
sa.aad.info = name; aad.op = OP_SETPROCATTR;
sa.aad.error = -EINVAL; aad.info = name;
aad.error = -EINVAL;
return aa_audit(AUDIT_APPARMOR_DENIED, return aa_audit(AUDIT_APPARMOR_DENIED,
__aa_current_profile(), GFP_KERNEL, __aa_current_profile(), GFP_KERNEL,
&sa, NULL); &sa, NULL);
......
...@@ -964,11 +964,13 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info, ...@@ -964,11 +964,13 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
int error) int error)
{ {
struct common_audit_data sa; struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
COMMON_AUDIT_DATA_INIT(&sa, NONE); COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = op; sa.aad = &aad;
sa.aad.name = name; aad.op = op;
sa.aad.info = info; aad.name = name;
sa.aad.error = error; aad.info = info;
aad.error = error;
return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp, return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp,
&sa, NULL); &sa, NULL);
......
...@@ -70,13 +70,13 @@ struct aa_ext { ...@@ -70,13 +70,13 @@ struct aa_ext {
static void audit_cb(struct audit_buffer *ab, void *va) static void audit_cb(struct audit_buffer *ab, void *va)
{ {
struct common_audit_data *sa = va; struct common_audit_data *sa = va;
if (sa->aad.iface.target) { if (sa->aad->iface.target) {
struct aa_profile *name = sa->aad.iface.target; struct aa_profile *name = sa->aad->iface.target;
audit_log_format(ab, " name="); audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, name->base.hname); audit_log_untrustedstring(ab, name->base.hname);
} }
if (sa->aad.iface.pos) if (sa->aad->iface.pos)
audit_log_format(ab, " offset=%ld", sa->aad.iface.pos); audit_log_format(ab, " offset=%ld", sa->aad->iface.pos);
} }
/** /**
...@@ -94,13 +94,15 @@ static int audit_iface(struct aa_profile *new, const char *name, ...@@ -94,13 +94,15 @@ static int audit_iface(struct aa_profile *new, const char *name,
{ {
struct aa_profile *profile = __aa_current_profile(); struct aa_profile *profile = __aa_current_profile();
struct common_audit_data sa; struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
COMMON_AUDIT_DATA_INIT(&sa, NONE); COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad = &aad;
if (e) if (e)
sa.aad.iface.pos = e->pos - e->start; aad.iface.pos = e->pos - e->start;
sa.aad.iface.target = new; aad.iface.target = new;
sa.aad.name = name; aad.name = name;
sa.aad.info = info; aad.info = info;
sa.aad.error = error; aad.error = error;
return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa, return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,
audit_cb); audit_cb);
......
...@@ -34,7 +34,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) ...@@ -34,7 +34,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
struct common_audit_data *sa = va; struct common_audit_data *sa = va;
audit_log_format(ab, " rlimit=%s value=%lu", audit_log_format(ab, " rlimit=%s value=%lu",
rlim_names[sa->aad.rlim.rlim], sa->aad.rlim.max); rlim_names[sa->aad->rlim.rlim], sa->aad->rlim.max);
} }
/** /**
...@@ -50,12 +50,14 @@ static int audit_resource(struct aa_profile *profile, unsigned int resource, ...@@ -50,12 +50,14 @@ static int audit_resource(struct aa_profile *profile, unsigned int resource,
unsigned long value, int error) unsigned long value, int error)
{ {
struct common_audit_data sa; struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
COMMON_AUDIT_DATA_INIT(&sa, NONE); COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = OP_SETRLIMIT, sa.aad = &aad;
sa.aad.rlim.rlim = resource; aad.op = OP_SETRLIMIT,
sa.aad.rlim.max = value; aad.rlim.rlim = resource;
sa.aad.error = error; aad.rlim.max = value;
aad.error = error;
return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa, return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa,
audit_cb); audit_cb);
} }
......
...@@ -436,9 +436,9 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) ...@@ -436,9 +436,9 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
{ {
struct common_audit_data *ad = a; struct common_audit_data *ad = a;
audit_log_format(ab, "avc: %s ", audit_log_format(ab, "avc: %s ",
ad->selinux_audit_data.denied ? "denied" : "granted"); ad->selinux_audit_data->denied ? "denied" : "granted");
avc_dump_av(ab, ad->selinux_audit_data.tclass, avc_dump_av(ab, ad->selinux_audit_data->tclass,
ad->selinux_audit_data.audited); ad->selinux_audit_data->audited);
audit_log_format(ab, " for "); audit_log_format(ab, " for ");
} }
...@@ -452,9 +452,9 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) ...@@ -452,9 +452,9 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
{ {
struct common_audit_data *ad = a; struct common_audit_data *ad = a;
audit_log_format(ab, " "); audit_log_format(ab, " ");
avc_dump_query(ab, ad->selinux_audit_data.ssid, avc_dump_query(ab, ad->selinux_audit_data->ssid,
ad->selinux_audit_data.tsid, ad->selinux_audit_data->tsid,
ad->selinux_audit_data.tclass); ad->selinux_audit_data->tclass);
} }
/* This is the slow part of avc audit with big stack footprint */ /* This is the slow part of avc audit with big stack footprint */
...@@ -464,10 +464,12 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, ...@@ -464,10 +464,12 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
unsigned flags) unsigned flags)
{ {
struct common_audit_data stack_data; struct common_audit_data stack_data;
struct selinux_audit_data sad = {0,};
if (!a) { if (!a) {
a = &stack_data; a = &stack_data;
COMMON_AUDIT_DATA_INIT(a, NONE); COMMON_AUDIT_DATA_INIT(a, NONE);
a->selinux_audit_data = &sad;
} }
/* /*
...@@ -481,12 +483,12 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, ...@@ -481,12 +483,12 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
(flags & MAY_NOT_BLOCK)) (flags & MAY_NOT_BLOCK))
return -ECHILD; return -ECHILD;
a->selinux_audit_data.tclass = tclass; a->selinux_audit_data->tclass = tclass;
a->selinux_audit_data.requested = requested; a->selinux_audit_data->requested = requested;
a->selinux_audit_data.ssid = ssid; a->selinux_audit_data->ssid = ssid;
a->selinux_audit_data.tsid = tsid; a->selinux_audit_data->tsid = tsid;
a->selinux_audit_data.audited = audited; a->selinux_audit_data->audited = audited;
a->selinux_audit_data.denied = denied; a->selinux_audit_data->denied = denied;
a->lsm_pre_audit = avc_audit_pre_callback; a->lsm_pre_audit = avc_audit_pre_callback;
a->lsm_post_audit = avc_audit_post_callback; a->lsm_post_audit = avc_audit_post_callback;
common_lsm_audit(a); common_lsm_audit(a);
...@@ -523,7 +525,7 @@ inline int avc_audit(u32 ssid, u32 tsid, ...@@ -523,7 +525,7 @@ inline int avc_audit(u32 ssid, u32 tsid,
if (unlikely(denied)) { if (unlikely(denied)) {
audited = denied & avd->auditdeny; audited = denied & avd->auditdeny;
/* /*
* a->selinux_audit_data.auditdeny is TRICKY! Setting a bit in * a->selinux_audit_data->auditdeny is TRICKY! Setting a bit in
* this field means that ANY denials should NOT be audited if * this field means that ANY denials should NOT be audited if
* the policy contains an explicit dontaudit rule for that * the policy contains an explicit dontaudit rule for that
* permission. Take notice that this is unrelated to the * permission. Take notice that this is unrelated to the
...@@ -532,15 +534,15 @@ inline int avc_audit(u32 ssid, u32 tsid, ...@@ -532,15 +534,15 @@ inline int avc_audit(u32 ssid, u32 tsid,
* *
* denied == READ * denied == READ
* avd.auditdeny & ACCESS == 0 (not set means explicit rule) * avd.auditdeny & ACCESS == 0 (not set means explicit rule)
* selinux_audit_data.auditdeny & ACCESS == 1 * selinux_audit_data->auditdeny & ACCESS == 1
* *
* We will NOT audit the denial even though the denied * We will NOT audit the denial even though the denied
* permission was READ and the auditdeny checks were for * permission was READ and the auditdeny checks were for
* ACCESS * ACCESS
*/ */
if (a && if (a &&
a->selinux_audit_data.auditdeny && a->selinux_audit_data->auditdeny &&
!(a->selinux_audit_data.auditdeny & avd->auditdeny)) !(a->selinux_audit_data->auditdeny & avd->auditdeny))
audited = 0; audited = 0;
} else if (result) } else if (result)
audited = denied = requested; audited = denied = requested;
......
This diff is collapsed.
...@@ -46,6 +46,22 @@ struct avc_cache_stats { ...@@ -46,6 +46,22 @@ struct avc_cache_stats {
unsigned int frees; unsigned int frees;
}; };
struct selinux_audit_data {
u32 ssid;
u32 tsid;
u16 tclass;
u32 requested;
u32 audited;
u32 denied;
/*
* auditdeny is a bit tricky and unintuitive. See the
* comments in avc.c for it's meaning and usage.
*/
u32 auditdeny;
struct av_decision *avd;
int result;
};
/* /*
* AVC operations * AVC operations
*/ */
......
...@@ -185,6 +185,15 @@ struct smack_known { ...@@ -185,6 +185,15 @@ struct smack_known {
*/ */
#define SMK_NUM_ACCESS_TYPE 5 #define SMK_NUM_ACCESS_TYPE 5
/* SMACK data */
struct smack_audit_data {
const char *function;
char *subject;
char *object;
char *request;
int result;
};
/* /*
* Smack audit data; is empty if CONFIG_AUDIT not set * Smack audit data; is empty if CONFIG_AUDIT not set
* to save some stack * to save some stack
...@@ -192,6 +201,7 @@ struct smack_known { ...@@ -192,6 +201,7 @@ struct smack_known {
struct smk_audit_info { struct smk_audit_info {
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
struct common_audit_data a; struct common_audit_data a;
struct smack_audit_data sad;
#endif #endif
}; };
/* /*
...@@ -311,7 +321,8 @@ static inline void smk_ad_init(struct smk_audit_info *a, const char *func, ...@@ -311,7 +321,8 @@ static inline void smk_ad_init(struct smk_audit_info *a, const char *func,
{ {
memset(a, 0, sizeof(*a)); memset(a, 0, sizeof(*a));
a->a.type = type; a->a.type = type;
a->a.smack_audit_data.function = func; a->a.smack_audit_data = &a->sad;
a->a.smack_audit_data->function = func;
} }
static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
......
...@@ -275,9 +275,9 @@ static inline void smack_str_from_perm(char *string, int access) ...@@ -275,9 +275,9 @@ static inline void smack_str_from_perm(char *string, int access)
static void smack_log_callback(struct audit_buffer *ab, void *a) static void smack_log_callback(struct audit_buffer *ab, void *a)
{ {
struct common_audit_data *ad = a; struct common_audit_data *ad = a;
struct smack_audit_data *sad = &ad->smack_audit_data; struct smack_audit_data *sad = ad->smack_audit_data;
audit_log_format(ab, "lsm=SMACK fn=%s action=%s", audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
ad->smack_audit_data.function, ad->smack_audit_data->function,
sad->result ? "denied" : "granted"); sad->result ? "denied" : "granted");
audit_log_format(ab, " subject="); audit_log_format(ab, " subject=");
audit_log_untrustedstring(ab, sad->subject); audit_log_untrustedstring(ab, sad->subject);
...@@ -310,11 +310,12 @@ void smack_log(char *subject_label, char *object_label, int request, ...@@ -310,11 +310,12 @@ void smack_log(char *subject_label, char *object_label, int request,
if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
return; return;
if (a->smack_audit_data.function == NULL) sad = a->smack_audit_data;
a->smack_audit_data.function = "unknown";
if (sad->function == NULL)
sad->function = "unknown";
/* end preparing the audit data */ /* end preparing the audit data */
sad = &a->smack_audit_data;
smack_str_from_perm(request_buffer, request); smack_str_from_perm(request_buffer, request);
sad->subject = subject_label; sad->subject = subject_label;
sad->object = object_label; sad->object = object_label;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment