On 06/20/2011 03:49 PM, Richard Henderson wrote:
>>
>> As I have already stated, if we *cannot* require pointers to be
>> zero-extended on entry to the kernel, we're going to have to have
>> special entry points for all the x32 system calls except the ones that
>> don't take pointers.
> 
> If it's a security concern, surely you have to do it in the kernel
> anyway, lest someone call into the kernel via their own assembly
> rather than something controlled by the compiler...
> 

That was the point... right now we rely on the ABI to not have any
invalid representations (except, as far as I know, on s390).  This means
any arbitrary register image presented to the kernel will be a set of
valid C objects; we then accept or reject them as being semantically
valid using normal C code in the kernel.

The issue occurs when the kernel can be entered with something in the
register that is invalid according to the calling convention, and not
have it rejected.

The current x86-64 ABI rules, for example, imply that if
%rdi = 0x3fb8c9119537d37d and the type of the first argument is
uint32_t, that is a valid argument with the value 0x9537d37d.  The extra
upper bits are ignored, and so no security issue arises.

The issue with requiring the upper bits to be normalized occurs with
code like:

static const long foo_table[10] = { ... };

long sys_foo(unsigned int bar)
{
        if (bar >= 10)
                return -EINVAL;

        return foo_table[bar];
}


If the upper bits are required to be zero, gcc could validly translate
that to:

sys_foo:
        cmpl    $10, %edi
        jae     .L1

        movq    foo_table(,%rdi,3), %rax
        retq
.L1:
        movq    $-EINVAL, %rax
        retq

Enter this function with a non-normalized %rdi and you have a security
hole even though the C is perfectly fine.

        -hpa


        

Reply via email to