关于VERIFY_OCTAL_PERMISSIONS权限检查

来源:互联网 发布:硕士毕业论文 知乎 编辑:程序博客网 时间:2024/06/07 11:07

修改内核创建/sys文件系统下的文件的权限时

将代码从 __ATTR(type, 0644, xx_show, NULL);
改为 __ATTR(type, 0666, xx_show, NULL);
编译时会报错:

include/linux/bug.h:33:45: error: negative width in bit-field '<anonymous>'#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))^include/linux/kernel.h:853:3: note: in expansion of macro 'BUILD_BUG_ON_ZERO'BUILD_BUG_ON_ZERO((perms) & 2) + \^include/linux/sysfs.h:75:12: note: in expansion of macro 'VERIFY_OCTAL_PERMISSIONS'.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \^arch/powerpc/platforms/powernv/opal-elog.c:85:2: note: in expansion of macro '__ATTR'__ATTR(id, 0666, elog_id_show, NULL);^include/linux/bug.h:33:45: error: negative width in bit-field '<anonymous>'#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))^include/linux/kernel.h:853:3: note: in expansion of macro 'BUILD_BUG_ON_ZERO'BUILD_BUG_ON_ZERO((perms) & 2) + \^include/linux/sysfs.h:75:12: note: in expansion of macro 'VERIFY_OCTAL_PERMISSIONS'.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \^arch/powerpc/platforms/powernv/opal-elog.c:87:2: note: in expansion of macro '__ATTR'__ATTR(type, 0666, xx_show, NULL);

问题出自宏VERIFY_OCTAL_PERMISSIONS对权限的检查:

/* Permissions on a sysfs file: you didn't miss the 0 prefix did you? */#define VERIFY_OCTAL_PERMISSIONS(perms)                                 \        (BUILD_BUG_ON_ZERO((perms) < 0) +                               \         BUILD_BUG_ON_ZERO((perms) > 0777) +                            \         /* User perms >= group perms >= other perms */                 \         BUILD_BUG_ON_ZERO(((perms) >> 6) < (((perms) >> 3) & 7)) +     \         BUILD_BUG_ON_ZERO((((perms) >> 3) & 7) < ((perms) & 7)) +      \         /* Other writable?  Generally considered a bad idea. */        \         BUILD_BUG_ON_ZERO((perms) & 2) +                               \         (perms))

这里从注释上也看的比较清晰权限的要求:
1.User perms >= group perms >= other perms
2. Other writable? Generally considered a bad idea.

1.所有者权限>=组用户权限>=其他人权限
也就是说 类似0466的这种权限是不允许的
2.这个检查不允许其他用户写的权限

这个宏看起来比较难看懂,我们仔细来分析一下:

入参是一个8进制数,注释也提示了我们是需要0开头的。

8进制数右移6位【perms) >> 6】就是取所有者权限
8进制数右移3位取低三位【perms) >> 3 & 7】就是取组权限

BUILD_BUG_ON_ZERO (x)
当x==0时编译会报错
当x!=0 时能够正常运行,结果为0

然后简化一下宏:

#define VERIFY_OCTAL_PERMISSIONS(perms) (BUILD_BUG_ON_ZERO(perms在边界值内?)+    \BUILD_BUG_ON_ZERO(所有者权限<组权限)+   \BUILD_BUG_ON_ZERO(组权限<其他用户权限)+ \BUILD_BUG_ON_ZERO(其他用户权限可写)+    \(perms))

这个宏的结果要么报错要么还是原来的值。

这里我们需要其他用户也要有写的权限就把BUILD_BUG_ON_ZERO((perms) & 2) 去掉就好了。

最后我们看看BUILD_BUG_ON_ZERO时怎么实现检查的,好奇。

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
  1. (e): 表达式e的声明
  2. !!(e): 对e的结果进行两次求非。即如果e开始是0的话,结果就是0;如果e不为0,则结果为1。
  3. –!!(e): 再乘-1。如果第2步结果为0,则仍为0;否则结果为-1。
  4. struct { int : –!!(0); } –> struct { int : 0; } : 如果e的结果为0,则我们声明一个结构体拥有一个int型的数据域,并且规定它所占的位的个数为0。这没有任何问题,我们认为一切正常。
  5. struct { int : –!!(1); } –> struct { int : –1; } : 如果e的结果非0,结构体的int型数据域的位域将变为一个负数,将位域声明为负数这是一个语法的错误。
  6. 现在要么结果为声明了一个位域为0的结构体,要么出现位域为负数编译出错;如果能正确编译,然后我们对该结构体进行sizeof操作,得到一个类型为size_t的结果,值为0。

再总结一下,BUILD_BUG_ON_ZERO(e) 表示的就是若表达式e结果为0,则编译通过,该宏的值也为0;若表达式e的结果不为0,则编译不通过。

后记,发现即便更改了权限检查,运行时也会报错

WARNING: CPU: 0 PID: 219 at fs/sysfs/group.c:61 internal_create_group+0x1e4/0x268()Attribute direction: Invalid permissions 0666Modules linked in:CPU: 0 PID: 219 Comm: sh Not tainted 4.1.15 #13Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)[<c0110254>] (unwind_backtrace) from [<c010b660>] (show_stack+0x10/0x14)[<c010b660>] (show_stack) from [<c0bf3338>] (dump_stack+0x7c/0xbc)[<c0bf3338>] (dump_stack) from [<c0135520>] (warn_slowpath_fmt+0x90/0xc8)[<c0135520>] (warn_slowpath_fmt) from [<c02aac28>] (internal_create_group+0x1e4/0x268)[<c02aac28>] (internal_create_group) from [<c02aaff0>] (sysfs_create_groups+0x4c/0x110)[<c02aaff0>] (sysfs_create_groups) from [<c05f0e70>] (device_add+0x348/0x570)[<c05f0e70>] (device_add) from [<c05f131c>] (device_create_groups_vargs+0x128/0x138)[<c05f131c>] (device_create_groups_vargs) from [<c05f13a4>] (device_create_with_groups+0x24/0x2c)[<c05f13a4>] (device_create_with_groups) from [<c051b444>] (gpiod_export+0x13c/0x1c0)[<c051b444>] (gpiod_export) from [<c051b51c>] (export_store+0x54/0xc0)[<c051b51c>] (export_store) from [<c02a9424>] (kernfs_fop_write+0xb8/0x19c)[<c02a9424>] (kernfs_fop_write) from [<c023df80>] (vfs_write+0xa0/0x1c4)[<c023df80>] (vfs_write) from [<c023e7f8>] (SyS_write+0x44/0x9c)[<c023e7f8>] (SyS_write) from [<c01076c0>] (ret_fast_syscall+0x0/0x3c)---[ end trace 66868f3da9543a66 ]---

还需要更改fs/sysfs/group.c ,把664 改成666

WARN(mode & ~(SYSFS_PREALLOC | 0664),                            "Attribute %s: Invalid permissions 0%o\n",                             (*attr)->name, mode); mode &= SYSFS_PREALLOC | 0664;
原创粉丝点击