> On Aug 27, 2024, at 02:17, Martin Uecker <uec...@tugraz.at> wrote:
> 
> Am Montag, dem 26.08.2024 um 17:21 -0700 schrieb Kees Cook:
>> On Mon, Aug 26, 2024 at 11:01:08PM +0200, Martin Uecker wrote:
>>> Am Montag, dem 26.08.2024 um 13:30 -0700 schrieb Kees Cook:
>>>> On Mon, Aug 26, 2024 at 07:30:15PM +0000, Qing Zhao wrote:
>>>>> Hi, Martin,
>>>>> 
>>>>> Looks like that there is some issue when I tried to use the _Generic for 
>>>>> the testing cases, and then I narrowed down to a
>>>>> small testing case that shows the problem without any change to GCC.
>>>>> 
>>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat t1.c
>>>>> struct annotated {
>>>>>  char b;
>>>>>  int c[];
>>>>> } *array_annotated;  
>>>>> extern void * counted_by_ref (int *);
>>>>> 
>>>>> int main(int argc, char *argv[])
>>>>> {
>>>>>  typeof(counted_by_ref (array_annotated->c)) ret
>>>>>    = counted_by_ref (array_annotated->c); 
>>>>>   _Generic (ret, void* : (void)0, default: *ret = 10);
>>>>> 
>>>>>  return 0;
>>>>> }
>>>>> [opc@qinzhao-ol8u3-x86 gcc]$ /home/opc/Install/latest/bin/gcc t1.c
>>>>> t1.c: In function ‘main’:
>>>>> t1.c:12:44: warning: dereferencing ‘void *’ pointer
>>>>>   12 |   _Generic (ret, void* : (void)0, default: *ret = 10);
>>>>>      |                                            ^~~~
>>>>> t1.c:12:49: error: invalid use of void expression
>>>>>   12 |   _Generic (ret, void* : (void)0, default: *ret = 10);
>>>>>      |                                                 ^
>>>> 
>>>> I implemented it like this[1] in the Linux kernel. So yours could be:
>>>> 
>>>> struct annotated {
>>>>  char b;
>>>>  int c[] __attribute__((counted_by(b));
>>>> };
>>>> extern struct annotated *array_annotated;
>>>> 
>>>> int main(int argc, char *argv[])
>>>> {
>>>>  typeof(_Generic(__builtin_get_counted_by(array_annotated->c),
>>>>    void *: (size_t *)NULL,
>>>>    default: __builtin_get_counted_by(array_annotated->c)))
>>>> ret = __builtin_get_counted_by(array_annotated->c);
>>>>  if (ret)
>>>> *ret = 10;
>>>> 
>>>>  return 0;
>>>> }
>>>> 
>>>> It's a bit cumbersome, but it does what's needed.
>>>> 
>>>> This is, however, just doing exactly what Bill has suggested: it is
>>>> converting the (void *)NULL into (size_t *)NULL when there is no
>>>> counted_by annotation...
>>>> 
>>>> -Kees
>>>> 
>>>> [1] 
>>>> https://lore.kernel.org/linux-hardening/20240822231324.make.666-k...@kernel.org/
>>> 
>>> Interesting. Will __builtin_get_counted_by(array_annotated->c) give
>>> a null pointer (or an invalid pointer) of the correct type if 
>>> array_annotated is a null pointer of an annotated struct type?
>> 
>> If you mean this part:
>> 
>> typeof(P) __obj_ptr = NULL; \
>> /* Just query the counter type for type_max checking. */ \
>> typeof(_Generic(__flex_counter(__obj_ptr->FAM), \
>> void *: (size_t *)NULL, \
>> default: __flex_counter(__obj_ptr->FAM))) \
>> __counter_type_ptr = NULL; \
>> 
>> Where __obj_ptr starts as NULL, then yes. (Or at least, yes it does
>> currently with Qing's GCC patch and Bill's Clang patch.)
> 
> Does __builtin_get_counted_by not evaluate its argument?

__builtin_get_counted_by currently is implemented as a C reserved words, and 
purely implemented in C parser as an C operator. 

So, it doesn’t apply complicated evaluations on its argument. 
I think that this should provide enough and simple functionality as needed. 
If no, please let me know. 


> In any
> case, I think this should be documented whether this is 
> supposed to work (or not).
Okay. 
> 
>> 
>>> I also wonder a bit about the multiple macro evaluations of the arguments
>>> for P and SIZE.
>> 
>> I tried to design it so they aren't used with anything that should
>> have side-effects.
> 
> I was more concerned about the cost of macro expansions on
> compile times. I would do:
> 
> __auto_type __FOO = (FOO);
> 
> for all macro parameters that are evaluated multiple times
> and are expressions which might contain macros themselves.
> 
> There is also the issue of evaluation of typeof for variably modified 
> types, which might not currently affect the kernel, but this would
> also become safer for such types.
> 
> 
>> Anyway, if __builtin_get_counted_by returns (size_t *)NULL then I think
>> the _Generic wrapping isn't needed. That would make it easier to use?
> 
> It would make it easier for your use case.  I wonder though
> whether other people might want to have the compile time error
> when there is no attribute.

Then this will go back to the previous discussion: whether we should go the 
approach  for the unary operator __counted_by(PTR), then the other builtin 
__builtin_has_attribute(PTR, counted_by) should be provided to the user. 

For GCC, there is no issue, we already have the __builtin_has_attribute (PTR, 
counted_by) available. 
But CLANG doesn’t have this builtin currently, need to implement it before the 
unary operator __counted_by(PTR).

Let me know your opinion.

Thanks

Qing
> 
> 
> Martin
> 
>> 
>> -Kees


Reply via email to