1

I'm trying to write a test in which copy_to_user() fails (only copies some of the data, or none at all, without using NULL pointers), but am unsuccessful.

The test, in user mode has the lines:

type to[1];
foo(to);

foo is a wrapper function which calls a system-call that has the lines:

type from[2] = {something1, something2};
int not_copied = copy_to_user(to, from, sizeof(type) * 2);

It turns out not_copied is 0, even when I try using malloc for the "type to" declaration. Also, 'to[0]' and 'to[1]' are 'something1' and 'something2' respectively.

Am I right in thinking my declaration of 'type to' isn't restricting copy_to_user destination's memory as intended?

And how do I make it fail?

thanks.

Jared
  • 69
  • 3
  • 1
    You could *wrap* `copy_to_user` and implement your own, which would fail. Common approach for testing. More info is [here](https://stackoverflow.com/a/28775374/147407). – Andrejs Cainikovs May 04 '18 at 09:59
  • @AndrejsCainikovs - Want to test my implementation, which uses the copy_to_user function. But thanks, I'm sure your suggestion will come in handy someday. – Jared May 07 '18 at 06:36

2 Answers2

1

As far as I understand, in order for copy_to_user to fail, some of the addresses within the range must actually be unwritable or unmapped. Your type to[1] is just an address somewhere within a page of user-space memory; if it's on the stack, the address right after the end will always be writable because the stack grows down (unless you're on a HPPA, which you almost certainly aren't); if you put it in the data segment, you'd have to set things up very carefully to ensure that it was right at the end of the data segment with nothing immediately afterward; in principle a malloc allocation could have nothing immediately afterward, but unless you're using an allocator like ElectricFence that deliberately puts unmapped guard pages immediately after every allocation, it almost certainly won't.

In order to deliberately set up the situation where the write accesses both accessible and inaccessible memory you could do something like this:

size_t pagesize = sysconf(_SC_PAGESIZE);
char *to_allocation = mmap(0, 2*pagesize, PROT_READ|PROT_WRITE,
                           MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memset(to_allocation, 0x55, 2*pagesize); // force allocation
mprotect(to_allocation + pagesize, pagesize, PROT_NONE);

foo(to_allocation + pagesize - sizeof(type));

(But with error handling, of course.)

zwol
  • 135,547
  • 38
  • 252
  • 361
0

I've managed to make it reliably fail by making these changes:

type to[SMALL_INTEGER]
foo(to)

the wrapper has:

type from[HUGE_INTEGER]
// fill from with huge amount of data <- unsure if this part is necessary
int not_copied = copy_to_user(to, from, sizeof(type) * HUGE_INTEGER);
Jared
  • 69
  • 3