mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-01-30 23:02:18 +00:00
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.
210 lines
4.6 KiB
C
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,
|
|
};
|