【问题标题】:mprotect and file handlesmprotect 和文件句柄
【发布时间】:2014-04-23 07:48:17
【问题描述】:

我有一个简单的程序,我试图保护一块内存,然后将一个文件读入该内存,当它发生段错误时释放它.. 首先我认为只有文件是fifo才会有问题。但现在看来即使是普通文件也失败了,

这是代码:

#include <errno.h>
#include <string.h>
#include <iostream>
#include <assert.h>
#include <malloc.h>
#include <sys/mman.h>
#include <unistd.h>
#include <map>
#include <algorithm>
#include <unistd.h>
#include <signal.h>
using namespace std;

#define BUFFER_SIZE 8000
#define handle_error(msg) \
    do { cout << __LINE__ << endl ;perror(msg); exit(EXIT_FAILURE); } while (0)

volatile int fault_count = 0;
char* buffer = 0;
int size = 40960;

int my_fault_handler(void* addr, int serious) {
    if (mprotect(buffer, size,
                 PROT_READ | PROT_WRITE) == -1)
         handle_error("mprotect");
    ++fault_count;
    cout << "Segfaulting" << endl;
    return 1;
}


static void handler(int sig, siginfo_t *si, void *unused) {
    my_fault_handler(si ->si_addr, sig);
}
int main (int argc, char *argv[])
{
    long pagesize = sysconf(_SC_PAGESIZE);
    struct sigaction sa;

   sa.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = &handler;
    if (sigaction(SIGSEGV, &sa, NULL) == -1)
        perror("sigaction");

    cerr << "pageSize: " << pagesize << endl;

    buffer = (char*)memalign(pagesize, size);
    if (buffer == NULL)
        handle_error("memalign");
    if (mprotect(buffer, size, PROT_READ) == -1)
        handle_error("mprotect");

    FILE* file = fopen("test", "r");
    cout << "File Open" << endl;
    if (!file) {
        cout << "Failed opening file " << strerror(errno) << endl;
        return 0;
    }

    //*buffer = 0;
    while(fread(buffer, pagesize*2, 1, file)) {
       if (mprotect(buffer, size,
                    PROT_READ) == -1)
            handle_error("mprotect");
    }
    cout << ' ' << strerror(errno) << endl;

    return(0);
}

注意 //*buffer = 0;,如果我取消标记此行,程序会出现段错误并正常工作.. 有人知道吗? errno 是错误的地址。

谢谢!

更新: 这里似乎问了一个类似的问题: Loading MachineCode From File Into Memory and Executing in C -- mprotect Failing 在建议 posix_memalign 的地方,我已经尝试过了,但没有成功。

【问题讨论】:

  • 您能否准确解释一下当您在未更改的情况下运行程序时会发生什么,以及您期望会发生什么?对我来说,程序将页面大小打印为 4096,然后是“文件打开”,然后是“成功”。这发生在未更改的程序和取消注释 *buffer = 0 行之后。
  • 您有“测试”文件吗?对我来说,当我评论 *buffer = 0;我得到一个错误的地址错误,当文件正在读取时没有段错误
  • 可以添加你使用的编译器命令行吗?
  • 我创建了一个空的test 文件用于测试目的。编译器调用就像g++ a.c 一样简单。 (我还必须删除 #include &lt;sigsegv.h&gt; 行,因为我的系统上不存在该头文件。)
  • 是的,这不是必需的,您能否在 segfault 函数中添加一个 cout 以确保您在两种情况下都存在 segfaulting?我也用过简单的 g++

标签: c++ linux file mprotect


【解决方案1】:

问题是您没有在短读后检查 FILE 句柄中的错误。

系统会告诉您第一个 fread 失败并且没有触发故障处理程序。

如果您在循环外检查ferror(例如草率):

while(fread(buffer, pagesize*2, 1, file)) {
   if (mprotect(buffer, size,
                PROT_READ) == -1)
        handle_error("mprotect");
}
if (ferror(file) != 0) {
    cout << "Error" << endl;
}

它失败的原因是底层read 失败,并返回了14 (EFAULT) 的错误号,这与在这种情况下读取失败时记录的情况不太一样(它说@987654327 @)

当有问题的代码在用户上下文中运行时,您只能信任在 mprotect 情况下触发的信号处理程序,大多数 system 调用将失败并返回EFAULT,在这种情况下缓冲区无效或没有正确的权限。

【讨论】:

  • 是的,我确实打印出错误是 EFAULT 和错误地址.. 所以你的回答是没有解决方案?缓冲区必须有效?没有其他接口吗?
  • 在依赖系统调用的情况下,您绝对不能保证当缓冲区的权限与所需的权限不同时会调用您的处理程序 - 它通常会以EFAULT errno 失败.如果你读入一个临时的、可写的缓冲区并 memcpy'd 到你会得到触发信号的地址。
  • 是的,但是我得到了整个缓冲区的额外 memcpy。
  • 是的,但这几乎是保证调用信号处理程序的唯一方法。您可以检查短读取、错误状态和EFAULT errno,然后手动触发保护更改,省去处理信号触发的开销。
  • 我会给你一个 +1,但除非你向我展示不能保证我的 seg 处理程序的文档 :)
猜你喜欢
  • 2011-09-04
  • 1970-01-01
  • 2017-08-14
  • 2016-02-05
  • 1970-01-01
  • 1970-01-01
  • 2014-08-28
  • 2010-09-09
  • 1970-01-01
相关资源
最近更新 更多