__ATTR引发的编译错误【原创】
有一天我编译内核模块驱动的时候发现如下错误
Linux kernel版本:4.1.15
error: negative width in bit-field '<anonymous>'
代码如下:
static struct device_attribute sysfs_keypad_list[] = { __ATTR(virt_key, 0666, keypad_show_error, keypad_virt_key_store), };
当我做这样的修改后:
static struct device_attribute sysfs_keypad_list[] = { __ATTR(virt_key, 0665, keypad_show_error, keypad_virt_key_store), };
编译就不报错了
这样让我很是奇怪,接下来咱们跟入代码一看究竟
首先我们看下__ATTR的实现:
继续跟入,我们发现如下的算法,显而易见,此版本的内核对权限做了一个小小的算法,如下算法大家可以写一个简单的c代码进行解读
当我传入perms=0x666的时候,BUILD_BUG_ON_ZERO(perms & 2) 这个会报错,因为如下:
为什么 BUILD_BUG_ON_ZERO( (0x666) & 2 )会报错呢?
我们可以写这样的代码来验证一下:
#include <stdio.h> int main() { struct a { int: -1; }; return 0; }
运行:
出现了同样的错误,那么我们应该明白了吧,gcc会在编译的时候对位域的定义进行检查,struct {int: -1}这样的定义编译器会认为是错误的
那至于为什么会打印这样的错误呢?这就需要对编译器进行了解了,也就是编译器是如何检查结构体位域的定义的,这块我没有深入研究过
如有人有这块的资料和信息欢迎评论和分享。
如下引用一段话,摘自网上(https://stackoverflow.com/questions/31395602/giving-s-iwugo-permission-to-module-parameter-results-in-compilation-error-whil)
Linux probably refuses to make module parameters world-writable for security reasons.
You should be able to use narrower permissions such as S_IWUSR | S_IWGRP
通俗的理解就是内核希望这样做的安全一点,减少其他组的写权限,体现在 BUILD_BUG_ON_ZERO(perms & 2)这个设计上
那么我们如何修改呢?
有如下两种方式的思路给大家借鉴:
第一种:
这样设计的思路是为了遵循作者的思想,保障安全(但__ATTR这个宏的用法不同版本是有差别的在这块,比如说3.6.5的版本是不会检查这个权限问题的)
static struct device_attribute sysfs_keypad_list[] = { __ATTR(virt_key, 0664, keypad_show_error, keypad_virt_key_store), };
第二种:
这样设计的思路是因为搞驱动开发的相信大家都清楚,如果这个接口是我们曾经释放出去的,开放了这样的权限
那么我们后期开发的时候必须兼容之前的接口设计,不能这样随意的更改权限,因为如果你修改了,某个客户之前有这样子使用权限的话,你改了权限后,他可能就用不了了,
因此我们可以做如下处理,思路就是我们自己定义,不使用内核的设计
#undef __ATTR #define __ATTR(_name, _mode, _show, _store) { \ .attr = {.name = __stringify(_name), \ .mode = _mode}, \ .show = _show, \ .store = _store, \ } static struct device_attribute sysfs_keypad_list[] = { __ATTR(virt_key, 0666, keypad_show_error, keypad_virt_key_store), };
分析如上,如有描述不准确的地方还请告知,Thanks