__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),                       
};

 方法三:

#undef VERIFY_OCTAL_PERMISSIONS
#define VERIFY_OCTAL_PERMISSIONS(perms) (perms)

static DEVICE_ATTR(reg_value, 0666, zbh_reg_show, zbh_reg_store);

 

分析如上,如有描述不准确的地方还请告知,Thanks

 

posted @ 2018-08-24 15:49  Sky&Zhang  阅读(1076)  评论(0编辑  收藏  举报