Re: [PATCH v2 07/14] x86: Use an opaque type for functions not callable from C

From: Andy Lutomirski
Date: Thu Aug 26 2021 - 12:54:20 EST

On 8/23/21 10:13 AM, Sami Tolvanen wrote:
> The kernel has several assembly functions that are not directly callable
> from C. Use an opaque type for these function prototypes to make misuse
> harder, and to avoid the need to annotate references to these functions
> for Clang's Control-Flow Integrity (CFI).

You have:

typedef const u8 *asm_func_t;

This is IMO a bit confusing. asm_func_t like this is an *address* of a
function, not a function.

To be fair, C is obnoxious, but I think this will lead to more confusion
than is idea. For example:

> -extern void __fentry__(void);

Okay, __fentry__ is the name of a symbol, and the expression __fentry__
is a pointer (or an array that decays to a pointer, thanks C), which is
at least somewhat sensible. But:

> -extern void (*paravirt_iret)(void);
> +extern asm_func_t paravirt_iret;

Now paravirt_iret is a global variable that points to an asm func. I
bet people will read this wrong and, worse, type it wrong.

I think that there a couple ways to change this that would be a bit nicer.

1. typedef const u8 asm_func_t[];

This is almost nice, but asm_func_t will still be accepted as a function
argument, and the automatic decay rules will probably be confusing.

2. Rename asm_func_t to asm_func_ptr. Then it's at least a bit more clear.

3. Use an incomplete struct:

struct asm_func;

typedef struct asm_func asm_func;

extern asm_func some_func;

void *get_ptr(void)
return &some_func;

No macros required, and I think it's quite hard to misuse this by
accident. asm_func can't be passed as an argument or used as a variable
because it has incomplete type, and there are no arrays so the decay
rules aren't in effect.