LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Probing a virtual memory address. (https://www.linuxquestions.org/questions/programming-9/probing-a-virtual-memory-address-672386/)

cyent 09-25-2008 05:32 PM

Probing a virtual memory address.
 
Hokay, long long time ago, I worked on a Vax machine.

It had a nifty OS call that allowed you to probe a memory address and find out if you could read or write to it. (They were based on machine code instructions PROBER and PROBEW, power pc architecture has 'em too.)

Sure you can do...
int isWritable( int * p)
int tmp = *p;
int result = 0;
*p = tmp+1;
result = *p == (tmp+1);
*p = tmp;
return result;
}
but if there is nothing there you'll segfault, and if there is DMA hardware there... who knows what will happen.

Is there a linux routine I can invoke to work out if an address is writable?

jlliagre 09-26-2008 01:36 AM

I would look at pmap source code. "pmap -x pid" is displaying the infomation needed.

cyent 09-28-2008 05:37 PM

Quote:

Originally Posted by jlliagre (Post 3292168)
I would look at pmap source code. "pmap -x pid" is displaying the infomation needed.

Actually pmap is remarkably crude about it, it is just printing /proc/PID/maps to the screen!

(To trivially see that, run "strace pmap -x PID")

Anything better out there?

jlliagre 09-28-2008 05:45 PM

I'm missing why you discard pmap and its Linux implementation. All the information you need is there, isn't it ?

cyent 09-28-2008 05:59 PM

IsValidDataPointer,IsValidFunctionPointer
 
Quote:

Originally Posted by jlliagre (Post 3294450)
I'm missing why you discard pmap and its Linux implementation. All the information you need is there, isn't it ?

Ok, let me take a step back.

I want to implement the following two asserts...

assert( IsValidDataPointer(pointer));

assert( IsValidFunctionPointer(pointer));

So what on ye olde 1980's Vax was a single machine code instruction, using the /proc/PID/maps solution will be open a file, scanf about 100 lines, close file. And scanf is an extraordinarily heavyweight function involving 10's of thousands of machine instructions.

Ok, can be done. Just seems way too heavyweight.

jlliagre 09-28-2008 08:43 PM

I agree it is heavyweight compared to a single machine code instruction but given the fact the x86 architecture is missing these instructions, it has to be done another way. The pmap solution is also probably inaccurate as the pseudo file content might be partially obsoleted by its own parsing. Beware too that a read-only memory address doesn't imply it is executable nor it necessarily points to a valid instruction.

Anyway, here is a quick and dirty portable implementation I just wrote to see if it was doable in C. Make sure compiler optimizations are disabled for the write probe to work.
Code:

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

jmp_buf env;

static void handler(int sig)
{
  signal(SIGSEGV,handler);
  longjmp(env, 1);
}

int prober(void *p)
{
  char *c=(char *)p;
  char z;
  if(setjmp(env)!=0) return(1);
  z=*c;
  return(0);
}

int probew(void *p)
{
  char *c=(char *)p;
  if(setjmp(env)!=0) return(1);
  *c^=0;
  return(0);
}

main(int argc, char **argv)
{
  char s[]="hi there";
  signal(SIGSEGV,handler);
  printf("%s\n", (prober((void *)s))?"Not readable":"Readable");
  printf("%s\n", (probew((void *)s))?"Not writable":"Writable");
  printf("%s\n", (prober((void *)main))?"Not readable":"Readable");
  printf("%s\n", (probew((void *)main))?"Not writable":"Writable");
}


cyent 09-28-2008 10:05 PM

Quote:

Originally Posted by jlliagre (Post 3294562)
Anyway, here is a quick and dirty portable implementation I just wrote to see if it was doable in C. Make sure compiler optimizations are disabled for the write probe to work.

Nah. Don't need to disable optimization, just need volatile....
Code:


int probew(void *p)
{
  volatile unsigned char *c=(volatile char *)p;
  unsigned char temp;
  if(setjmp(env)!=0) return(1);
  // Preserve *c, may segfault if can't read
  temp = *c;
  *c = 0;
  if (*c == 0) // That write seems to have worked,
    if(temp !=0) // Maybe it was 0 anyway
    {
      *c = temp; // Put it back.
      return 0;  // Say it is writable.
    }

  // Well try write a 0xff instead
  *c=0xff;
  if (*c != 0xff) // Whoops, that didn't work
    return 1; // Say not writable.

  *c = temp; // Put it back
  return(0); // Say writable.
}

main(int argc, char **argv)
{
  char s[]="hi there";
  signal(SIGSEGV,handler);
  printf("%s\n", (prober((void *)s))?"Not readable":"Readable");
  printf("%s\n", (probew((void *)s))?"Not writable":"Writable");
  printf("%s\n", (prober((void *)main))?"Not readable":"Readable");
  printf("%s\n", (probew((void *)main))?"Not writable":"Writable");
}

[/QUOTE]

jlliagre 09-29-2008 01:35 AM

Your probew implementation is doing unnecessary tests if your goal is to implement the VAX original instructions and might be destructive too if you are unlucky.

cyent 09-29-2008 03:56 PM

I guess I'm trying to be too portable...
 
Quote:

Originally Posted by jlliagre (Post 3294762)
Your probew implementation is doing unnecessary tests if your goal is to implement the VAX original instructions and might be destructive too if you are unlucky.

The program I want to use this on also runs on an embedded device without MMU, and your test would pass erroneously on areas with no ram. Hmm. But it would screw up DMA devices.

As to the unlucky, I doubt if your test is atomic either. Your test probably also compiles to load to register, do something in register, store to memory.

The sad thing is the routine I want is available in the kernel... It is called "access_ok". It just doesn't seem to be exported into userland.

jlliagre 10-02-2008 08:05 AM

Every program that writes something to a random address might screw up itself of worst, especially if it writes something different than what was there before.

On your embedded device, access_ok might be implemented by using a similar approach than the initial solution I suggested, according to its documentation.

Note that, depending on architecture, this function probably just checks that the pointer is in the user space range - after calling this function, memory access functions may still return -EFAULT.

I'm afraid what you are after has no perfect solution.

cyent 10-02-2008 04:37 PM

Quote:

Originally Posted by jlliagre (Post 3297962)
I'm afraid what you are after has no perfect solution.

Hah! There is one.... VERR and VERW are the x86 machine ops equivalent to the Vax PROBER PROBEW

Now I just need to work out to package it as a snippet of inline assembler, I'm done!


All times are GMT -5. The time now is 08:25 AM.