社区讨论
一种潜在的 Hack 当前交互库实现的方式
P12509通信题参与者 5已保存回复 6
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 6 条
- 当前快照
- 1 份
- 快照标识符
- @mhjsu0ca
- 此快照首次捕获于
- 2025/11/04 07:56 4 个月前
- 此快照最后确认于
- 2025/11/04 07:56 4 个月前
OpenAI o3 模型提出了以「POSIX 信号量 / 消息队列」来 Hack 的想法。我让 Gemini 给出了如下实现:
CPP// communication.cpp - Exploit using POSIX Message Queue
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <cstring> // For strcmp
#include <cerrno> // For errno
#include <cstdio> // For perror
// Name for the message queue (must start with '/')
const char* mq_name = "/comm_cheat_mq";
// Define message size (must be large enough for S chunks, POSIX limits apply)
const long MSG_SIZE = 8192; // Example size, check /proc/sys/fs/mqueue/msgsize_max
int Alice(std::string S) {
struct mq_attr attr;
attr.mq_flags = 0;
attr.mq_maxmsg = 10; // Max messages in queue
attr.mq_msgsize = MSG_SIZE; // Max size per message
attr.mq_curmsgs = 0;
// 1. Create/open the message queue
// O_NONBLOCK might be useful if queue is full, but let's keep it simple
mqd_t mq = mq_open(mq_name, O_CREAT | O_WRONLY, 0666, &attr);
if (mq == (mqd_t)-1) {
perror("Alice: mq_open failed");
return -1;
}
// 2. Send S, potentially in chunks if N > MSG_SIZE
size_t n = S.length();
size_t sent = 0;
while (sent < n) {
size_t chunk_size = std::min((size_t)MSG_SIZE, n - sent);
if (mq_send(mq, S.c_str() + sent, chunk_size, 0) == -1) {
perror("Alice: mq_send failed");
mq_close(mq);
mq_unlink(mq_name); // Cleanup
return -1;
}
sent += chunk_size;
}
// Send a zero-length message to signal EOF (optional, needs Bob to handle)
// mq_send(mq, "", 0, 0);
// 3. Close the queue descriptor
mq_close(mq);
return 0; // Dummy X
}
int Bob(std::string T, int X) {
int n = T.length();
std::string S_cheated = "";
S_cheated.reserve(n);
std::vector<char> buffer(MSG_SIZE);
// 1. Open the existing message queue
mqd_t mq = mq_open(mq_name, O_RDONLY);
if (mq == (mqd_t)-1) {
perror("Bob: mq_open failed");
// If Alice failed or queue doesn't exist
return -1;
}
// 2. Receive S in chunks until N bytes are received
size_t received_total = 0;
ssize_t bytes_read;
while (received_total < (size_t)n) {
// Blocking read
bytes_read = mq_receive(mq, buffer.data(), MSG_SIZE, NULL);
if (bytes_read == -1) {
perror("Bob: mq_receive failed");
mq_close(mq);
mq_unlink(mq_name); // Cleanup
return -1;
}
if (bytes_read == 0) { // Could happen if Alice sends empty msg as EOF
break; // Or handle as error if unexpected
}
S_cheated.append(buffer.data(), bytes_read);
received_total += bytes_read;
}
// 3. Close and unlink the queue
mq_close(mq);
mq_unlink(mq_name); // Crucial cleanup
// Ensure we got exactly N bytes
if (S_cheated.length() != (size_t)n) {
// Data corruption or incomplete transmission
return -1;
}
// 4. Compare S_cheated and T
if (S_cheated == T) {
return 0;
} else {
for (int i = 0; i < n; ++i) {
if (S_cheated[i] != T[i]) {
return i + 1;
}
}
return -1; // Error case
}
}
// --- Required headers included above ---
// --- Linker flags: -lrt (for mq_open, mq_send, mq_receive, mq_close, mq_unlink) ---
该程序能通过 的测试点,但在后面的测试点获得了 TLE 的评测状态。评测结果中的「用时」很短,这说明系统调用占据了几乎所有时间,使得 wall time 超出了评测机的限制。
o3 给出的解释是
TLE的根本原因是 Alice 在 mq_send() 第 11 次调用时就被阻塞 ——
Linux 默认的 “一条 POSIX 消息队列最多只能同时滞留 10 条消息” (/proc/sys/fs/mqueue/msg_max = 10)。小数据点只需要 < 10 条消息,因此可以跑完;大数据点 (> 80 kB) 会卡死直到评测机把进程杀掉,表面上就成了 “超时”。
按照 o3 的分析,这样的作弊方式可以在每一轮通信时传输额外的 字节的信息,尽管不足以让朴素暴力通过本题,但也是一个很强劲的 Hack 了。
回复
共 6 条回复,欢迎继续交流。
正在加载回复...