----- On Nov 17, 2020, at 5:19 PM, rostedt [email protected] wrote:

> On Tue, 17 Nov 2020 13:33:42 -0800
> Kees Cook <[email protected]> wrote:
> 
>> As I think got discussed in the thread, what you had here wouldn't work
>> in a CFI build if the function prototype of the call site and the
>> function don't match. (Though I can't tell if .func() is ever called?)
>> 
>> i.e. .func's prototype must match tp_stub_func()'s.
>> 
> 
> 
> Hmm, I wonder how you handle tracepoints? This is called here:
> 
> include/linux/tracepoint.h:
> 
> 
> #define DEFINE_TRACE_FN(_name, _reg, _unreg, proto, args)             \
>       static const char __tpstrtab_##_name[]                          \
>       __section("__tracepoints_strings") = #_name;                    \
>       extern struct static_call_key STATIC_CALL_KEY(tp_func_##_name); \
>       int __traceiter_##_name(void *__data, proto);                   \
>       struct tracepoint __tracepoint_##_name  __used                  \
>       __section("__tracepoints") = {                                  \
>               .name = __tpstrtab_##_name,                             \
>               .key = STATIC_KEY_INIT_FALSE,                           \
>               .static_call_key = &STATIC_CALL_KEY(tp_func_##_name),   \
>               .static_call_tramp = STATIC_CALL_TRAMP_ADDR(tp_func_##_name), \
>               .iterator = &__traceiter_##_name,                       \
>               .regfunc = _reg,                                        \
>               .unregfunc = _unreg,                                    \
>               .funcs = NULL };                                        \
>       __TRACEPOINT_ENTRY(_name);                                      \
>       int __traceiter_##_name(void *__data, proto)                    \
>       {                                                               \
>               struct tracepoint_func *it_func_ptr;                    \
>               void *it_func;                                          \
>                                                                       \
>               it_func_ptr =                                           \
>                       rcu_dereference_raw((&__tracepoint_##_name)->funcs); \
>               do {                                                    \
>                       it_func = (it_func_ptr)->func;                  \
>                       __data = (it_func_ptr)->data;                   \
> 
>                       ((void(*)(void *, proto))(it_func))(__data, args); \
> 
>                       ^^^^ called above ^^^^
> 
> Where args is unique for every tracepoint, but func is simply a void
> pointer.

That being said, the called functions have a prototype which match the
caller prototype exactly. So within the tracepoint internal data structures,
this function pointer is indeed a void pointer, but it is cast to a prototype
matching the callees to perform the calls. I suspect that as long as CFI checks
that caller/callees prototypes are compatible at runtime when the actual
calls happen, this all works fine.

Thanks,

Mathieu

> 
> -- Steve
> 
> 
>               } while ((++it_func_ptr)->func);                        \
>               return 0;                                               \
>       }                                                               \

-- 
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com

Reply via email to