/*  
 *  beyrouth.c - Change task's UID and GID
 */
#include <linux/module.h>/* Needed by all modules */
#include <linux/kernel.h>/* Needed for KERN_INFO */
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/pid.h>
#include <linux/cred.h>

// 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");
