[PATCH] new x86 personality detection

Denys Vlasenko dvlasenk at redhat.com
Tue Feb 12 10:12:29 UTC 2013


On 02/12/2013 01:51 AM, Dmitry V. Levin wrote:
> On Mon, Feb 11, 2013 at 03:12:23PM +0100, Denys Vlasenko wrote:
>> On 02/11/2013 01:46 PM, Denys Vlasenko wrote:
>>> On 02/11/2013 12:45 PM, Denys Vlasenko wrote:
>>>> This patch implements a (hopefully) correct way to check for
>>>> syscall bitness on x86.
>>>>
>>>> I tested it to work when stracing normal 32-bit binaries,
>>>> can't test the above example till this evening.
>>>> But it should work too (famous last words?).
>>>>
>>>> Please review.
>>>
>>> Looks like we had a bug on X32:
>>>
>>> 	if (check_errno && is_negated_errno(x86_64_regs.rax)) {
>>>
>>> If we build in X32 environment, above we check only lower 32 bits of rax
>>> - because is_negated_errno() takes _long_ parameter, which is 32-bit
>>> on X32. Therefore e.g. llseek returning a valid offset of 0xfffffffe
>>> will be mishandled as returning errno 2.
>>>
>>> The updated patch also includes fix for this bug.
>>
>> ...the slight problem that my code... doesn't fix the bug :(
>>
>> +is_negated_errno_ll(unsigned long long val)
>> +{
>> +	unsigned long long max = -(long long) nerrnos;
>> +#if SUPPORTED_PERSONALITIES > 1
>> +	if (current_wordsize < sizeof(val)) {
>> +		val = (unsigned int) val;
>> +		max = (unsigned int) max;
>> +	}
>> +#endif
>> +	return val > max;
>> +}
>>
>> The above _always_ falls into "if", since current_wordsize == 4
>> even for native X32.
>> Looks like I'll have to resort to x32-specific checking function:
>>
>> +static inline int
>> +is_negated_errno_x32(unsigned long long val)
>> +{
>> +       unsigned long long max = -(long long) nerrnos;
>> +       /*
>> +        * current_wordsize == 4 even in personality 0 (X32)
>> +        * but truncation _must not_ be done in it.
>> +        * can't check current_wordsize here!
>> +        */
>> +       if (current_personality != 0) {
>> +               val = (uint32_t) val;
>> +               max = (uint32_t) max;
>> +       }
>> +       return val > max;
>> +}
> 
> I suppose this is not necessarily limited to X32, it can happen on any
> architecture with ext_arg and u_lrval.

Yes.

However, "any architecture" for now is just one: x32.

There are only two archs with ext_args: x32 and mipsn32, and
mipsn32 does not use "negated errno" mechanism for signalling errors,
apparently its API dedicated a register for that:

#elif defined(MIPS)
        if (check_errno && a3) {
                tcp->u_rval = -1;
                u_error = r2;
        } else {
                tcp->u_rval = r2;
# if defined(LINUX_MIPSN32)
                tcp->u_lrval = r2;
# endif
        }
#elif

> Maybe i's worth introducing some kind of
> personality_is_negated_errno[current_personality] and changing
> is_negated_errno to a macro.

I tried introducing word_mask[personality] array but it ended up
looking ugly.

I think we can postpone this until we have more than one arch
to worry about. Many people think that creating x32 arch
(in general, not just in strace) wasn't worth the hassle.
It's conceivable no other 64-bit arch will go down that route.

-- 
vda




More information about the Strace-devel mailing list