Add caching of capability and syscall reject logging so that only the

first reject or complain message is logged.  This greatly reduces the
pressure on the auditing subsystem.
This commit is contained in:
John Johansen 2007-01-04 08:50:48 +00:00
parent 3a8869b0d9
commit cb28cf95cf
5 changed files with 124 additions and 26 deletions

View file

@ -57,6 +57,16 @@ extern int subdomain_logsyscall;
#define SD_WARN(fmt, args...) printk(KERN_WARNING "AppArmor: " fmt, ##args)
#define SD_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
/* apparmor logged syscall reject caching */
enum aasyscall {
AA_SYSCALL_PTRACE,
AA_SYSCALL_SYSCTL_WRITE,
AA_SYSCALL_MOUNT,
AA_SYSCALL_UMOUNT
};
#define AA_SYSCALL_TO_MASK(X) (1 << (X))
/* basic AppArmor data structures */
struct flagval {
@ -154,6 +164,9 @@ struct subdomain {
__u32 sd_hat_magic; /* used with change_hat */
struct list_head list; /* list of subdomains */
struct task_struct *task;
kernel_cap_t cached_caps;
unsigned int cached_syscalls;
};
typedef int (*sd_iter) (struct subdomain *, void *);
@ -239,7 +252,7 @@ extern void free_nullprofiles(void);
extern int sd_audit_message(struct subdomain *, unsigned int gfp, int,
const char *, ...);
extern int sd_audit_syscallreject(struct subdomain *, unsigned int gfp,
const char *);
enum aasyscall call);
extern int sd_audit(struct subdomain *, const struct sd_audit *);
extern char *sd_get_name(struct dentry *dentry, struct vfsmount *mnt);
@ -294,6 +307,7 @@ extern int destroy_subdomainfs(void);
/* capabilities.c */
extern const char *capability_to_name(unsigned int cap);
extern const char *syscall_to_name(enum aasyscall call);
/* apparmor_version.c */
extern const char *apparmor_version(void);

View file

@ -54,3 +54,18 @@ const char *capability_to_name(unsigned int cap)
return capname;
}
static const char *syscall_names[] = {
"ptrace",
"sysctl (write)",
"mount",
"umount"
};
const char *syscall_to_name(enum aasyscall call)
{
const char *name;
name = (call < (sizeof(syscall_names) / sizeof(char *))
? syscall_names[call] : "invalid-syscall");
return name;
}

View file

