Re: [PATCH v9 3/5] x86/KASLR: Randomize virtual address separately

From: Ingo Molnar
Date: Fri Jun 17 2016 - 04:35:47 EST



* Ingo Molnar <mingo@xxxxxxxxxx> wrote:

>
> * Kees Cook <keescook@xxxxxxxxxxxx> wrote:
>
> > -unsigned char *choose_random_location(unsigned long input,
> > - unsigned long input_size,
> > - unsigned long output,
> > - unsigned long output_size)
> > +void choose_random_location(unsigned long input,
> > + unsigned long input_size,
> > + unsigned long *output,
> > + unsigned long output_size,
> > + unsigned long *virt_addr)
> > {
> > - unsigned long choice = output;
> > unsigned long random_addr;
> >
> > + /* By default, keep output position unchanged. */
> > + *virt_addr = *output;
>
> So I applied this, after fixing a conflict with a recent hibernation related
> change, but it would be nice to further clean up the types in this file, in
> particular could we please propagate 'const' for all input-only pointers?
>
> For example in the above function it would be obvious at a glance if it said
> something like:
>
> void choose_random_location(unsigned long input,
> unsigned long input_size,
> const unsigned long *output,
> unsigned long output_size,
> unsigned long *virt_addr)
>
> when reading such a function prototype I can immediately tell: 'yeah, while it's
> named "output", it's in fact a read-only input parameter - the _real_ output of
> the function is 'virt_addr'.)

Doh, so I managed to confuse myself by looking at the unpatched function only.
This patch in fact starts writing to 'output':

+ /* Update the new physical address location. */
+ if (*output != random_addr) {
+ add_identity_map(random_addr, output_size);
+ *output = random_addr;
+ }

At which point 'output' cannot be const, and in fact it might be beneficial that
'virt_addr' is passed in by a pointer as well.

The comment of the function definitely needs to be updated:

* it takes the input and output pointers as 'unsigned long'.

... which is not true anymore.

I also find the type flow and naming for the 'output' pointer very confusing. We
have:

asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
unsigned char *input_data,
unsigned long input_len,
unsigned char *output,
unsigned long output_len)

...

choose_random_location((unsigned long)input_data, input_len,
(unsigned long *)&output,
max(output_len, kernel_total_size),
&virt_addr);


void choose_random_location(unsigned long input,
unsigned long input_size,
unsigned long *output,
unsigned long output_size,
unsigned long *virt_addr)

...

*output = random_addr;


it is very easy to confuse 'unsigned long *output' with the 'char *output' pointer
to the output stream! But in reality this is a double pointer and we want to use
it to change the pointer.

So at minimum we should rename 'output' in choose_random_location() to something
like 'output_ptr' - but even better would be to just preserve its natural type and
use 'char * const *' and do a single type cast when setting it.

Same goes for 'virt_addr'.

Agreed?

Thanks,

Ingo