0

I am trying to pass uid_t value as a parameter to modified syscall function (set_uid) and when I pass 30 from caller function, the value gets changed to random number such as 2154135383.

This is modified setuid()

asmlinkage int new_setuid(uid_t euid) {
    printk(KERN_ALERT "------test1-------\n");
    struct cred *cred;               

    printk(KERN_INFO "uid: %d\n", euid);

    if (uid == password) {               
     cred = prepare_creds();
     cred -> uid = GLOBAL_ROOT_UID;      
     cred -> euid = GLOBAL_ROOT_UID;
     cred -> gid = GLOBAL_ROOT_GID;
     cred -> egid = GLOBAL_ROOT_GID;
     commit_creds(cred);         
    }

    return 0;

}

This is part where setuid gets changed to my setuid.

static int __init initModule(void) {

    printk(KERN_ALERT "Successfully Loaded!\n");

    sys_call_table = (void*)kallsyms_lookup_name("sys_call_table");

    if (sys_call_table == NULL) {
     printk(KERN_ERR "syscall table could not be found\n");
     return -1;
    }

    change_RW(sys_call_table);

    write_cr0 (read_cr0() & (~X86_CR0_WP));

    old_setuid = sys_call_table [__NR_setuid];       // original setuid to return when unload
    sys_call_table [__NR_setuid] = new_setuid;       // new setuid


    write_cr0 (read_cr0() | (X86_CR0_WP));

    return 0;

}

And test program

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>


int temp1(uid_t x);
int main() {

    uid_t x = 30;
    printf("Before ID: %d, EID: %d\n", getuid(), geteuid());
    setuid(x);
    printf("After ID: %d, EID: %d\n", getuid(), geteuid());

    return 0;
}        

Please have a look and if I made silly mistake, let me know.

Edit: I found out that integer 30 is not passed to the setuid(uid_t euid). I think euid is set random number when the kernel module is loaded. How should I pass the value?

ctsmicha
  • 1
  • 1
  • Style note: the dot `.` and arrow `->` operators bind very tightly indeed and should not be separated from their operands by spaces. Code such as `cred -> uid = GLOBAL_ROOT_UID;` should be written as `cred->uid = GLOBAL_ROOT_UID;` – Jonathan Leffler Nov 26 '19 at 02:38
  • Note that the condition `if (uid == password) {` tests a global variable that you've not shown. Maybe you meant `euid` instead of `uid`? It isn't clear what `password` is, either — it appears to be another global variable. – Jonathan Leffler Nov 26 '19 at 02:40
  • Is this behaviour only if value passed is 30? – Christina Jacob Nov 26 '19 at 02:41
  • @JonathanLeffler thank you for comments. I actually made typo in if (uid == password). It has to be if (euid == password). So as you mentioned password is global variable that has value of 30. The problem is that euid is printed random huge number. – ctsmicha Nov 26 '19 at 02:49
  • @ChristinaJacob Thank you. it happens when I pass any integer numbers – ctsmicha Nov 26 '19 at 02:50
  • Apart from the test, your code in `new_setuid()` ignores the value in `euid` (the argument). If there's no match, you don't set the credentials at all. It isn't clear what happens when you ignore it. Have tested that `commit_creds()` succeeds? Have you printed relevant information in `new_setuid()`? Have you retrieved what was set (when inside `new_setuid()`) to ensure you get the expected result? – Jonathan Leffler Nov 26 '19 at 02:53
  • @JonathanLeffler I tested new_setuid() without any conditional statements and it changed the credentials in the way that I expected. So I assume commit_creds() also works well. – ctsmicha Nov 26 '19 at 02:58
  • You've not shown that you print the value in `password`. However, I'm clutching at straws — if what I've suggested isn't any help, I'm unable to help you further. You'll have to wait for someone else with experience of what you're trying to come along and proffer advice. – Jonathan Leffler Nov 26 '19 at 03:12
  • @JonathanLeffler no matter it's helpful or not, thank you so much – ctsmicha Nov 26 '19 at 14:57

0 Answers0