问题
I have this struct:
typedef struct xyz_data {
void *myfa; <------- correct
void *myfb; <------- incorrect
}
and this function definition:
asmlinkage ssize_t (*real_sys_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage ssize_t hooked_sys_read(unsigned int fd, char __user *buf, size_t count);
(as you might be guessing, this will point to the kernel's __NR_read
).
Saving hooked_sys_read
to *myfa;
is as simple as xyz_data_something->myfa = hooked_sys_read
, but what about myfb
? I'm not sure xyz_data_something->myfb = &real_sys_read
will work.
I'm hijacking some syscalls (If you're interested in the project, everything is available in GitHub) and each hijacked syscall will use that struct to call the real syscall it belongs to (which will be accessed via *myfb
), making use of the returned value.
Keep in mind that each syscall has it's own return type.
回答1:
Scenario
typedef struct xyz_data {
void *myfa;
void *myfb;
} xyz_data; // Type name assumed — not specified in question
asmlinkage ssize_t (*real_sys_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage ssize_t hooked_sys_read(unsigned int fd, char __user *buf, size_t count);
xyz_data *xyz_data_something = ...;
xyz_data_something->myfa = hooked_sys_read;
xyz_data_something->myfb = &real_sys_read;
Analysis
What you wrote is not type-safe (so the compiler can't help you much), but you are taking the address of the variable that holds the pointer to the 'real sys read' function, not a copy of that pointer (because of the &
). You can apply &
(and *
) to function names willy-nilly and they all end up the same:
reader->myfa = &hooked_sys_read;
reader->myfa = hooked_sys_read;
reader->myfa = *hooked_sys_read;
reader->myfa = **hooked_sys_read;
reader->myfa = ***hooked_sys_read;
reader->myfa = ****hooked_sys_read;
You can't do that with pointers to functions. Note that the compiler cannot even diagnose a 'function pointer assigned to object pointer' problem when you do:
xyz_data_something->myfb = &real_sys_read;
You are assigning the address of a (function) pointer variable to a void *
, so you are assigning an object pointer to a void pointer, which is legitimate — but incorrect.
Synthesis
You should have one of these two function-type typedefs:
typedef ssize_t ReadFunction(unsigned int fd, char __user *data, size_t size);
typedef ssize_t (*ReadPointer)(unsigned int fd, char __user *data, size_t size);
Then your structure can be either:
typedef struct xyz_data
{
ReadFunction *myfa;
ReadFunction *myfb;
} xyz_data;
Or:
typedef struct xyz_data
{
ReadPointer myfa;
ReadPointer myfb;
} xyz_data;
Given a structure pointer:
xyz_data *reader = ...;
The following assignments will compile cleanly and work correctly (for both structure types):
reader->myfa = hooked_sys_read;
reader->myfb = real_sys_read;
Proof of Concept
#include <sys/types.h>
#define asmlinkage
#define __user
asmlinkage ssize_t (*real_sys_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage ssize_t hooked_sys_read(unsigned int fd, char __user *buf, size_t count);
typedef ssize_t (*ReadPointer)(unsigned int fd, char __user *data, size_t size);
typedef struct xyz_data
{
ReadPointer myfa;
ReadPointer myfb;
} xyz_data;
extern xyz_data getter(void);
xyz_data getter(void)
{
xyz_data data;
xyz_data *reader = &data;
reader->myfa = hooked_sys_read;
reader->myfb = real_sys_read;
// The next line fails to compile: assignment from incompatible pointer type
// reader->myfb = &real_sys_read;
reader->myfa = &hooked_sys_read;
reader->myfa = hooked_sys_read;
reader->myfa = *hooked_sys_read;
reader->myfa = **hooked_sys_read;
reader->myfa = ***hooked_sys_read;
reader->myfa = ****hooked_sys_read;
return *reader;
}
It compiles cleanly. It isn't good code, though — the repeated assignments alone are enough to make it bad.
回答2:
You should not be assigning a function pointer to a void pointer.
See https://stackoverflow.com/a/5579907/1351983.
来源:https://stackoverflow.com/questions/18815440/initializing-a-member-of-a-struct-to-a-function-pointer-without-knowing-the-retu