You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中如何获取父进程的uid/euid/gid?能否不依赖/proc或ps获取父进程UID?

嘿,我来帮你梳理这两个C语言相关的进程凭证获取问题:

1. 在C语言中获取父进程的UID、EUID以及GID

首先,要拿到父进程的这些身份ID,第一步肯定是用getppid()获取父进程的PID对吧?接下来的关键就是怎么从PID拿到对应的凭证信息:

  • 要是你的系统支持/proc文件系统(绝大多数Linux发行版都支持),这绝对是最省事的办法。你可以直接读取/proc/[pid]/status文件,里面的Uid和Gid字段就包含了你要的信息——Uid那一行的四个数值分别是real UID、effective UID、saved set UID和filesystem UID,Gid同理。写个简单的C程序就能解析这些内容:打开文件,逐行扫描,匹配到Uid:或Gid:后提取后面的数字就行。

  • 但如果你不能碰/proc(对应第二个问题的要求),那事情就麻烦多了。POSIX标准里根本没有提供跨平台的系统调用,能直接获取另一个进程的凭证信息。不同的UNIX-like系统有各自的“偏方”:

    • Linux:可以用ptrace()系统调用,先附加到目标进程,然后读取内核里task_struct结构体里的凭证数据。但这方法有俩大坑:一是需要权限——普通用户只能附加自己的进程,root才能碰任意进程;二是内核版本一变,task_struct的布局可能就改了,代码直接失效,完全不具备可移植性。
    • BSD系系统:可以用kvm接口,通过读取内核虚拟内存来获取进程信息,但同样需要特殊权限,而且得链接特定的库,也是系统专属的。
2. 无需/proc或ps,获取父进程/任意进程的UID

先给你个明确结论:在标准POSIX环境下,根本没有类似getppid()这种直接的系统调用,能拿到父进程或者任意进程的UID。getppid()是POSIX标准里的,但它只返回PID,没给配套的获取身份凭证的接口。

要是必须躲开/proc和ps这种shell工具,那只能靠特定系统的非标准手段:

  • Linux下的ptrace方案:简单说就是用ptrace(PTRACE_ATTACH, pid, NULL, NULL)把目标进程挂起,然后通过ptrace(PTRACE_PEEKDATA)读取进程内存里的凭证信息,最后再用PTRACE_DETACH恢复进程运行。但这方法问题不少:
    1. 权限卡得严:普通用户只能操作自己的进程,root才能为所欲为。
    2. 会打断目标进程:附加之后进程会暂停,虽然能恢复,但可能影响人家的正常运行。
    3. 内核版本绑定:进程的UID存在内核的task_struct里,不同内核版本的结构体偏移不一样,你得对着内核源码找正确的偏移,代码换个内核版本就废了。

给你写个极简的示例(仅适用于特定旧版Linux,别直接拿去用):

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

int get_process_uid(pid_t pid) {
    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
        perror("Failed to attach to process");
        return -1;
    }

    // 等待目标进程进入停止状态
    int status;
    if (waitpid(pid, &status, 0) == -1) {
        perror("waitpid failed");
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
        return -1;
    }

    // 注意:这里的内存偏移是示例,实际要对应你的内核版本
    // 你得去查对应内核的task_struct结构体里uid字段的偏移
    long uid_val = ptrace(PTRACE_PEEKDATA, pid, (void*)0xc0000000 + 0x10, NULL);
    if (uid_val == -1 && errno != 0) {
        perror("Failed to read UID");
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
        return -1;
    }

    // 解除附加,让进程继续运行
    if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) {
        perror("Failed to detach from process");
        return -1;
    }

    return (int)uid_val;
}

int main() {
    pid_t parent_pid = getppid();
    int parent_uid = get_process_uid(parent_pid);
    if (parent_uid != -1) {
        printf("Parent process UID: %d\n", parent_uid);
    }
    return 0;
}

再次强调,这个示例只是演示思路,实际用的时候得自己查内核源码找正确的偏移,实用性非常有限。

  • BSD系统的kvm方案:比如FreeBSD里,你可以用kvm_openfiles()打开内核文件,然后用kvm_getproc2()获取进程的kinfo_proc结构体,里面就有UID信息。但这需要链接-lkvm库,而且得有读取内核内存的权限,同样是系统专属的。

最后总结一下:

  • 要是能用/proc,那这是Linux下最可靠、最容易实现的方法,没啥坑。
  • 要是必须禁用/proc,那只能用特定系统的非标准接口,不仅权限要求高,还存在兼容性问题,根本没有通用的POSIX级解决方案。

内容的提问来源于stack exchange,提问作者Zibri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:40:22