forked from Qortal/Brooklyn
2a709f28fa
* 0day explit mitigation * Memory corruption prevention * Privilege escalation prevention * Buffer over flow prevention * File System corruption defense * Thread escape prevention This may very well be the most intensive inclusion to BrooklynR. This will not be part of an x86 suite nor it will be released as tool kit. The security core toolkit will remain part of kernel base.
341 lines
13 KiB
C
341 lines
13 KiB
C
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/file.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/grinternal.h>
|
|
|
|
#ifdef CONFIG_TREE_PREEMPT_RCU
|
|
#define DISABLE_PREEMPT() preempt_disable()
|
|
#define ENABLE_PREEMPT() preempt_enable()
|
|
#else
|
|
#define DISABLE_PREEMPT()
|
|
#define ENABLE_PREEMPT()
|
|
#endif
|
|
|
|
#define BEGIN_LOCKS(x) \
|
|
DISABLE_PREEMPT(); \
|
|
rcu_read_lock(); \
|
|
read_lock(&tasklist_lock); \
|
|
read_lock(&grsec_exec_file_lock); \
|
|
if (x != GR_DO_AUDIT) \
|
|
spin_lock(&grsec_alert_lock); \
|
|
else \
|
|
spin_lock(&grsec_audit_lock)
|
|
|
|
#define END_LOCKS(x) \
|
|
if (x != GR_DO_AUDIT) \
|
|
spin_unlock(&grsec_alert_lock); \
|
|
else \
|
|
spin_unlock(&grsec_audit_lock); \
|
|
read_unlock(&grsec_exec_file_lock); \
|
|
read_unlock(&tasklist_lock); \
|
|
rcu_read_unlock(); \
|
|
ENABLE_PREEMPT(); \
|
|
if (x == GR_DONT_AUDIT) \
|
|
gr_handle_alertkill(current)
|
|
|
|
enum {
|
|
FLOODING,
|
|
NO_FLOODING
|
|
};
|
|
|
|
extern char *gr_alert_log_fmt;
|
|
extern char *gr_audit_log_fmt;
|
|
extern char *gr_alert_log_buf;
|
|
extern char *gr_audit_log_buf;
|
|
|
|
static int gr_log_start(int audit)
|
|
{
|
|
char *loglevel = (audit == GR_DO_AUDIT) ? KERN_INFO : KERN_ALERT;
|
|
char *fmt = (audit == GR_DO_AUDIT) ? gr_audit_log_fmt : gr_alert_log_fmt;
|
|
char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf;
|
|
#if (CONFIG_GRKERNSEC_FLOODTIME > 0 && CONFIG_GRKERNSEC_FLOODBURST > 0)
|
|
unsigned long curr_secs = get_seconds();
|
|
|
|
if (audit == GR_DO_AUDIT)
|
|
goto set_fmt;
|
|
|
|
if (!grsec_alert_wtime || time_after(curr_secs, grsec_alert_wtime + CONFIG_GRKERNSEC_FLOODTIME)) {
|
|
grsec_alert_wtime = curr_secs;
|
|
grsec_alert_fyet = 0;
|
|
} else if (time_before_eq(curr_secs, grsec_alert_wtime + CONFIG_GRKERNSEC_FLOODTIME)
|
|
&& (grsec_alert_fyet < CONFIG_GRKERNSEC_FLOODBURST)) {
|
|
grsec_alert_fyet++;
|
|
} else if (grsec_alert_fyet == CONFIG_GRKERNSEC_FLOODBURST) {
|
|
grsec_alert_wtime = curr_secs;
|
|
grsec_alert_fyet++;
|
|
printk(KERN_ALERT "grsec: more alerts, logging disabled for %d seconds\n", CONFIG_GRKERNSEC_FLOODTIME);
|
|
return FLOODING;
|
|
}
|
|
else return FLOODING;
|
|
|
|
set_fmt:
|
|
#endif
|
|
memset(buf, 0, PAGE_SIZE);
|
|
if (current->signal->curr_ip && gr_acl_is_enabled()) {
|
|
sprintf(fmt, "%s%s", loglevel, "grsec: From %pI4: (%.64s:%c:%.950s) ");
|
|
snprintf(buf, PAGE_SIZE - 1, fmt, ¤t->signal->curr_ip, current->role->rolename, gr_roletype_to_char(), current->acl->filename);
|
|
} else if (current->signal->curr_ip) {
|
|
sprintf(fmt, "%s%s", loglevel, "grsec: From %pI4: ");
|
|
snprintf(buf, PAGE_SIZE - 1, fmt, ¤t->signal->curr_ip);
|
|
} else if (gr_acl_is_enabled()) {
|
|
sprintf(fmt, "%s%s", loglevel, "grsec: (%.64s:%c:%.950s) ");
|
|
snprintf(buf, PAGE_SIZE - 1, fmt, current->role->rolename, gr_roletype_to_char(), current->acl->filename);
|
|
} else {
|
|
sprintf(fmt, "%s%s", loglevel, "grsec: ");
|
|
strcpy(buf, fmt);
|
|
}
|
|
|
|
return NO_FLOODING;
|
|
}
|
|
|
|
static void gr_log_middle(int audit, const char *msg, va_list ap)
|
|
__attribute__ ((format (printf, 2, 0)));
|
|
|
|
static void gr_log_middle(int audit, const char *msg, va_list ap)
|
|
{
|
|
char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf;
|
|
unsigned int len = strlen(buf);
|
|
|
|
vsnprintf(buf + len, PAGE_SIZE - len - 1, msg, ap);
|
|
|
|
return;
|
|
}
|
|
|
|
static void gr_log_middle_varargs(int audit, const char *msg, ...)
|
|
__attribute__ ((format (printf, 2, 3)));
|
|
|
|
static void gr_log_middle_varargs(int audit, const char *msg, ...)
|
|
{
|
|
char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf;
|
|
unsigned int len = strlen(buf);
|
|
va_list ap;
|
|
|
|
va_start(ap, msg);
|
|
vsnprintf(buf + len, PAGE_SIZE - len - 1, msg, ap);
|
|
va_end(ap);
|
|
|
|
return;
|
|
}
|
|
|
|
static void gr_log_end(int audit, int append_default)
|
|
{
|
|
char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf;
|
|
if (append_default) {
|
|
struct task_struct *task = current;
|
|
struct task_struct *parent = task->real_parent;
|
|
const struct cred *cred = __task_cred(task);
|
|
const struct cred *pcred = __task_cred(parent);
|
|
unsigned int len = strlen(buf);
|
|
|
|
snprintf(buf + len, PAGE_SIZE - len - 1, DEFAULTSECMSG, gr_task_fullpath(task), task->comm, task_pid_nr(task), GR_GLOBAL_UID(cred->uid), GR_GLOBAL_UID(cred->euid), GR_GLOBAL_GID(cred->gid), GR_GLOBAL_GID(cred->egid), gr_parent_task_fullpath(task), parent->comm, task_pid_nr(task->real_parent), GR_GLOBAL_UID(pcred->uid), GR_GLOBAL_UID(pcred->euid), GR_GLOBAL_GID(pcred->gid), GR_GLOBAL_GID(pcred->egid));
|
|
}
|
|
|
|
printk("%s\n", buf);
|
|
|
|
return;
|
|
}
|
|
|
|
void gr_log_varargs(int audit, const char *msg, int argtypes, ...)
|
|
{
|
|
int logtype;
|
|
char *result = (audit == GR_DO_AUDIT) ? "successful" : "denied";
|
|
char *str1 = NULL, *str2 = NULL, *str3 = NULL;
|
|
void *voidptr = NULL;
|
|
int num1 = 0, num2 = 0;
|
|
unsigned long ulong1 = 0, ulong2 = 0;
|
|
struct dentry *dentry = NULL;
|
|
struct vfsmount *mnt = NULL;
|
|
struct file *file = NULL;
|
|
struct task_struct *task = NULL;
|
|
struct vm_area_struct *vma = NULL;
|
|
const struct cred *cred, *pcred;
|
|
va_list ap;
|
|
|
|
BEGIN_LOCKS(audit);
|
|
logtype = gr_log_start(audit);
|
|
if (logtype == FLOODING) {
|
|
END_LOCKS(audit);
|
|
return;
|
|
}
|
|
va_start(ap, argtypes);
|
|
switch (argtypes) {
|
|
case GR_TTYSNIFF:
|
|
task = va_arg(ap, struct task_struct *);
|
|
gr_log_middle_varargs(audit, msg, &task->signal->curr_ip, gr_task_fullpath0(task), task->comm, task_pid_nr(task), gr_parent_task_fullpath0(task), task->real_parent->comm, task_pid_nr(task->real_parent));
|
|
break;
|
|
case GR_SYSCTL_HIDDEN:
|
|
str1 = va_arg(ap, char *);
|
|
gr_log_middle_varargs(audit, msg, result, str1);
|
|
break;
|
|
case GR_RBAC:
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
gr_log_middle_varargs(audit, msg, result, gr_to_filename(dentry, mnt));
|
|
break;
|
|
case GR_RBAC_STR:
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
str1 = va_arg(ap, char *);
|
|
gr_log_middle_varargs(audit, msg, result, gr_to_filename(dentry, mnt), str1);
|
|
break;
|
|
case GR_STR_RBAC:
|
|
str1 = va_arg(ap, char *);
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
gr_log_middle_varargs(audit, msg, result, str1, gr_to_filename(dentry, mnt));
|
|
break;
|
|
case GR_RBAC_MODE2:
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
str1 = va_arg(ap, char *);
|
|
str2 = va_arg(ap, char *);
|
|
gr_log_middle_varargs(audit, msg, result, gr_to_filename(dentry, mnt), str1, str2);
|
|
break;
|
|
case GR_RBAC_MODE3:
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
str1 = va_arg(ap, char *);
|
|
str2 = va_arg(ap, char *);
|
|
str3 = va_arg(ap, char *);
|
|
gr_log_middle_varargs(audit, msg, result, gr_to_filename(dentry, mnt), str1, str2, str3);
|
|
break;
|
|
case GR_FILENAME:
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt));
|
|
break;
|
|
case GR_STR_FILENAME:
|
|
str1 = va_arg(ap, char *);
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
gr_log_middle_varargs(audit, msg, str1, gr_to_filename(dentry, mnt));
|
|
break;
|
|
case GR_FILENAME_STR:
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
str1 = va_arg(ap, char *);
|
|
gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt), str1);
|
|
break;
|
|
case GR_FILENAME_TWO_INT:
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
num1 = va_arg(ap, int);
|
|
num2 = va_arg(ap, int);
|
|
gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt), num1, num2);
|
|
break;
|
|
case GR_FILENAME_TWO_INT_STR:
|
|
dentry = va_arg(ap, struct dentry *);
|
|
mnt = va_arg(ap, struct vfsmount *);
|
|
num1 = va_arg(ap, int);
|
|
num2 = va_arg(ap, int);
|
|
str1 = va_arg(ap, char *);
|
|
gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt), num1, num2, str1);
|
|
break;
|
|
case GR_TEXTREL:
|
|
str1 = va_arg(ap, char *);
|
|
file = va_arg(ap, struct file *);
|
|
ulong1 = va_arg(ap, unsigned long);
|
|
ulong2 = va_arg(ap, unsigned long);
|
|
gr_log_middle_varargs(audit, msg, str1, file ? gr_to_filename(file->f_path.dentry, file->f_path.mnt) : "<anonymous mapping>", ulong1, ulong2);
|
|
break;
|
|
case GR_PTRACE:
|
|
task = va_arg(ap, struct task_struct *);
|
|
gr_log_middle_varargs(audit, msg, task->exec_file ? gr_to_filename(task->exec_file->f_path.dentry, task->exec_file->f_path.mnt) : "(none)", task->comm, task_pid_nr(task));
|
|
break;
|
|
case GR_RESOURCE:
|
|
task = va_arg(ap, struct task_struct *);
|
|
cred = __task_cred(task);
|
|
pcred = __task_cred(task->real_parent);
|
|
ulong1 = va_arg(ap, unsigned long);
|
|
str1 = va_arg(ap, char *);
|
|
ulong2 = va_arg(ap, unsigned long);
|
|
gr_log_middle_varargs(audit, msg, ulong1, str1, ulong2, gr_task_fullpath(task), task->comm, task_pid_nr(task), GR_GLOBAL_UID(cred->uid), GR_GLOBAL_UID(cred->euid), GR_GLOBAL_GID(cred->gid), GR_GLOBAL_GID(cred->egid), gr_parent_task_fullpath(task), task->real_parent->comm, task_pid_nr(task->real_parent), GR_GLOBAL_UID(pcred->uid), GR_GLOBAL_UID(pcred->euid), GR_GLOBAL_GID(pcred->gid), GR_GLOBAL_GID(pcred->egid));
|
|
break;
|
|
case GR_CAP:
|
|
task = va_arg(ap, struct task_struct *);
|
|
cred = __task_cred(task);
|
|
pcred = __task_cred(task->real_parent);
|
|
str1 = va_arg(ap, char *);
|
|
gr_log_middle_varargs(audit, msg, str1, gr_task_fullpath(task), task->comm, task_pid_nr(task), GR_GLOBAL_UID(cred->uid), GR_GLOBAL_UID(cred->euid), GR_GLOBAL_GID(cred->gid), GR_GLOBAL_GID(cred->egid), gr_parent_task_fullpath(task), task->real_parent->comm, task_pid_nr(task->real_parent), GR_GLOBAL_UID(pcred->uid), GR_GLOBAL_UID(pcred->euid), GR_GLOBAL_GID(pcred->gid), GR_GLOBAL_GID(pcred->egid));
|
|
break;
|
|
case GR_SIG:
|
|
str1 = va_arg(ap, char *);
|
|
voidptr = va_arg(ap, void *);
|
|
gr_log_middle_varargs(audit, msg, str1, voidptr);
|
|
break;
|
|
case GR_SIG2:
|
|
task = va_arg(ap, struct task_struct *);
|
|
cred = __task_cred(task);
|
|
pcred = __task_cred(task->real_parent);
|
|
num1 = va_arg(ap, int);
|
|
gr_log_middle_varargs(audit, msg, num1, gr_task_fullpath0(task), task->comm, task_pid_nr(task), GR_GLOBAL_UID(cred->uid), GR_GLOBAL_UID(cred->euid), GR_GLOBAL_GID(cred->gid), GR_GLOBAL_GID(cred->egid), gr_parent_task_fullpath0(task), task->real_parent->comm, task_pid_nr(task->real_parent), GR_GLOBAL_UID(pcred->uid), GR_GLOBAL_UID(pcred->euid), GR_GLOBAL_GID(pcred->gid), GR_GLOBAL_GID(pcred->egid));
|
|
break;
|
|
case GR_CRASH1:
|
|
task = va_arg(ap, struct task_struct *);
|
|
cred = __task_cred(task);
|
|
pcred = __task_cred(task->real_parent);
|
|
ulong1 = va_arg(ap, unsigned long);
|
|
gr_log_middle_varargs(audit, msg, gr_task_fullpath(task), task->comm, task_pid_nr(task), GR_GLOBAL_UID(cred->uid), GR_GLOBAL_UID(cred->euid), GR_GLOBAL_GID(cred->gid), GR_GLOBAL_GID(cred->egid), gr_parent_task_fullpath(task), task->real_parent->comm, task_pid_nr(task->real_parent), GR_GLOBAL_UID(pcred->uid), GR_GLOBAL_UID(pcred->euid), GR_GLOBAL_GID(pcred->gid), GR_GLOBAL_GID(pcred->egid), GR_GLOBAL_UID(cred->uid), ulong1);
|
|
break;
|
|
case GR_CRASH2:
|
|
task = va_arg(ap, struct task_struct *);
|
|
cred = __task_cred(task);
|
|
pcred = __task_cred(task->real_parent);
|
|
ulong1 = va_arg(ap, unsigned long);
|
|
gr_log_middle_varargs(audit, msg, gr_task_fullpath(task), task->comm, task_pid_nr(task), GR_GLOBAL_UID(cred->uid), GR_GLOBAL_UID(cred->euid), GR_GLOBAL_GID(cred->gid), GR_GLOBAL_GID(cred->egid), gr_parent_task_fullpath(task), task->real_parent->comm, task_pid_nr(task->real_parent), GR_GLOBAL_UID(pcred->uid), GR_GLOBAL_UID(pcred->euid), GR_GLOBAL_GID(pcred->gid), GR_GLOBAL_GID(pcred->egid), ulong1);
|
|
break;
|
|
case GR_RWXMAP:
|
|
file = va_arg(ap, struct file *);
|
|
gr_log_middle_varargs(audit, msg, file ? gr_to_filename(file->f_path.dentry, file->f_path.mnt) : "<anonymous mapping>");
|
|
break;
|
|
case GR_RWXMAPVMA:
|
|
vma = va_arg(ap, struct vm_area_struct *);
|
|
if (vma->vm_file)
|
|
str1 = gr_to_filename(vma->vm_file->f_path.dentry, vma->vm_file->f_path.mnt);
|
|
else if (vma->vm_flags & (VM_GROWSDOWN | VM_GROWSUP))
|
|
str1 = "<stack>";
|
|
else if (vma->vm_start <= current->mm->brk &&
|
|
vma->vm_end >= current->mm->start_brk)
|
|
str1 = "<heap>";
|
|
else
|
|
str1 = "<anonymous mapping>";
|
|
gr_log_middle_varargs(audit, msg, str1);
|
|
break;
|
|
case GR_PSACCT:
|
|
{
|
|
unsigned int wday, cday;
|
|
__u8 whr, chr;
|
|
__u8 wmin, cmin;
|
|
__u8 wsec, csec;
|
|
|
|
task = va_arg(ap, struct task_struct *);
|
|
wday = va_arg(ap, unsigned int);
|
|
cday = va_arg(ap, unsigned int);
|
|
whr = va_arg(ap, int);
|
|
chr = va_arg(ap, int);
|
|
wmin = va_arg(ap, int);
|
|
cmin = va_arg(ap, int);
|
|
wsec = va_arg(ap, int);
|
|
csec = va_arg(ap, int);
|
|
ulong1 = va_arg(ap, unsigned long);
|
|
cred = __task_cred(task);
|
|
pcred = __task_cred(task->real_parent);
|
|
|
|
gr_log_middle_varargs(audit, msg, gr_task_fullpath(task), task->comm, task_pid_nr(task), &task->signal->curr_ip, tty_name(task->signal->tty), GR_GLOBAL_UID(cred->uid), GR_GLOBAL_UID(cred->euid), GR_GLOBAL_GID(cred->gid), GR_GLOBAL_GID(cred->egid), wday, whr, wmin, wsec, cday, chr, cmin, csec, (task->flags & PF_SIGNALED) ? "killed by signal" : "exited", ulong1, gr_parent_task_fullpath(task), task->real_parent->comm, task_pid_nr(task->real_parent), &task->real_parent->signal->curr_ip, tty_name(task->real_parent->signal->tty), GR_GLOBAL_UID(pcred->uid), GR_GLOBAL_UID(pcred->euid), GR_GLOBAL_GID(pcred->gid), GR_GLOBAL_GID(pcred->egid));
|
|
}
|
|
break;
|
|
default:
|
|
gr_log_middle(audit, msg, ap);
|
|
}
|
|
va_end(ap);
|
|
// these don't need DEFAULTSECARGS printed on the end
|
|
if (argtypes == GR_CRASH1 || argtypes == GR_CRASH2)
|
|
gr_log_end(audit, 0);
|
|
else
|
|
gr_log_end(audit, 1);
|
|
END_LOCKS(audit);
|
|
}
|