3

Here's the situation:

I'm analysing a programs' interaction with a driver by using an LD_PRELOADed module that hooks the ioctl() system call. The system I'm working with (embedded Linux 2.6.18 kernel) luckily has the length of the data encoded into the 'request' parameter, so I can happily dump the ioctl data with the right length.

However quite a lot of this data has pointers to other structures, and I don't know the length of these (this is what I'm investigating, after all). So I'm scanning the data for pointers, and dumping the data at that position. I'm worried this could leave my code open to segfaults if the pointer is close to a segment boundary (and my early testing seems to show this is the case).

So I was wondering what I can do to pre-emptively check whether the current process owns a particular offset before trying to dereference? Is this even possible?

Edit: Just an update as I forgot to mention something that could be very important, the target system is MIPS based, although I'm also testing my module on my x86 machine.

PeterBelm
  • 798
  • 1
  • 8
  • 22
  • 1
    possible duplicate of [Catching segfaults in C](http://stackoverflow.com/questions/554138/catching-segfaults-in-c) – Yuval Adam Nov 28 '10 at 18:36

4 Answers4

3

Open a file descriptor to /dev/null and try write(null_fd, ptr, size). If it returns -1 with errno set to EFAULT, the memory is invalid. If it returns size, the memory is safe to read. There may be a more elegant way to query memory validity/permissions with some POSIX invention, but this is the classic simple way.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
1

If your embedded linux has the /proc/ filesystem mounted, you can parse the /proc/self/maps file and validate the pointer/offsets against that. The maps file contains the memory mappings of the process, see here

Community
  • 1
  • 1
nos
  • 223,662
  • 58
  • 417
  • 506
  • Thanks for the suggestion, at first this seemed perfect, but when considering how to implement this I realised it could be fairly slow since I'd have to parse it every time ioctl is called. – PeterBelm Nov 28 '10 at 20:00
0

I know of no such possibility. But you may be able to achieve something similar. As man 7 signal mentions, SIGSEGV can be caught. Thus, I think you could

  1. Start with dereferencing a byte sequence known to be a pointer
  2. Access one byte after the other, at some time triggering SIGSEGV
  3. In SIGSEGV's handler, mark a variable that is checked in the loop of step 2
  4. Quit the loop, this page is done.

There's several problems with that.

  • Since several buffers may live in the same page, you might output what you think is one buffer that are, in reality, several. You may be able to help with that by also LD_PRELOADing electric fence which would, AFAIK cause the application to allocate a whole page for every dynamically allocated buffer. So you would not output several buffers thinking it is only one, but you still don't know where the buffer ends and would output much garbage at the end. Also, stack based buffers can't be helped by this method.
  • You don't know where the buffers end.

Untested.

Community
  • 1
  • 1
dennycrane
  • 2,301
  • 18
  • 15
  • 1
    How would this be implemented if the process already has a signal handler for SIGSEGV? I'm not sure if it does or not, but it's a distinct possibility. Can signal handlers be layered? Not knowing where the buffer ends isn't a big problem, for interesting ones I would find out how long it is, I just need a 'catch all' approach to dumping the data for the moment. – PeterBelm Nov 28 '10 at 18:46
  • `signal(2)` returns the pointer to the previously installed handler. You should check for the constants `SIG_IGN` and `SIG_DFL` before dereferencing to call it. If you want to use that on non-Linux Unices it may be worthwhile to use `sigaction(2)` instead. It also allows to query for the previously installed sigaction. – dennycrane Nov 28 '10 at 18:48
0

Can't you just check for the segment boundaries? (I'm guessing by segment boundaries you mean page boundaries?)

If so, page boundaries are well delimited (either 4K or 8K) so simple masking of the address should deal with it.

boatcoder
  • 17,525
  • 18
  • 114
  • 178