Files
MeowOS-For-R3P2/patch_v2/meowpkg/test_fmt_utc.c
T
AskaEth cf5703b32b fix(nyai): M35 评审 r1 — 闭合 exFAT 大小写绕过(P1)+ 修 fmt_utc 1/2 月 + 成员名/炸弹纵深
P1(信任边界):is_system_pkg() 原用 strncmp,而落盘目录在 exFAT(名字比较
不区分大小写)。包内 app.json 写 "OS.MEOW.READER" 时 valid_pkg 放行、
is_system_pkg 返回 0 → 当第三方无签放行 → dst 解析到已装的
MeowAPPs/os.meow.reader → 备份后部署假包并删掉真系统 App(无需私钥)。
三层封堵:
  1) is_system_pkg 改 strncasecmp(前缀判定不再受大小写影响);
  2) valid_pkg 收紧为只收 [a-z0-9._-],并拒绝前导/尾随 '.'(现网包名全小写,
     无兼容代价;tail-dot 同时挡 exFAT/Windows 名字映射怪癖);
  3) 部署前 readdir 检查 MeowAPPs 里是否有与 pkg 仅大小写不同的已装目录
     (有则拒装并报两个名字);部署后再用 readdir 复核 on-disk 名字与清单包名
     逐字节相等,不等则回滚,杜绝「身份不明的 App 目录」。

P2-1:fmt_utc() 的 March-based 月份换算写成 +9(应为 -9),1/2 月会打成
20251901/20251931 且年份不 +1。修正为 int 运算;新增 test_fmt_utc.c
(直接 include nyai.c 测 static 函数)覆盖 epoch/负数、1/1、2/1、2/28、闰年
2/29(2024 与 2000)、3/1、12/31 23:59:59、2038-01-01、int32 上界、2100 非闰。

纵深防御(评审残留风险,一并做):
- tar 成员名净化不再依赖外部 tar:mpk_check_members 解析 tar -tv 的名字,
  拒绝绝对路径 / 含 '..' 组件 / 首字符 '-' / 原始控制字符;解包后 stg_tree_ok
  再用 readdir 的真实名字复核控制字符(tar 列名会把控制字符转义成可见文本,
  原检查会漏)。
- 解压炸弹:累加 tar -tv 的体积,超过 512MB 上限拒装,并加 statvfs
  「剩余空间 ≥ 体积 + 16MB」门禁(解包先于验签,恶意包可在验签前写满卡)。
- 顺手改掉 appmeta.package 注释里「== 文件名茎」的旧语义。

回归:test_nyai.sh 49 → 70 条断言全过(新增:fmt_utc 13 例、大写包名绕过顶替
已装系统包被拒且原 App 未变、尾点包名、与已装目录仅大小写不同、绝对路径/
../ / 首字符 '-' 成员名、控制字符成员名、700MB 解压炸弹),
`-Wall -Wextra` 零告警,二进制可重复构建。

交付:nyai 153,844 B / md5 ef7940ecf5ece993d718ac1d9019cc82(旧 4524ce6b…)。
真机 10.58.215.50 仍不可登录(22 端口 TCP 可连、15-50s 无 banner),本轮
**未做真机复核**,仅宿主验证。
2026-11-10 21:42:37 +08:00

53 lines
2.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* test_fmt_utc.c — fmt_utc() 边界单测(宿主)。
*
* fmt_utc 是 nyai.c 里的 static 函数;这里把 main 改名后直接 include 源码来测,
* 不引入测试框架、不复制实现(避免单测与实现漂移)。
* 覆盖:epoch/负数、1 月、2 月(闰/平)、3 月、12 月 31 日、闰年 2/29、2100 世纪闰年规则、
* 2038 int32 边界。真机时区无关(fmt_utc 固定 UTC)。
*
* 用法:cc -Wall -Wextra test_fmt_utc.c -o test_fmt_utc && ./test_fmt_utc
*/
#define main nyai_main_unused
#include "nyai.c"
#undef main
#include <stdio.h>
#include <string.h>
struct utc_case { long long t; const char *want; };
int main(void)
{
static const struct utc_case cases[] = {
{ 0LL, "t0" }, /* epoch 由调用方定义为「无时间」 */
{ -1LL, "t0" },
{ 1LL, "19700101-000001" },
{ 1LL * 1767225600, "20260101-000000" }, /* 2026-01-01(曾打成 20251901) */
{ 1769904000LL, "20260201-000000" }, /* 2026-02-01(曾打成 20251931) */
{ 1772236800LL, "20260228-000000" }, /* 2026-02-28(平年) */
{ 1709164800LL, "20240229-000000" }, /* 2024-02-29(闰年) */
{ 951782400LL, "20000229-000000" }, /* 2000-02-29(400 年闰) */
{ 4102444800LL, "21000101-000000" }, /* 2100-01-01(非闰世纪) */
{ 1772323200LL, "20260301-000000" }, /* 2026-03-01(March-based 起点) */
{ 1798761599LL, "20261231-235959" }, /* 年末最后一秒 */
{ 2145916800LL, "20380101-000000" },
{ 2147483647LL, "20380119-031407" }, /* int32 time_t 上界 */
};
int fail = 0;
for (unsigned i = 0; i < sizeof cases / sizeof cases[0]; i++) {
char got[32];
fmt_utc(cases[i].t, got, sizeof got);
if (strcmp(got, cases[i].want) != 0) {
printf("FAIL fmt_utc(%lld) = %s, want %s\n",
cases[i].t, got, cases[i].want);
fail++;
}
}
if (fail == 0) {
printf("PASS fmt_utc: %u cases\n", (unsigned)(sizeof cases / sizeof cases[0]));
return 0;
}
printf("FAILED %d/%u\n", fail, (unsigned)(sizeof cases / sizeof cases[0]));
return 1;
}