2

I can see the supplementary groups of a process by running cat /proc/$PID/status and looking at the Groups: line.

How can I modify this value for a process?

I know that these values are normally configured by user in the /etc/group file, but changes to that file don't immediately propagate into kernel data structures. I want to know what's done by a userspace program to set these values in the kernel.

AdminBee
  • 22,803
jrpear
  • 404

2 Answers2

2

You can set a process's supplementary groups with the setgroups syscall.

jrpear
  • 404
1

I have specifically made a kernel-module program for doing this.

#include <linux/cred.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pid.h>
#include <linux/pid_namespace.h>
#include <linux/printk.h>
#include <linux/sched.h>
#include <linux/uidgid.h>

static int arg_pid=0; static int arg_gid=0; static char *arg_act="add";

module_param(arg_pid, int, 0); MODULE_PARM_DESC(arg_pid, "PID of the process"); module_param(arg_gid, int, 0); MODULE_PARM_DESC(arg_gid, "GID of the group to add to PID's supplimentary groups"); module_param(arg_act, charp, 0); MODULE_PARM_DESC(arg_act, "action to perform: add/remove/list/query");

struct pid pid_struct = NULL; struct task_struct task = NULL; struct cred real_cd = NULL; struct cred effe_cd = NULL; struct group_info gi = NULL; struct group_info new_gi = NULL;

bool query(int gid, struct group_info *gi){ for(int x=0; x<gi->ngroups; ++x) if(gid==gi->gid[x].val) return true; return false; }

int init_module(void) { if(arg_pid==0){ pr_info("Error: Usage: insmod supgroup.ko arg_pid=## arg_gid=## (arg_act='add/remove/list/query') && rmmod supgroup\n"); return 0; } pid_struct = find_get_pid(arg_pid); if(pid_struct==NULL){ pr_info("Error: find_get_pid() failed\n"); return 0; } task = pid_task(pid_struct, PIDTYPE_PID); if(task==NULL){ pr_info("Error: pid_task() failed\n"); return 0; } if(task->real_cred==NULL){ pr_info("Error: task->real_cred == NULL\n"); return 0; } gi = task->real_cred->group_info; if(gi==NULL){ pr_info("Error: task->real_cred->group_info == NULL\n"); return 0; }

if(!strcmp(arg_act, &quot;add&quot;)){
    if(query(arg_gid, gi)){
        pr_info(&quot;GID %d is already in PID %d's supplementary group list\n&quot;, arg_gid, arg_pid);
        return 0;
    }
    new_gi = groups_alloc(gi-&gt;ngroups+1);
    if(new_gi==NULL){
        pr_info(&quot;Error: groups_alloc() failed, out of kernel memory?\n&quot;);
        return 0;
    }
    for(int x=0; x&lt;gi-&gt;ngroups; ++x)
        new_gi-&gt;gid[x] = gi-&gt;gid[x];
    new_gi-&gt;gid[gi-&gt;ngroups].val = arg_gid;
    groups_sort(new_gi);

    // forcefully set group_info
    get_cred((const struct cred *)new_gi);
    *(struct group_info**)(&amp;task-&gt;real_cred-&gt;group_info) = new_gi;
    *(struct group_info**)(&amp;task-&gt;cred-&gt;group_info) = new_gi;

    pr_info(&quot;Added GID %d to PID %d's supplementary groups\n&quot;, arg_gid, arg_pid);
}else if(!strcmp(arg_act, &quot;remove&quot;)){
    if(!query(arg_gid, gi)){
        pr_info(&quot;GID %d is not in PID %d's supplementary group list\n&quot;, arg_gid, arg_pid);
        return 0;
    }
    new_gi = groups_alloc(gi-&gt;ngroups-1);
    if(new_gi==NULL){
        pr_info(&quot;Error: groups_alloc() failed, out of kernel memory?\n&quot;);
        return 0;
    }
    for(int x=0,y=0; x&lt;gi-&gt;ngroups; ++x)
        if(gi-&gt;gid[x].val != arg_gid){
            new_gi-&gt;gid[y] = gi-&gt;gid[x];
            y++;
        }

    // forcefully set group_info
    get_cred((const struct cred *)new_gi);
    *(struct group_info**)(&amp;task-&gt;real_cred-&gt;group_info) = new_gi;
    *(struct group_info**)(&amp;task-&gt;cred-&gt;group_info) = new_gi;

    pr_info(&quot;Removed GID %d from PID %d's supplementary groups\n&quot;, arg_gid, arg_pid);
}else if(!strcmp(arg_act, &quot;list&quot;)){
    pr_info(&quot;Listing PID %d's supplementary groups' GIDs: &quot;, arg_pid);
    for(int x=0; x&lt;gi-&gt;ngroups; ++x)
        pr_info(&quot;%d &quot;, gi-&gt;gid[x].val);
    pr_info(&quot;Done\n&quot;);
}else if(!strcmp(arg_act, &quot;query&quot;)){
    pr_info(&quot;GID %d is %s PID %d's supplementary group list\n&quot;, arg_gid, query(arg_gid, gi)?&quot;in&quot;:&quot;not in&quot;, arg_pid);
}

return 0;

}

void cleanup_module(void){} MODULE_LICENSE("GPL");

Checkout its usage at my Github repo (https://github.com/xuancong84/supgroup). This is useful for updating supplementary group info for running processes.