@ -81,6 +81,62 @@ static inline void put_sdprofile(struct sdprofile *p)
free_sdprofile(p);
}
/**
* cap_is_cached - check if @cap access has already been logged for current
* @cap: capability to test if cached
*/
static inline int cap_is_cached(int cap)
{
struct subdomain *sd = SD_SUBDOMAIN(current->security);
return cap_raised(sd->cached_caps, cap);
}
/**
* add_to_cached_caps - add a capability to the tasks logged capabilities cache
* @cap: the capability to add
*/
static inline void add_to_cached_caps(int cap)
{
struct subdomain *sd = SD_SUBDOMAIN(current->security);
sd->cached_caps = cap_combine(sd->cached_caps, CAP_TO_MASK(cap));
}
/**
* clear_cached_caps - clear the tasks logged capabilities cache
*/
static inline void clear_cached_caps(struct subdomain *sd)
{
sd->cached_caps = CAP_EMPTY_SET;
}
/**
* syscall_is_cached - check if @call access has already been logged
* @call: syscall to test if cached
*/
static inline int syscall_is_cached(enum aasyscall call)
{
struct subdomain *sd = SD_SUBDOMAIN(current->security);
return sd->cached_syscalls & AA_SYSCALL_TO_MASK(call);
}
/**
* add_to_cached_syscalls - add a syscall to the tasks logged syscalls cache
* @call: the syscall to add
*/
static inline void add_to_cached_syscalls(enum aasyscall call)
{
struct subdomain *sd = SD_SUBDOMAIN(current->security);
sd->cached_syscalls |= AA_SYSCALL_TO_MASK(call);
}
/**
* clear_cached_syscalls - clear the tasks logged syscalls cache
*/
static inline void clear_cached_syscalls(struct subdomain *sd)
{
sd->cached_syscalls = 0;
}
/**
* sd_switch
* @sd: subdomain to switch
@ -99,6 +155,8 @@ static inline void sd_switch(struct subdomain *sd,
sd->profile = get_sdprofile(profile);
sd->active = get_sdprofile(active);
clear_cached_caps(sd);
clear_cached_syscalls(sd);
}
/**

View file

@ -105,11 +105,9 @@ static int subdomain_ptrace(struct task_struct *parent,
sd = SD_SUBDOMAIN(parent->security);
if (__sd_is_confined(sd)) {
if (__sd_is_confined(sd))
error = sd_audit_syscallreject(sd, GFP_ATOMIC,
"ptrace");
WARN_ON(error != -EPERM);
}
AA_SYSCALL_PTRACE);
read_unlock_irqrestore(&sd_lock, flags);
}
@ -178,11 +176,9 @@ static int subdomain_sysctl(struct ctl_table *table, int op)
sd = SD_SUBDOMAIN(current->security);
if ((op & 002) && __sd_is_confined(sd) && !capable(CAP_SYS_ADMIN)) {
if ((op & 002) && __sd_is_confined(sd) && !capable(CAP_SYS_ADMIN))
error = sd_audit_syscallreject(sd, GFP_ATOMIC,
"sysctl (write)");
WARN_ON(error != -EPERM);
}
AA_SYSCALL_SYSCTL_WRITE);
read_unlock_irqrestore(&sd_lock, flags);
@ -247,10 +243,9 @@ static int subdomain_sb_mount(char *dev_name, struct nameidata *nd, char *type,
sd = SD_SUBDOMAIN(current->security);
if (__sd_is_confined(sd)) {
error = sd_audit_syscallreject(sd, GFP_ATOMIC, "mount");
WARN_ON(error != -EPERM);
}
if (__sd_is_confined(sd))
error = sd_audit_syscallreject(sd, GFP_ATOMIC,
AA_SYSCALL_MOUNT);
read_unlock_irqrestore(&sd_lock, lockflags);
@ -270,10 +265,9 @@ static int subdomain_umount(struct vfsmount *mnt, int flags)
sd = SD_SUBDOMAIN(current->security);
if (__sd_is_confined(sd)) {
error = sd_audit_syscallreject(sd, GFP_ATOMIC, "umount");
WARN_ON(error != -EPERM);
}
if (__sd_is_confined(sd))
error = sd_audit_syscallreject(sd, GFP_ATOMIC,
AA_SYSCALL_UMOUNT);
read_unlock_irqrestore(&sd_lock, lockflags);

View file

@ -562,18 +562,24 @@ int sd_audit_message(struct subdomain *sd, unsigned int gfp, int flags,
* @gfp: memory allocation flags
*/
int sd_audit_syscallreject(struct subdomain *sd, unsigned int gfp,
const char *msg)
enum aasyscall call)
{
struct sd_audit sa;
int error = -EPERM;
sa.type = SD_AUDITTYPE_SYSCALL;
sa.name = msg;
sa.flags = 0;
sa.gfp_mask = gfp;
sa.errorcode = 0;
sa.result = 0; /* failure */
if (!syscall_is_cached(call)) {
sa.type = SD_AUDITTYPE_SYSCALL;
sa.name = syscall_to_name(call);
sa.flags = 0;
sa.gfp_mask = gfp;
sa.errorcode = 0;
sa.result = 0; /* failure */
return sd_audit(sd, &sa);
error = sd_audit(sd, &sa);
if (error == -EPERM)
add_to_cached_syscalls(call);
}
return error;
}
/**
@ -631,6 +637,16 @@ int sd_audit(struct subdomain *sd, const struct sd_audit *sa)
logcls = sdcomplain ? "PERMITTING" : "REJECTING";
}
/* test if event has already been logged and cached used to log
* only first time event occurs.
*/
if (sa->type == SD_AUDITTYPE_CAP) {
if (cap_is_cached(sa->ival)) {
opspec_error = -EPERM;
goto skip_logging;
}
}
/* In future extend w/ per-profile flags
* (flags |= sa->active->flags)
*/
@ -737,7 +753,7 @@ int sd_audit(struct subdomain *sd, const struct sd_audit *sa)
audit_log_format(ab,
"access to capability '%s' ",
capability_to_name(sa->ival));
add_to_cached_caps(sa->ival);
opspec_error = -EPERM;
} else if (sa->type == SD_AUDITTYPE_SYSCALL) {
audit_log_format(ab, "access to syscall '%s' ", sa->name);
@ -754,6 +770,7 @@ int sd_audit(struct subdomain *sd, const struct sd_audit *sa)
audit_log_end(ab);
skip_logging:
if (sdcomplain)
error = 0;
else