Lvwenxuan
|
7a03be035e
|
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "pthread.h" // 引入POSIX线程库,用于多线程编程
#include "linux/capability.h" // 引入Linux能力(capabilities)定义,用于权限控制
#include <sys/capability.h> // 引入系统能力接口
#include "it_test_capability.h" // 假设是测试框架或测试相关的头文件
#include <signal.h> // 引入信号处理函数
#include <sys/types.h> // 引入基本数据类型
#include <time.h> // 引入时间处理函数
#define CAP_NUM 2 // 定义能力数组的大小
#define INVAILD_PID 65535 // 定义一个无效的进程ID
#define CHANGE_CHILD_UID 1000 // 定义子进程要更改的用户ID
// 信号处理函数,当前为空实现
static void Sigac(int param)
{
return;
}
// 子进程函数
static void Child()
{
int i = 10; // 循环计数器
signal(25, Sigac); // 设置信号25的处理函数为Sigac
while (i--) { // 循环10次,每次睡眠1秒
sleep(1);
}
// 睡眠10秒后退出
exit(0);
}
// 测试子进程的函数
static int TestChild(VOID)
{
struct __user_cap_header_struct capheader; // 定义能力头部结构体
struct __user_cap_data_struct capdata[CAP_NUM]; // 定义能力数据结构体数组
struct __user_cap_data_struct capdatac[CAP_NUM]; // 定义另一个能力数据结构体数组,用于获取当前能力
struct timespec tp; // 定义时间结构体
int ret; // 定义返回值变量,此处漏写了初始化
// 初始化结构体
(void)memset_s(&capheader, sizeof(struct __user_cap_header_struct), 0, sizeof(struct __user_cap_header_struct)); // 清零能力头部结构体
(void)memset_s(capdata, CAP_NUM * sizeof(struct __user_cap_data_struct), 0, CAP_NUM * sizeof(struct __user_cap_data_struct)); // 清零能力数据结构体数组
capdata[0].permitted = 0xffffffff; // 设置允许的所有能力为全开
capdata[1].permitted = 0xffffffff; // 同上,第二个数据结构体也全开(虽然只用一个)
capheader.version = _LINUX_CAPABILITY_VERSION_3; // 设置能力版本
// 设置能力的有效位
capdata[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SETPCAP); // 允许修改进程能力
capdata[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SETUID); // 允许改变用户ID
capdata[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_KILL); // 允许发送信号
capdata[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_TIME); // 允许改变系统时间
capdata[CAP_TO_INDEX(CAP_SYS_NICE)].effective |= CAP_TO_MASK(CAP_SYS_NICE); // 允许改变调度优先级
// 使用capset设置能力并检查返回值
ret = capset(&capheader, &capdata[0]);
ICUNIT_ASSERT_EQUAL(ret, 0, ret); // 断言capset返回0,表示成功
ret = capget(&capheader, &capdatac[0]); // 获取当前能力
ICUNIT_ASSERT_EQUAL(ret, 0, ret); // 断言capget返回0,表示成功
capheader.pid = INVAILD_PID; // 设置一个无效的PID
ret = capget(&capheader, &capdatac[0]); // 尝试获取无效PID的能力
ICUNIT_ASSERT_EQUAL(ret, -1, ret); // 断言返回-1,表示失败
errno = 0; // 重置errno
capheader.pid = 3; // 设置PID为3
kill(capheader.pid, 0); // 检查PID是否存在
if (errno != ESRCH) { // 如果PID存在
ret = capget(&capheader, &capdatac[0]); // 获取能力
ICUNIT_ASSERT_EQUAL(ret, 0, ret); // 断言成功
printf("e %d,p %d\n", capdatac[0].effective, capdatac[0].permitted); // 打印有效和允许的能力
}
// 类似地,检查PID 4, 5, 6
errno = 0;
capheader.pid = 4;
kill(capheader.pid, 0);
if (errno != ESRCH) {
ret = capget(&capheader, &capdatac[0]);
ICUNIT_ASSERT_EQUAL(ret, 0, ret);
printf("e %d,p %d\n", capdatac[0].effective, capdatac[0].permitted);
}
errno = 0;
capheader.pid = 5;
kill(capheader.pid, 0);
if (errno != ESRCH) {
ret = capget(&capheader, &capdatac[0]);
ICUNIT_ASSERT_EQUAL(ret, 0, ret);
printf("e %d,p %d\n", capdatac[0].effective, capdatac[0].permitted);
}
errno = 0;
capheader.pid = 6;
kill(capheader.pid, 0);
if (errno != ESRCH) {
ret = capget(&capheader, &capdatac[0]);
ICUNIT_ASSERT_EQUAL(ret, 0, ret);
printf("e %d,p %d\n", capdatac[0].effective, capdatac[0].permitted);
}
capheader.pid = 0; // 重置PID为0(当前进程)
// 尝试重置子进程的UID
int pid = fork(); // 创建子进程
if (pid == 0) { // 如果是子进程
ret = setuid(CHANGE_CHILD_UID); // 尝试改变用户ID
ICUNIT_ASSERT_EQUAL(ret, 0, ret); // 断言成功
Child(); // 执行子进程函数
}
sleep(1); // 父进程等待1秒
ret = kill(pid, SIGXFSZ); // 尝试发送SIGXFSZ信号给子进程
ICUNIT_ASSERT_EQUAL(ret, 0, ret); // 断言成功
// 移除KILL能力并再次尝试发送信号,应该失败
capdata[CAP_TO_INDEX(CAP_SYS_NICE)].effective &= ~CAP_TO_MASK(CAP_KILL);
ret = capset(&capheader, &capdata[0]); // 更新能力
ret = kill(pid, SIGXFSZ); // 再次尝试发送信号
ICUNIT_ASSERT_EQUAL(ret, -1, ret); // 断言失败
// 尝试设置系统时间,应该成功然后失败(移除SYS_TIME能力)
tp.tv_sec = 0; // 设置时间为0
tp.tv_nsec = 0; // 纳秒部分也设置为0
ret = clock_settime(CLOCK_REALTIME, &tp); // 尝试设置时间
ICUNIT_ASSERT_EQUAL(ret, 0, ret); // 断言成功
capdata[CAP_TO_INDEX(CAP_SYS_NICE)].effective &= ~CAP_TO_MASK(CAP_SYS_TIME); // 移除SYS_TIME能力
ret = capset(&capheader, &capdata[0]); // 更新能力
ret = clock_settime(CLOCK_REALTIME, &tp); // 再次尝试设置时间
ICUNIT_ASSERT_EQUAL(ret, -1, ret); // 断言失败
// 尝试改变子进程的调度优先级,应该成功然后失败(移除SYS_NICE能力)
struct sched_param param = { 0 }; // 定义调度参数结构体
ret = sched_getparam(pid, ¶m); // 获取当前调度参数
param.sched_priority--; // 降低优先级
ret = sched_setparam(pid, ¶m); // 尝试设置新的调度参数
ICUNIT_ASSERT_EQUAL(ret, 0, ret); // 断言成功
capdata[CAP_TO_INDEX(CAP_SYS_NICE)].effective &= ~CAP_TO_MASK(CAP_SYS_NICE); // 移除SYS_NICE能力
ret = capset(&capheader, &capdata[0]); // 更新能力
ret = sched_setparam(pid, ¶m); // 再次尝试设置调度参数
ICUNIT_ASSERT_EQUAL(ret, -1, ret);
wait(nullptr);
exit(92);
return 0;
}
static int TestCase(VOID)
{
int ret;
int status = 0;
pid_t pid = fork();
ICUNIT_GOTO_WITHIN_EQUAL(pid, 0, 100000, pid, EXIT);
if (pid == 0) {
ret = TestChild();
exit(__LINE__);
}
ret = waitpid(pid, &status, 0);
ICUNIT_GOTO_EQUAL(ret, pid, ret, EXIT);
status = WEXITSTATUS(status);
ICUNIT_GOTO_EQUAL(status, 92, status, EXIT);
return 0;
EXIT:
return 1;
}
void ItTestCap001(void)
{
TEST_ADD_CASE("IT_SEC_CAP_001", TestCase, TEST_POSIX, TEST_SEC, TEST_LEVEL0, TEST_FUNCTION);
}
|
7 months ago |