* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/capability.h>
#include <linux/cred.h>
#include <linux/nsproxy.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/fcntl.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/path.h>
#include <linux/fs.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
#include <linux/sched/task.h>
#endif
#include "pbl/pbl_runenv_config.h"
#include "runenv_config_module.h"
#include "docker_query.h"
#include "ka_common_pub.h"
#include "ka_task_pub.h"
extern struct task_struct init_task;
static bool is_admin_task(struct task_struct *tsk)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
kernel_cap_t privileged = (kernel_cap_t) {((uint64_t)(CAP_TO_MASK(CAP_AUDIT_READ + 1) -1) << 32) | (((uint64_t)~0) >> 32)};
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
unsigned int i;
kernel_cap_t privileged = (kernel_cap_t){{ ~0, (CAP_TO_MASK(CAP_AUDIT_READ + 1) -1)}};
#else
unsigned int i;
kernel_cap_t privileged = CAP_FULL_SET;
#endif
const struct cred *cred = NULL;
kernel_cap_t effective;
unsigned int user_id;
rcu_read_lock();
cred = __task_cred(tsk);
user_id = cred->uid.val;
effective = cred->cap_effective;
rcu_read_unlock();
#ifndef EMU_ST
if (cred->user_ns != &init_user_ns) {
return false;
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
if ((effective.val & privileged.val) != privileged.val) {
return false;
}
#else
CAP_FOR_EACH_U32(i)
{
if ((effective.cap[i] & privileged.cap[i]) != privileged.cap[i]) {
return false;
}
}
#endif
if (user_id == 0) {
return true;
} else {
return false;
}
}
STATIC bool cgroup_mount_is_ro(void)
{
struct path kernel_path;
int ret;
bool is_ro = false;
ret = kern_path("/sys/fs/cgroup/memory", 0, &kernel_path);
if (ret != 0) {
return false;
}
if (kernel_path.mnt == NULL) {
recfg_err("Cgroup memory path mount is NULL.\n");
path_put(&kernel_path);
return false;
}
is_ro = __mnt_is_readonly(kernel_path.mnt);
path_put(&kernel_path);
return is_ro;
}
bool dbl_current_is_admin(void)
{
if (!is_admin_task(current)) {
return false;
}
if (cgroup_mount_is_ro()) {
return false;
}
return true;
}
EXPORT_SYMBOL(dbl_current_is_admin);
static int task_struct_check(struct task_struct *tsk)
{
if (tsk == NULL) {
recfg_err("The tsk is NULL\n");
return -EINVAL;
}
if (tsk->nsproxy == NULL) {
recfg_err("The tsk->nsproxy is NULL\n");
return -ENODEV;
}
if (tsk->nsproxy->mnt_ns == NULL) {
recfg_err("The tsk->nsproxy->mnt_ns is NULL\n");
return -EFAULT;
}
return 0;
}
static struct mnt_namespace *get_current_mnt_ns(void)
{
int ret;
ret = task_struct_check(current);
if (ret) {
recfg_err("Current is invalid. (ret=%d)\n", ret);
return NULL;
}
return ka_task_get_current_mnt_ns();
}
static struct mnt_namespace *get_host_mnt_ns(void)
{
return init_task.nsproxy->mnt_ns;
}
static bool check_in_host_mach(void)
{
struct mnt_namespace *current_ns = NULL;
struct mnt_namespace *host_ns = NULL;
current_ns = get_current_mnt_ns();
if (current_ns == NULL) {
return false;
}
host_ns = get_host_mnt_ns();
if (host_ns == NULL) {
return false;
}
if (current_ns == host_ns) {
return true;
}
return false;
}
bool run_in_normal_docker(void)
{
if ((!check_in_host_mach()) && (!dbl_current_is_admin())) {
recfg_debug("In normal docker.\n");
return true;
}
return false;
}
EXPORT_SYMBOL(run_in_normal_docker);
bool run_in_admin_docker(void)
{
if ((!check_in_host_mach()) && dbl_current_is_admin()) {
recfg_debug("In admin docker.\n");
return true;
}
return false;
}
bool run_in_docker(void)
{
if (!check_in_host_mach()) {
recfg_debug("In docker.\n");
return true;
}
return false;
}
EXPORT_SYMBOL(run_in_docker);
int dbl_host_pid_to_container_pid(pid_t host_pid, pid_t *container_pid)
{
#ifndef DMS_UT
ka_struct_pid_t *pgrp = NULL;
ka_task_struct_t *tsk = NULL;
if (!run_in_docker()) {
*container_pid = host_pid;
return 0;
}
ka_for_each_process(tsk) {
if ((tsk != NULL) && (tsk->pid == host_pid)) {
pgrp = task_pid(tsk);
if (pgrp == NULL) {
recfg_err("The process group parameter is NULL.\n");
return -EINVAL;
}
*container_pid = pgrp->numbers[pgrp->level].nr;
break;
}
}
#endif
return 0;
}
EXPORT_SYMBOL(dbl_host_pid_to_container_pid);