#CCSP2026A. 沙箱代理审计

    ID: 732 Type: Default 5000ms 2048MiB Tried: 42 Accepted: 3 Difficulty: 3 Uploaded By: Tags>CCSP模拟字符串处理STL字符串Trie树数据结构平衡树

沙箱代理审计

题目来自 CCSP2026 T1,评测使用官方数据和自造高质量复刻数据。我们承认原始题面、大样例、官方数据版权均归中国计算机学会(CCF)所有,因此题面与评测服务均免费对外开放。如果您认为我们侵犯了您的权益,可联系我们。

综合数据范围、民间数据、场上选手提交,我们将原本时空限制的 1.0 秒/512 MB 调整为 5.0 秒/2048 MB。

由于官方数据在正确性与时间空间强度均过弱,我们将给出子任务内的数据分布:对于子任务 1 到 3,前 2 个数据为官方数据;对于子任务 4,前 4 个数据为官方数据;子任务内的其余后续数据均为民间数据。当前 3 个子任务评测通过后才会开启子任务 4 的评测。

目前一部分用户的已通过代码仍旧可以被持续 hack,但是综合考虑后我们决定不再新增 hack 数据。

时间限制: 1.0 秒 5.0 秒

空间限制: 512 MB 2048 MB

题目描述

某代码平台允许自动化代理(Agent)读取文件、修改工作区和执行命令,并通过沙箱规则控制权限。请你实现一个审计器,按顺序处理授权和工具调用,判断每次调用能否执行,并维护文件的存在状态。

1. 初始状态

所有代理共用权限规则和文件状态。初始时没有文件,也没有任何权限。授权一旦加入便始终有效。代理编号仅标识来源,不影响审计结果。

2. 路径规范化

文件用相对路径表示。路径只包含小写字母、数字、点号 . 和斜杠 /,不含下划线 _,不以 / 开头或结尾,也不含连续的 /。

路径以 / 分隔为若干段。测试数据可能出现 .、.. 路径段。把路径按 / 切分后,逐段比较该段的全部内容:某段恰好为 . 时,按当前目录处理;某段恰好为 .. 时,按上一级目录处理。只要这一段还含有其他字符,它就是普通名称,不作特殊处理。例如,...、....、.git、a..b 均为普通名称。

处理任何路径前,均须从左到右进行规范化:

  1. 遇到 . 段时,忽略该段;
  2. 遇到 .. 段时,删除前面最近的一个尚未被删除的普通路径段;
  3. 遇到其他路径段时,保留该段。

输入保证规范化过程中不会越过沙箱根目录,且规范化结果非空。权限规则、目录边界匹配和文件存在性判断均使用规范化后的路径。

例如,./src 规范化后为 src;docs/./guide/../readme 与 docs/readme 表示同一个文件;规则路径 src/lib/.. 规范化后为 src;pkg/.../file 规范化后仍为 pkg/.../file。

3. 权限规则

权限分为读、写和执行三类,分别授权,互不替代。

  • READ p:允许读取路径 p 及其所有子路径;
  • WRITE p:允许写入或删除路径 p 及其所有子路径;
  • EXEC c:允许执行以完整单词序列 c 为前缀的命令。

路径按目录边界匹配:规则 src 能匹配 src、src/main.c 和 src/lib/a.c,但不能匹配 src2/main.c。

命令按空格分词后匹配:只有调用命令开头的若干个完整单词与某条执行规则完全相同时,才具有执行权限。例如,规则 git status 能匹配 git status 和 git status -s,但不能匹配 git 或 git status2。

4. 工具调用与判定顺序

调用有以下四种操作。文件操作只处理参数指定的那个文件,不递归处理其他路径。

操作 所需权限 成功条件及效果
read 读权限 文件已存在;不改变文件状态。
write 写权限 不要求文件已存在;成功后文件存在。
delete 文件已存在;成功后文件不存在。
exec 执行权限 命令匹配至少一条执行规则;不改变文件状态。

对每条调用,严格按以下顺序判断:

  1. 若缺少所需权限,输出 DENIED,文件状态不变;
  2. 否则,若操作为 read 或 delete,且文件不存在,输出 ERROR,文件状态不变;
  3. 否则,输出 OK,并按上表更新文件状态。

输入格式

从标准输入读入数据。

第一行包含一个整数 mm,表示事件数量。接下来 mm 行,每行是一条事件,格式为以下四种之一:

ALLOW_READ p
ALLOW_WRITE p
ALLOW_EXEC c
CALL id op arg

前三种事件分别增加一条读、写或执行规则。p 为路径;c 为命令前缀,可以包含空格,取该行 ALLOW_EXEC 之后的完整内容。

CALL 表示一次工具调用。id 为代理编号,op 为 read、write、delete、exec 之一。参数 arg 不含空格:

  • 当 op 不是 exec 时,arg 为路径;
  • 当 op 为 exec 时,arg 用下划线 _ 表示命令中的空格。判断前须先将 _ 还原为空格,例如 git_status_-s 表示 git status -s。真实命令单词中不含下划线。

只有 CALL 中的命令参数使用上述下划线编码;输入中的所有路径(包括 op 不是 exec 时的 CALL arg)均不含下划线 _。

输出格式

输出到标准输出。

对每条 CALL 事件输出一行 OK、DENIED 或 ERROR,顺序与调用出现的顺序相同。授权事件不产生输出。

10
CALL 1 read src/main.c
ALLOW_WRITE src
CALL 1 write src/main.c
ALLOW_READ src
CALL 2 read src/main.c
CALL 1 delete src/main.c
CALL 2 read src/main.c
ALLOW_EXEC git status
CALL 1 exec git_status_-s
CALL 1 exec git_commit
DENIED
OK
OK
OK
ERROR
OK
DENIED

样例 1 解释

样例共有 7 条调用,输出 7 行。

  • 首次读取未授权,输出 DENIED;
  • 写入、读取、删除依次成功;
  • 再次读取时文件已不存在,输出 ERROR;
  • git status -s 匹配规则 git status,输出 OK;
  • git commit 不匹配,输出 DENIED。

子任务

对于所有测试数据,1≤m≤2×1051 \le m \le 2 \times 10^5;每个路径和命令的长度不超过 100100;代理编号不超过 10910^9。所有路径均满足前述规范化保证。

本题采用捆绑测试,你只有通过一个子任务中的所有测试点才能得到该子任务的分数。

子任务 分值 特殊限制
1 20 调用操作只有 read 和 write
2 规范化后,仅测试权限规则与调用路径完全相同的匹配,不测试祖先目录匹配
3 不包含 ALLOW_EXEC 和 exec
4 40 无