在不知道返回类型的情况下将结构的成员初始化为函数指针

时间:2013-09-15 17:41:00

标签: c kernel system-calls

我有这个结构:

typedef struct xyz_data {
    void *myfa; <------- correct
    void *myfb; <------- incorrect
}

和这个函数定义:

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);

(正如您可能猜测的那样,这将指向内核的__NR_read)。

hooked_sys_read保存到*myfa;就像xyz_data_something->myfa = hooked_sys_read一样简单,但myfb呢?我不确定xyz_data_something->myfb = &real_sys_read是否可行。

我正在劫持一些系统调用(如果你对该项目感兴趣,一切都在GitHub中可用),每个被劫持的系统调用将使用该结构来调用它所属的真实系统调用(将通过{{1访问)使用返回的值。

请记住,每个系统调用都有自己的返回类型。

2 个答案:

答案 0 :(得分:2)

方案

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;

分析

你写的不是类型安全的(所以编译器对你没什么帮助),但是你正在获取保存指向'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;

你不能用指向函数的指针来做到这一点。请注意,当您执行以下操作时,编译器甚至无法诊断“分配给对象指针的函数指针”问题:

xyz_data_something->myfb = &real_sys_read;

您正在将(函数)指针变量的地址分配给void *,因此您要将一个对象指针指定给一个合法的void指针 - 但不正确。

合成

您应该拥有以下两种函数类型的typedef之一:

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);

然后你的结构可以是:

typedef struct xyz_data
{
    ReadFunction *myfa;
    ReadFunction *myfb;
} xyz_data;

或者:

typedef struct xyz_data
{
    ReadPointer myfa;
    ReadPointer myfb;
} xyz_data;

给定结构指针:

xyz_data *reader = ...;

以下分配将干净地编译并正常工作(对于两种结构类型):

reader->myfa = hooked_sys_read;
reader->myfb = real_sys_read;

概念证明

#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;
}

它干净利落地编译。然而,这不是一个好的代码 - 单独的重复分配足以使它变坏。

答案 1 :(得分:1)

您不应该将函数指针指定给void指针。

请参阅https://stackoverflow.com/a/5579907/1351983