3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-01-30 23:02:18 +00:00
Brooklyn/grsecurity/gracl_learn.c
Scare Crowe 2a709f28fa Auto exploit mitigation feature
* 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.
2021-11-13 09:26:51 +05:00

210 lines
4.6 KiB
C

#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/file.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/grinternal.h>
extern ssize_t write_grsec_handler(struct file * file, const char __user * buf,
size_t count, loff_t *ppos);
extern int gr_acl_is_enabled(void);
static DECLARE_WAIT_QUEUE_HEAD(learn_wait);
static int gr_learn_attached;
/* use a 512k buffer */
#define LEARN_BUFFER_SIZE (512 * 1024)
static DEFINE_SPINLOCK(gr_learn_lock);
static DEFINE_MUTEX(gr_learn_user_mutex);
/* we need to maintain two buffers, so that the kernel context of grlearn
uses a semaphore around the userspace copying, and the other kernel contexts
use a spinlock when copying into the buffer, since they cannot sleep
*/
static char *learn_buffer;
static char *learn_buffer_user;
static int learn_buffer_len;
static int learn_buffer_user_len;
static ssize_t
read_learn(struct file *file, char __user * buf, size_t count, loff_t * ppos)
{
DECLARE_WAITQUEUE(wait, current);
ssize_t retval = 0;
add_wait_queue(&learn_wait, &wait);
do {
mutex_lock(&gr_learn_user_mutex);
set_current_state(TASK_INTERRUPTIBLE);
spin_lock(&gr_learn_lock);
if (learn_buffer_len) {
set_current_state(TASK_RUNNING);
break;
}
spin_unlock(&gr_learn_lock);
mutex_unlock(&gr_learn_user_mutex);
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
goto out;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
goto out;
}
schedule();
} while (1);
memcpy(learn_buffer_user, learn_buffer, learn_buffer_len);
learn_buffer_user_len = learn_buffer_len;
retval = learn_buffer_len;
learn_buffer_len = 0;
spin_unlock(&gr_learn_lock);
if (copy_to_user(buf, learn_buffer_user, learn_buffer_user_len))
retval = -EFAULT;
mutex_unlock(&gr_learn_user_mutex);
out:
set_current_state(TASK_RUNNING);
remove_wait_queue(&learn_wait, &wait);
return retval;
}
static unsigned int
poll_learn(struct file * file, poll_table * wait)
{
poll_wait(file, &learn_wait, wait);
if (learn_buffer_len)
return (POLLIN | POLLRDNORM);
return 0;
}
void
gr_clear_learn_entries(void)
{
char *tmp;
mutex_lock(&gr_learn_user_mutex);
spin_lock(&gr_learn_lock);
tmp = learn_buffer;
learn_buffer = NULL;
spin_unlock(&gr_learn_lock);
if (tmp)
vfree(tmp);
if (learn_buffer_user != NULL) {
vfree(learn_buffer_user);
learn_buffer_user = NULL;
}
learn_buffer_len = 0;
mutex_unlock(&gr_learn_user_mutex);
return;
}
void
gr_add_learn_entry(const char *fmt, ...)
{
va_list args;
unsigned int len;
if (!gr_learn_attached)
return;
spin_lock(&gr_learn_lock);
/* leave a gap at the end so we know when it's "full" but don't have to
compute the exact length of the string we're trying to append
*/
if (learn_buffer_len > LEARN_BUFFER_SIZE - 16384) {
spin_unlock(&gr_learn_lock);
wake_up_interruptible(&learn_wait);
return;
}
if (learn_buffer == NULL) {
spin_unlock(&gr_learn_lock);
return;
}
va_start(args, fmt);
len = vsnprintf(learn_buffer + learn_buffer_len, LEARN_BUFFER_SIZE - learn_buffer_len, fmt, args);
va_end(args);
learn_buffer_len += len + 1;
spin_unlock(&gr_learn_lock);
wake_up_interruptible(&learn_wait);
return;
}
static int
open_learn(struct inode *inode, struct file *file)
{
if (file->f_mode & FMODE_READ && gr_learn_attached)
return -EBUSY;
if (file->f_mode & FMODE_READ) {
int retval = 0;
mutex_lock(&gr_learn_user_mutex);
if (learn_buffer == NULL)
learn_buffer = vmalloc(LEARN_BUFFER_SIZE);
if (learn_buffer_user == NULL)
learn_buffer_user = vmalloc(LEARN_BUFFER_SIZE);
if (learn_buffer == NULL) {
retval = -ENOMEM;
goto out_error;
}
if (learn_buffer_user == NULL) {
retval = -ENOMEM;
goto out_error;
}
learn_buffer_len = 0;
learn_buffer_user_len = 0;
gr_learn_attached = 1;
out_error:
mutex_unlock(&gr_learn_user_mutex);
return retval;
}
return 0;
}
static int
close_learn(struct inode *inode, struct file *file)
{
if (file->f_mode & FMODE_READ) {
char *tmp = NULL;
mutex_lock(&gr_learn_user_mutex);
spin_lock(&gr_learn_lock);
tmp = learn_buffer;
learn_buffer = NULL;
spin_unlock(&gr_learn_lock);
if (tmp)
vfree(tmp);
if (learn_buffer_user != NULL) {
vfree(learn_buffer_user);
learn_buffer_user = NULL;
}
learn_buffer_len = 0;
learn_buffer_user_len = 0;
gr_learn_attached = 0;
mutex_unlock(&gr_learn_user_mutex);
}
return 0;
}
const struct file_operations grsec_fops = {
.read = read_learn,
.write = write_grsec_handler,
.open = open_learn,
.release = close_learn,
.poll = poll_learn,
};