最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Check if running inside unprivileged container - Stack Overflow

programmeradmin2浏览0评论

I'm trying to check if my program is running inside an unprivileged container environment. I'm using 4 different heuristics to determine this - ie. checking the uid/gid in /proc/self/uid_map, gid_map, determining if the caller process has some capabilities set, trying to write to something inside /proc/sys as majority of unprivileged containers don't allow mounting host proc as rw.

Is this method correct?

#include <stdio.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/capability.h>

int likely_unpriv_container(void) {
    FILE *fp;
    char buffer[1024];
    unsigned long in_id, out_id, range;
    bool uid_unpriv = false, gid_unpriv = false, has_caps = false, can_write = false;
    int l = 0;
    cap_t caps;
    cap_flag_value_t value;
    int fd;

    fp = fopen("/proc/self/uid_map", "r");
    if (!fp) {
        return -1;
    }

    while (fgets(buffer, sizeof(buffer), fp)) {
        l++;
        if (sscanf(buffer, "%lu %lu %lu", &in_id, &out_id, &range) == 3) {
            if (out_id != 0 || !(in_id == 0 && range == 4294967295)) {
                uid_unpriv = true;
            }
        }
    }
    if (l > 1) {
        uid_unpriv = true;
    }
    fclose(fp);

    fp = fopen("/proc/self/gid_map", "r");
    if (!fp) {
        return -1;
    }

    l = 0;
    while (fgets(buffer, sizeof(buffer), fp)) {
        l++;
        if (sscanf(buffer, "%lu %lu %lu", &in_id, &out_id, &range) == 3) {
            if (out_id != 0 || !(in_id == 0 && range == 4294967295)) {
                gid_unpriv = true;
            }
        }
    }
    if (l > 1) {
        gid_unpriv = true;
    }
    fclose(fp);

    caps = cap_get_proc();
    if (caps) {
        if (cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        if (cap_get_flag(caps, CAP_CHOWN, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        if (cap_get_flag(caps, CAP_DAC_OVERRIDE, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        if (cap_get_flag(caps, CAP_SETFCAP, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        if (cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        cap_free(caps);
    }

    fd = open("/proc/sys/user/max_user_namespaces", O_WRONLY);
    if (fd >= 0) {
        can_write = true;
        close(fd);
    }

    if (uid_unpriv && gid_unpriv && !has_caps && !can_write) {
        return 0;
    } else {
        return -1;
    }
}

I'm trying to check if my program is running inside an unprivileged container environment. I'm using 4 different heuristics to determine this - ie. checking the uid/gid in /proc/self/uid_map, gid_map, determining if the caller process has some capabilities set, trying to write to something inside /proc/sys as majority of unprivileged containers don't allow mounting host proc as rw.

Is this method correct?

#include <stdio.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/capability.h>

int likely_unpriv_container(void) {
    FILE *fp;
    char buffer[1024];
    unsigned long in_id, out_id, range;
    bool uid_unpriv = false, gid_unpriv = false, has_caps = false, can_write = false;
    int l = 0;
    cap_t caps;
    cap_flag_value_t value;
    int fd;

    fp = fopen("/proc/self/uid_map", "r");
    if (!fp) {
        return -1;
    }

    while (fgets(buffer, sizeof(buffer), fp)) {
        l++;
        if (sscanf(buffer, "%lu %lu %lu", &in_id, &out_id, &range) == 3) {
            if (out_id != 0 || !(in_id == 0 && range == 4294967295)) {
                uid_unpriv = true;
            }
        }
    }
    if (l > 1) {
        uid_unpriv = true;
    }
    fclose(fp);

    fp = fopen("/proc/self/gid_map", "r");
    if (!fp) {
        return -1;
    }

    l = 0;
    while (fgets(buffer, sizeof(buffer), fp)) {
        l++;
        if (sscanf(buffer, "%lu %lu %lu", &in_id, &out_id, &range) == 3) {
            if (out_id != 0 || !(in_id == 0 && range == 4294967295)) {
                gid_unpriv = true;
            }
        }
    }
    if (l > 1) {
        gid_unpriv = true;
    }
    fclose(fp);

    caps = cap_get_proc();
    if (caps) {
        if (cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        if (cap_get_flag(caps, CAP_CHOWN, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        if (cap_get_flag(caps, CAP_DAC_OVERRIDE, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        if (cap_get_flag(caps, CAP_SETFCAP, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        if (cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &value) != -1 && value == CAP_SET) {
            has_caps = true;
        }
        cap_free(caps);
    }

    fd = open("/proc/sys/user/max_user_namespaces", O_WRONLY);
    if (fd >= 0) {
        can_write = true;
        close(fd);
    }

    if (uid_unpriv && gid_unpriv && !has_caps && !can_write) {
        return 0;
    } else {
        return -1;
    }
}
Share Improve this question edited Mar 15 at 5:14 Jonathan Leffler 756k145 gold badges951 silver badges1.3k bronze badges asked Mar 15 at 1:53 sjk05sjk05 1416 bronze badges 1
  • Please define "correct" and explain what makes you doubt. – Yunnosch Commented Mar 15 at 8:15
Add a comment  | 

1 Answer 1

Reset to default 1

Your provided method is valid, effective, and correctly implemented.

发布评论

评论列表(0)

  1. 暂无评论