Linux用户态下判断一个指针的合法性

Windows下面就不多说了:IsBadReadPtr,IsBadStringPtr,IsBadWritePtr。

Linux内核态可以用__access_ok函数来判断内存区域的访问性。
用户态自己写了一个,就是利用了段错误这个信号,然后处理这个信号。用siglongjmp和sigsetjmp在栈里面跳转。

直接Posix族的代码贴出来,应该还有一些小bug,有待继续完善
只把读取权限的写了,别的同理



#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>

/*
x86/Linux、x86/Solaris、SPARC/Solaris will sigal SIGSEGV
x86/FreeBSD、x86/NetBSD、x86/OpenBSD MacOS will sigal SIGBUS
*/

#if defined(__MACH__) && defined(__FreeBSD__) && defined(__NetBSD__) && defined(__OpenBSD__)\
    && defined(__DragonFly__)
#define ERROR_SIGNAL SIGBUS
#else
#define ERROR_SIGNAL SIGSEGV
#endif

static sigjmp_buf badreadjmpbuf;


static void badreadfunc(int signo)
{
    /*write(STDOUT_FILENO, "catch\n", 6);*/
    siglongjmp(badreadjmpbuf, 1);
}


int isbadreadptr(void *ptr, int length)
{
    struct sigaction sa, osa;
    int ret = 0;

    /*init new handler struct*/
    sa.sa_handler = badreadfunc;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    /*retrieve old and set new handlers*/
    if(sigaction(ERROR_SIGNAL, &sa, &osa)<0)
        return (-1);

    if(sigsetjmp(badreadjmpbuf, 1) == 0)
    {
        int i, hi=length/sizeof(int), remain=length%sizeof(int);
        int* pi = ptr;
        char* pc = (char*)ptr + hi;
        for(i=0;i<hi;i++)
        {
            int tmp = *(pi+i);
        }
        for(i=0;i<remain;i++)
        {
            char tmp = *(pc+i);
        }

    }
    else
    {
        ret = 1;
    }

    /*restore prevouis signal actions*/
    if(sigaction(ERROR_SIGNAL, &osa, NULL)<0)
        return (-1);

    return ret;
}


int main()
{
    int *p = 0;
    int flag;
    int testint = 1234567890, *teststack = &testint;
    int * testheap = malloc(sizeof(int) * 10);

    printf("bad ptr %d\n", isbadreadptr(p, 4));
    printf("bad ptr %d\n", isbadreadptr(teststack, 4));
    printf("bad ptr %d\n", isbadreadptr(testheap, 40));
    free(testheap);


    printf("exiting main\n");
    return 0;
}

你可能感兴趣的:(linux,windows,Solaris,Access,FreeBSD)