为什么在 Linux hwmon 中允许可能存在缓冲区溢出的 sprintf?
Why is sprintf with possible buffer overflow allowed in Linux hwmon?
我已经看到以下代码片段被重复用于 Linux hwmon 设备:
return sprintf(buf, "%d\n", in_input);
其中 buf
是指向 char char *buf
的指针,而 in_input
通常是 int
或 u16
。目的是将从设备读回的值复制到为此设备属性创建的sysfs文件。
作为示例,您可以查看 Linux/drivers/hwmon/mcp3021.c(或 4.9 内核之前的任何 hwmon 设备)。您可以在第 81 行 returns a u16
看到该函数,在第 99 行代码将 u16
存储到 char *buf
.
81 static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
82 {
83 return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);
84 }
85
86 static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
87 char *buf)
88 {
89 struct i2c_client *client = to_i2c_client(dev);
90 struct mcp3021_data *data = i2c_get_clientdata(client);
91 int reg, in_input;
92
93 reg = mcp3021_read16(client);
94 if (reg < 0)
95 return reg;
96
97 in_input = volts_from_reg(data, reg);
98
99 return sprintf(buf, "%d\n", in_input);
100 }
这段代码不会总是导致缓冲区溢出吗?我们总是将 u16 存储到分配给 char 8 位的缓冲区中。为什么 Linux 设备驱动程序允许这样做?
请注意,对于执行完全相同操作的我的驱动程序,sysfs 会正确显示返回值,即使它不可能存储为 char(8 位)。所以想知道 char *
表示是否不准确?
发布的代码显示糟糕的编程风格,但如果已知 buf
指向至少 8 字节的数组,则行为已定义并且 sprintf
不会导致缓冲区溢出。
请注意,show_in_input
不接收目标缓冲区的大小,需要更改 API 才能使用 snprintf()
。
根据 sysfs.txt 中的文档,传递给 show
函数的缓冲区大小为 PAGE_SIZE
:
sysfs allocates a buffer of size (PAGE_SIZE
) and passes it to the method. Sysfs will call the method exactly once for each read or write.
由于PAGE_SIZE肯定比一个小整数的长度大,缓冲区溢出的实际可能性不大。
我已经看到以下代码片段被重复用于 Linux hwmon 设备:
return sprintf(buf, "%d\n", in_input);
其中 buf
是指向 char char *buf
的指针,而 in_input
通常是 int
或 u16
。目的是将从设备读回的值复制到为此设备属性创建的sysfs文件。
作为示例,您可以查看 Linux/drivers/hwmon/mcp3021.c(或 4.9 内核之前的任何 hwmon 设备)。您可以在第 81 行 returns a u16
看到该函数,在第 99 行代码将 u16
存储到 char *buf
.
81 static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
82 {
83 return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);
84 }
85
86 static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
87 char *buf)
88 {
89 struct i2c_client *client = to_i2c_client(dev);
90 struct mcp3021_data *data = i2c_get_clientdata(client);
91 int reg, in_input;
92
93 reg = mcp3021_read16(client);
94 if (reg < 0)
95 return reg;
96
97 in_input = volts_from_reg(data, reg);
98
99 return sprintf(buf, "%d\n", in_input);
100 }
这段代码不会总是导致缓冲区溢出吗?我们总是将 u16 存储到分配给 char 8 位的缓冲区中。为什么 Linux 设备驱动程序允许这样做?
请注意,对于执行完全相同操作的我的驱动程序,sysfs 会正确显示返回值,即使它不可能存储为 char(8 位)。所以想知道 char *
表示是否不准确?
发布的代码显示糟糕的编程风格,但如果已知 buf
指向至少 8 字节的数组,则行为已定义并且 sprintf
不会导致缓冲区溢出。
请注意,show_in_input
不接收目标缓冲区的大小,需要更改 API 才能使用 snprintf()
。
根据 sysfs.txt 中的文档,传递给 show
函数的缓冲区大小为 PAGE_SIZE
:
sysfs allocates a buffer of size (
PAGE_SIZE
) and passes it to the method. Sysfs will call the method exactly once for each read or write.
由于PAGE_SIZE肯定比一个小整数的长度大,缓冲区溢出的实际可能性不大。