From 9730fa1edbd71997253b8c10f501f68d46e5431e Mon Sep 17 00:00:00 2001 From: xiacong Date: Sat, 4 Nov 2023 11:51:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=86=85=E6=A0=B8=E9=80=83?= =?UTF-8?q?=E9=80=B8=E6=A3=80=E6=B5=8B=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: xiacong Change-Id: If5b8e718fcfd0fa66c0f834bce573a92a0a86201 Signed-off-by: xiacong --- container_escape_detection/Kconfig | 6 + container_escape_detection/Makefile | 8 ++ container_escape_detection/apply_ced.sh | 28 +++++ container_escape_detection/core/ced_driver.c | 105 +++++++++++++++++ container_escape_detection/core/ced_module.c | 22 ++++ .../core/ced_permission.c | 73 ++++++++++++ container_escape_detection/core/ced_record.c | 109 ++++++++++++++++++ .../include/ced_detection.h | 16 +++ container_escape_detection/include/ced_log.h | 22 ++++ .../include/ced_permission.h | 21 ++++ .../include/ced_record.h | 25 ++++ 11 files changed, 435 insertions(+) create mode 100644 container_escape_detection/Kconfig create mode 100644 container_escape_detection/Makefile create mode 100755 container_escape_detection/apply_ced.sh create mode 100644 container_escape_detection/core/ced_driver.c create mode 100644 container_escape_detection/core/ced_module.c create mode 100644 container_escape_detection/core/ced_permission.c create mode 100644 container_escape_detection/core/ced_record.c create mode 100644 container_escape_detection/include/ced_detection.h create mode 100644 container_escape_detection/include/ced_log.h create mode 100644 container_escape_detection/include/ced_permission.h create mode 100644 container_escape_detection/include/ced_record.h diff --git a/container_escape_detection/Kconfig b/container_escape_detection/Kconfig new file mode 100644 index 0000000..35c3c20 --- /dev/null +++ b/container_escape_detection/Kconfig @@ -0,0 +1,6 @@ +config SECURITY_CONTAINER_ESCAPE_DETECTION + bool "Enable container escape detection" + default n + depends on SECURITY + help + Build support for container escape detection. diff --git a/container_escape_detection/Makefile b/container_escape_detection/Makefile new file mode 100644 index 0000000..2d63eaa --- /dev/null +++ b/container_escape_detection/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_SECURITY_CONTAINER_ESCAPE_DETECTION) += core/ced_record.o +obj-$(CONFIG_SECURITY_CONTAINER_ESCAPE_DETECTION) += core/ced_permission.o +obj-$(CONFIG_SECURITY_CONTAINER_ESCAPE_DETECTION) += core/ced_driver.o +obj-$(CONFIG_SECURITY_CONTAINER_ESCAPE_DETECTION) += core/ced_module.o + +ccflags-$(CONFIG_SECURITY_CONTAINER_ESCAPE_DETECTION) := -I$(srctree)/security/container_escape_detection/include +LINUXINCLUDE += -I$(srctree)/security/container_escape_detection/include +export LINUXINCLUDE diff --git a/container_escape_detection/apply_ced.sh b/container_escape_detection/apply_ced.sh new file mode 100755 index 0000000..2d34691 --- /dev/null +++ b/container_escape_detection/apply_ced.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# + +set -e + +OHOS_SOURCE_ROOT=$1 +KERNEL_BUILD_ROOT=$2 +PRODUCT_NAME=$3 +KERNEL_VERSION=$4 +CED_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/container_escape_detection + +function main() +{ + pushd . + + if [ ! -d " $KERNEL_BUILD_ROOT/security/container_escape_detection" ]; then + mkdir $KERNEL_BUILD_ROOT/security/container_escape_detection + fi + + cd $KERNEL_BUILD_ROOT/security/container_escape_detection + ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/security/container_escape_detection/ $CED_SOURCE_ROOT)/* ./ + + popd +} + +main diff --git a/container_escape_detection/core/ced_driver.c b/container_escape_detection/core/ced_driver.c new file mode 100644 index 0000000..bbbafa2 --- /dev/null +++ b/container_escape_detection/core/ced_driver.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * set_detect_flag.c + * + * Copyright (C) 2023 Huawei Technologies Co., Ltd. All rights reserved. + * + */ + +#define pr_fmt(fmt) "container escape: " fmt +#include +#include +#include +#include +#include +#include +#include +#include "ced_record.h" + +#define CONTAINER_ESCAP_IOCTL_BASE 'C' + +enum { + SET_DETECT_FALG, + CONTAINER_DETECTION_MAX_NUM +}; + +#define CONTAINER_ESCAPE_SET_DETECT_FALG \ + _IOW(CONTAINER_ESCAP_IOCTL_BASE, SET_DETECT_FALG, unsigned long long) + + + +int container_escape_set_flag(struct file *file, void __user *uarg) +{ + container_escape_set_flag_hook(current); + return 0; +} + +typedef int (*escape_set_flag_func)(struct file *file, void __user *arg); + +static escape_set_flag_func g_func_array[CONTAINER_DETECTION_MAX_NUM] = { + container_escape_set_flag, +}; + +static long container_escape_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *uarg = (void __user *)arg; + unsigned int func_cmd = _IOC_NR(cmd); + + if (uarg != NULL) { + pr_err("%s: invalid user uarg\n", __func__); + return -EINVAL; + } + + if (_IOC_TYPE(cmd) != CONTAINER_ESCAP_IOCTL_BASE) { + pr_err("%s: container escape magic fail, TYPE=%d\n", + __func__, _IOC_TYPE(cmd)); + return -EINVAL; + } + + if (func_cmd >= CONTAINER_DETECTION_MAX_NUM) { + pr_err("%s: access tokenid cmd error, cmd:%d\n", + __func__, func_cmd); + return -EINVAL; + } + + if (g_func_array[func_cmd]) + return (*g_func_array[func_cmd])(file, uarg); + + return -EINVAL; +} + +static const struct file_operations container_escape_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = container_escape_ioctl, + .compat_ioctl = container_escape_ioctl, +}; + +static struct miscdevice container_escape_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "container_escape_detect", + .fops = &container_escape_fops, +}; + +static int container_set_flag_init_module(void) +{ + int err; + + err = misc_register(&container_escape_device); + if (err < 0) { + pr_err("container_escape_device register failed\n"); + return err; + } + + pr_info("container_escape_device init success\n"); + return 0; +} + +static void container_set_flag_exit_module(void) +{ + misc_deregister(&container_escape_device); +} + +/* module entry points */ +module_init(container_set_flag_init_module); +module_exit(container_set_flag_exit_module); diff --git a/container_escape_detection/core/ced_module.c b/container_escape_detection/core/ced_module.c new file mode 100644 index 0000000..417e411 --- /dev/null +++ b/container_escape_detection/core/ced_module.c @@ -0,0 +1,22 @@ +#include +#include +#include "ced_detection.h" +#include "ced_record.h" + +void ced_register_ced_hooks(void) +{ + REGISTER_HCK_LITE_HOOK(ced_initialize_lhck, initialize_ced); + REGISTER_HCK_LITE_HOOK(record_ced_flag_lhck, record_ced_flag_hook); + REGISTER_HCK_LITE_HOOK(ced_switch_task_namespaces_lhck, switch_task_namespaces_hook); + REGISTER_HCK_LITE_HOOK(ced_detection_lhck, detection_hook); + printk("ced_register_ced_hooks\n"); +} + +static int __init ced_module_init(void) +{ + ced_register_ced_hooks(); + return 0; +} + +module_init(ced_module_init); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/container_escape_detection/core/ced_permission.c b/container_escape_detection/core/ced_permission.c new file mode 100644 index 0000000..d36c806 --- /dev/null +++ b/container_escape_detection/core/ced_permission.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Container escape detection + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include +#include +#include "ced_permission.h" +#include "ced_log.h" + +// static uint64_t init_task_ns_pac = 0; + +static uint64_t process_ns_pac_hash(struct task_struct *task) +{ + uint64_t pac_hash = 0; + uintptr_t ns_ptr = (uintptr_t)task->nsproxy->mnt_ns; + pac_hash ^= ns_ptr; + ns_ptr = (uintptr_t)task->nsproxy->pid_ns_for_children; + pac_hash ^= ns_ptr; + ns_ptr = (uintptr_t)task->nsproxy->net_ns; + pac_hash ^= ns_ptr; + return pac_hash; +} + +bool is_container_process(void) +{ + if (current->nsproxy == NULL) { + // 这个分支正常流程下进不来 + ced_log_info("@@@ %s %d, @@@\n detection container is escape=============", __func__, __LINE__); + return false; + } + uint64_t current_pac_hash = process_ns_pac_hash(current); + uint64_t init_task_ns_pac = process_ns_pac_hash(&init_task); + if (current_pac_hash == init_task_ns_pac) { + return false; + } else { + return true; + } +} + +bool is_derogation_power(void) +{ + const struct cred *cred = get_task_cred(current); + if (cred == NULL) { + return false; + } + const struct cred *init_cred = get_task_cred(&init_task); + if (init_cred == NULL) { + return false; + } + + if (cred->uid.val != init_cred->uid.val + || cred->gid.val != init_cred->gid.val + || cred->euid.val != init_cred->euid.val + || cred->fsuid.val != init_cred->fsuid.val || (cred->uid.val != init_cred->uid.val + && (memcmp(&cred->cap_inheritable, &init_cred->cap_inheritable, sizeof(kernel_cap_t)) + || memcmp(&cred->cap_permitted, &init_cred->cap_permitted, sizeof(kernel_cap_t)) + || memcmp(&cred->cap_effective, &init_cred->cap_effective, sizeof(kernel_cap_t))))) { + return true; + } + + return false; +} + + diff --git a/container_escape_detection/core/ced_record.c b/container_escape_detection/core/ced_record.c new file mode 100644 index 0000000..e9f3e17 --- /dev/null +++ b/container_escape_detection/core/ced_record.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Container escape detection + * + * Copyright (C) 2023 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include "ced_permission.h" +#include "ced_log.h" +#include "ced_record.h" +#include "ced_detection.h" + + +extern struct task_struct init_task; + +void initialize_ced(struct task_struct *task) { + memset((void *)&init_task.ced_flags, 0, sizeof(struct ced_record)); +} + +void record_ced_flag_hook(struct task_struct *task) +{ + if (task->ced_flags.has_security_started == 0) { + return; + } + if (is_container_process()) { + task->ced_flags.is_container_process = 1; + } + + if (is_derogation_power()) { + task->ced_flags.is_derogation = 1; + } +} + +void switch_task_namespaces_hook(struct task_struct *task, struct nsproxy *new) +{ + if (new == NULL) { + return; + } + record_ced_flag_hook(task); + detection_hook(task); +} + +void container_escape_set_flag_hook(struct task_struct *task) +{ + current->ced_flags.has_security_started = 1; + record_ced_flag_hook(task); +} + +bool detection_promotion_privilege(struct task_struct *task) +{ + const struct cred *cred = get_task_cred(task); + const struct cred *init_cred = get_task_cred(task); + bool flag = false; + if (cred->uid.val == init_cred->uid.val + && cred->gid.val == init_cred->gid.val + && !memcmp(&cred->cap_effective, &init_cred->cap_effective, sizeof(kernel_cap_t))) { + flag = true; + } + return flag; +} + +void detection_hook(struct task_struct *task) +{ + if (task == NULL) { + ced_log_info("@@@ %s %d, @@@\n task point is nullptr", __func__, __LINE__); + return; + } + + // 已安全启动 + if (task->ced_flags.has_security_started == 0) { + return; + } + + if (task->nsproxy == NULL){ + ced_log_info("@@@ %s %d, @@@\n task->nsproxy is nullptr", __func__, __LINE__); + database_dump(); + return; + } + + ced_log_info("is_container_process is %d is_container_process() is %d task_struct size %d\n", task->ced_flags.is_container_process, is_container_process(), sizeof(struct task_struct)); + if (task->ced_flags.is_container_process != 0 && (!is_container_process() + ||(task->ced_flags.is_derogation != 0 && detection_promotion_privilege(task)))) { + ced_log_info("@@@ %s %d, @@@\n detection container is escape=============", __func__, __LINE__); + database_dump(); + } +} + +void database_dump(void) +{ + extern struct task_struct init_task; + ced_log_error("################ init task info ####################\n"); + ced_log_error("pid<%d>, ppid<%d>, uid: %d, gid: %d, euid: %d, fsuid: %d,cap_inheritable : 0x%x%x, cap_permitted: 0x%x%x, cap_effective: 0x%x%x, root: 0x%llx, pwd: 0x%llx," + "mnt_ns: 0x%llx, pid_ns: 0x%llx, net_ns: 0x%llx\n", init_task.pid, init_task.real_parent->pid, init_task.cred->uid.val, init_task.cred->gid.val, init_task.cred->euid.val, + init_task.cred->fsuid.val, init_task.cred->cap_inheritable.cap[0], init_task.cred->cap_inheritable.cap[1], init_task.cred->cap_permitted.cap[0], + init_task.cred->cap_permitted.cap[1], init_task.cred->cap_effective.cap[0], init_task.cred->cap_effective.cap[1], &init_task.fs->root, &init_task.fs->pwd, + init_task.nsproxy->mnt_ns, init_task.nsproxy->pid_ns_for_children, init_task.nsproxy->net_ns); + ced_log_error("####################################################\n"); + ced_log_error("pid<%d>, ppid<%d>, uid: %d, gid: %d, euid: %d, fsuid: %d,cap_inheritable : 0x%x%x, cap_permitted: 0x%x%x, cap_effective: 0x%x%x, root: 0x%llx, pwd: 0x%llx," + "mnt_ns: 0x%llx, pid_ns: 0x%llx, net_ns: 0x%llx\n", current->pid, current->real_parent->pid, current->cred->uid.val, current->cred->gid.val, current->cred->euid.val, + current->cred->fsuid.val, current->cred->cap_inheritable.cap[0], current->cred->cap_inheritable.cap[1], current->cred->cap_permitted.cap[0], + current->cred->cap_permitted.cap[1], current->cred->cap_effective.cap[0], current->cred->cap_effective.cap[1], ¤t->fs->root, ¤t->fs->pwd, + current->nsproxy->mnt_ns, current->nsproxy->pid_ns_for_children, current->nsproxy->net_ns); +} \ No newline at end of file diff --git a/container_escape_detection/include/ced_detection.h b/container_escape_detection/include/ced_detection.h new file mode 100644 index 0000000..f04ad77 --- /dev/null +++ b/container_escape_detection/include/ced_detection.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Container escape detection + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include + +void detection_hook(struct task_struct *task); \ No newline at end of file diff --git a/container_escape_detection/include/ced_log.h b/container_escape_detection/include/ced_log.h new file mode 100644 index 0000000..89b17c6 --- /dev/null +++ b/container_escape_detection/include/ced_log.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#ifndef _CED_LOG_H +#define _CED_LOG_H + +#define CED_CHECK_FAILED (-1024) + +#define CED_TAG "ced_kernel" +#define CED_INFO_TAG "I" +#define CED_ERROR_TAG "E" +#define CED_DEBUG_TAG "D" + +#define ced_log_info(fmt, args...) pr_info("[%s/%s]%s: " fmt "\n", \ + CED_INFO_TAG, CED_TAG, __func__, ##args) + +#define ced_log_error(fmt, args...) pr_err("[%s/%s]%s: " fmt "\n", \ + CED_ERROR_TAG, CED_TAG, __func__, ##args) + +#endif /* _CED_LOG_H */ \ No newline at end of file diff --git a/container_escape_detection/include/ced_permission.h b/container_escape_detection/include/ced_permission.h new file mode 100644 index 0000000..cdad451 --- /dev/null +++ b/container_escape_detection/include/ced_permission.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Container escape detection + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _LINUX_CED_PERMISSION_H +#define _LINUX_CED_PERMISSION_H + +#include + +bool is_container_process(void); +bool is_derogation_power(void); + +#endif /* _LINUX_CED_PERMISSION_H */ diff --git a/container_escape_detection/include/ced_record.h b/container_escape_detection/include/ced_record.h new file mode 100644 index 0000000..8f4c09e --- /dev/null +++ b/container_escape_detection/include/ced_record.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Container escape detection + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _LINUX_CED_RECORD_H +#define _LINUX_CED_RECORD_H + +#include +#include + +void kernel_clone_hook(struct task_struct *task); +void commit_creds_hook(const struct cred *cred); +void switch_task_namespaces_hook(struct task_struct *task, struct nsproxy *new); +void container_escape_set_flag_hook(struct task_struct *task); +void database_dump(void); + +#endif /* _LINUX_CED_RECORD_H */ -- Gitee