假设我更改了一些用户设置,例如其初始登录组或将其添加到新组。我现在可以su user
使用这些新设置。但所有先前运行的进程仍将具有与以前相同的权限。
如何强制特定正在运行的进程重新读取/etc/passwd
并/etc/group
重新初始化其用户和组设置,而不终止它正在执行的任何活动?我尝试使用gdb
和 do附加到进程print setuid(MY_USER_ID)
,但尽管结果是0
(即成功),该进程仍然保留相同的数据(在bash
运行时检查groups
是否出现了其他组)。
答案1
非常有趣的尝试。实际上,进程的补充组(在 中定义/etc/group
)由以下设置setgroups
系统调用。它需要CAP_SETGID
特权或 root。
所以你可以这样做:
# id
uid=0(root) gid=0(root) groups=0(root)
# gdb -q id
Reading symbols from id...(no debugging symbols found)...done.
(gdb) b getgroups
Breakpoint 1 at 0x401990
(gdb) run
Starting program: /usr/bin/id
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, getgroups () at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) call setgroups(5, {1, 2, 3, 4, 5})
$1 = 0
(gdb) d 1
(gdb) c
Continuing.
uid=0(root) gid=0(root) groups=0(root),1(daemon),2(bin),3(sys),4(adm),5(tty)
[Inferior 1 (process 8059) exited normally]
(gdb)
答案2
看起来像是一个毫无意义的练习。
目标进程不仅可能不具有切换凭据所需的所有权限,它还可能将其 uid/gid 存储在某处并积极使用,因此意外的凭据更改实际上可能会破坏事物。
有各种实体知道谁拥有它们 - 文件、sysv ipc。
因此,您需要/停止/所有目标进程并更新所有可能的位置。
但是某些进程可能会在内核中以不间断的方式被阻止 - 现在怎么办?
出于玩具目的,您需要一个内核模块来更改进程的凭据,但即使这样也无法轻松处理阻塞的进程。
或者换句话说:你真正想要实现的目标是什么?为什么?
答案3
是的,我也经常遇到这个问题。这是一个 Linux 内核缺陷(可能会引起一些数据安全问题),因此没有用户级程序可以做到这一点。所以我明确地制作了一个内核模块程序来执行此操作。
#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, "add")){
if(query(arg_gid, gi)){
pr_info("GID %d is already in PID %d's supplementary group list\n", arg_gid, arg_pid);
return 0;
}
new_gi = groups_alloc(gi->ngroups+1);
if(new_gi==NULL){
pr_info("Error: groups_alloc() failed, out of kernel memory?\n");
return 0;
}
for(int x=0; x<gi->ngroups; ++x)
new_gi->gid[x] = gi->gid[x];
new_gi->gid[gi->ngroups].val = arg_gid;
groups_sort(new_gi);
// forcefully set group_info
get_cred((const struct cred *)new_gi);
*(struct group_info**)(&task->real_cred->group_info) = new_gi;
*(struct group_info**)(&task->cred->group_info) = new_gi;
pr_info("Added GID %d to PID %d's supplementary groups\n", arg_gid, arg_pid);
}else if(!strcmp(arg_act, "remove")){
if(!query(arg_gid, gi)){
pr_info("GID %d is not in PID %d's supplementary group list\n", arg_gid, arg_pid);
return 0;
}
new_gi = groups_alloc(gi->ngroups-1);
if(new_gi==NULL){
pr_info("Error: groups_alloc() failed, out of kernel memory?\n");
return 0;
}
for(int x=0,y=0; x<gi->ngroups; ++x)
if(gi->gid[x].val != arg_gid){
new_gi->gid[y] = gi->gid[x];
y++;
}
// forcefully set group_info
get_cred((const struct cred *)new_gi);
*(struct group_info**)(&task->real_cred->group_info) = new_gi;
*(struct group_info**)(&task->cred->group_info) = new_gi;
pr_info("Removed GID %d from PID %d's supplementary groups\n", arg_gid, arg_pid);
}else if(!strcmp(arg_act, "list")){
pr_info("Listing PID %d's supplementary groups' GIDs: ", arg_pid);
for(int x=0; x<gi->ngroups; ++x)
pr_info("%d ", gi->gid[x].val);
pr_info("Done\n");
}else if(!strcmp(arg_act, "query")){
pr_info("GID %d is %s PID %d's supplementary group list\n", arg_gid, query(arg_gid, gi)?"in":"not in", arg_pid);
}
return 0;
}
void cleanup_module(void){}
MODULE_LICENSE("GPL");
在我的 Github 存储库中查看详细用法(https://github.com/xuancong84/supgroup)。这对于 Linux 系统管理员很有用。