社区讨论

一种潜在的 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) ---
该程序能通过 n3×104n\leq 3 \times 10^4 的测试点,但在后面的测试点获得了 TLE 的评测状态。评测结果中的「用时」很短,这说明系统调用占据了几乎所有时间,使得 wall time 超出了评测机的限制。
o3 给出的解释是
TLE 的根本原因是 Alice 在 mq_send() 第 11 次调用时就被阻塞 ——
Linux 默认的 “一条 POSIX 消息队列最多只能同时滞留 10 条消息” (/proc/sys/fs/mqueue/msg_max = 10)。
小数据点只需要 < 10 条消息,因此可以跑完;大数据点 (> 80 kB) 会卡死直到评测机把进程杀掉,表面上就成了 “超时”。
按照 o3 的分析,这样的作弊方式可以在每一轮通信时传输额外的 8192×108192 \times 10 字节的信息,尽管不足以让朴素暴力通过本题,但也是一个很强劲的 Hack 了。

回复

6 条回复,欢迎继续交流。

正在加载回复...