초기 로그인 그룹과 같은 일부 사용자 설정을 변경하거나 새 그룹에 추가한다고 가정해 보겠습니다. 이제 su user
이 새로운 설정을 사용할 수 있습니다 . 그러나 이전에 실행 중인 모든 프로세스는 여전히 이전과 동일한 권한을 갖습니다.
수행 중인 활동을 종료하지 않고 실행 중인 특정 프로세스가 사용자 및 그룹 설정을 강제로 다시 읽고 다시 초기화하도록 하려면 /etc/passwd
어떻게 해야 합니까 ? 및 do를 사용하여 프로세스에 연결하려고 /etc/group
시도했지만 결과 (예: 성공)에도 불구하고 프로세스는 여전히 동일한 데이터를 유지합니다( 런타임에 다른 그룹이 나타나는지 확인).gdb
print setuid(MY_USER_ID)
0
bash
groups
답변1
매우 흥미로운 시도입니다. 실제로 프로세스의 보충 그룹( 에 정의됨 /etc/group
)은 다음과 같이 설정됩니다.setgroups
시스템 호출. CAP_SETGID
권한이나 루트가 필요합니다 .
그래서 당신은 이것을 할 수 있습니다 :
# 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 시스템 관리자에게 유용합니다.