我目前正在尝试使用蓝牙低功耗和iBeacon设备。 我编写了一个服务器来不断寻找附近的信标。
我的服务器遵循这个示例(链接)
不幸的是,调用以下函数:
hci_le_set_scan_parameters()
需要root权限。
由于我不想用root权限运行整个服务器,我想问一下是否有可能仅以root权限调用此函数?
我知道在执行程序时要求sudo始终至少是可疑的,但我找不到其他扫描iBeacon的可能性。如果还有其他可能性,我也很乐意听取建议。
感谢您的帮助和祝福。
nPLus
我目前正在尝试使用蓝牙低功耗和iBeacon设备。 我编写了一个服务器来不断寻找附近的信标。
我的服务器遵循这个示例(链接)
不幸的是,调用以下函数:
hci_le_set_scan_parameters()
seteuid(2)
临时获得root权限。capabilities(7)
(临时或永久)。
线程安全注意事项
据我所知,在Linux上,UID/GID是每个线程的属性,并且可以为单个线程设置它们,请参见seteuid()
手册页中的NOTES
部分和this post。
/proc/PID/exe
上的readlink()(其中PID
是正十进制数的进程ID)可以获取另一端当前正在运行的可执行文件。int
作为数据传递,如果成功则为0
,并将描述符作为辅助消息传递,否则为errno
错误代码(不带辅助数据)。
然而,考虑这些辅助程序可能被滥用的可能方式是很重要的。限制到特定目录,或者可能有一个系统范围的配置文件,指定允许的路径 glob 模式(并不可写入每个人),并使用例如 fnmatch() 来检查传递的路径是否已列出,是好的方法。
辅助进程可以通过设置 setuid
或通过 Linux 文件系统 capabilities 获得特权。例如,只给予辅助程序 CAP_DAC_OVERRIDE
能力将使其绕过文件读取、写入和执行检查。在 Debian 派生版中,操作文件系统能力的命令行工具 setcap
在 libcap2-bin 包中。
如果您无法将特权部分移动到单独的进程中,可以使用Linux、BSD和HP-UX系统支持的接口:setresuid(),它可以在一次调用中设置真实、有效和保存的用户ID。(有一个相应的setresgid()调用用于设置真实、有效和保存的组ID,但是当使用该调用时,请记住补充组列表不会被修改;您需要显式调用setgroups()或initgroups()来修改补充组列表。) 此外,还有文件系统用户ID和文件系统组ID,但是C库将在设置有效用户和/或组ID时将其设置为匹配的值。
如果使用超级用户权限启动进程,则有效用户ID将为零。 如果您首先使用getresuid(&ruid,&euid,&suid)
和getresgid(&rgid,&egid,&sgid)
,则可以使用setresgid(rgid,rgid,rgid)
确保仅保留真实组标识,并通过调用setresuid(ruid,ruid,0)
暂时放弃超级用户权限。 要重新获得超级用户权限,请使用setresuid(0,ruid,0)
,要永久放弃超级用户权限,请使用setresuid(ruid,ruid,ruid)
。有一种方法可以将特权限制在进程内的一个专用线程中,但这种方法是繁琐且脆弱的,我不建议使用。
为了将特权限制在单个线程内,您需要创建自定义包装器来包装 SYS_setresuid
/SYS_setresuid32
、SYS_setresgid
/SYS_setresgid32
、SYS_getresuid
/SYS_getresuid32
、SYS_getresgid
/SYS_getresgid32
、SYS_setfsuid
/SYS_setfsuid32
和 SYS_setfsgid
/SYS_setfsgid32
系统调用。(使包装器调用32位版本,如果返回 -ENOSYS,则回退到16位版本。)
在Linux中,用户和组身份实际上是基于线程而不是进程的。所使用的标准C库将使用实时POSIX信号和内部处理程序来通知其他线程切换身份,作为操作这些身份的库函数的一部分。
在您的进程早期,创建一个特权线程,它将保持根(0)作为保存的用户标识,但是将真实标识复制到有效和保存的标识中。对于主进程,将真实标识复制到有效和保存的标识中。当特权线程需要执行某些操作时,它首先将有效用户标识设置为root,执行操作,然后将有效用户标识重置为真实用户标识。这样,特权部分仅限于此一个线程,并且仅在必要时应用于该部分,因此大多数常见的信号等攻击将没有机会生效,除非它们恰好发生在这样的特权部分。在所有不同的方法中,我相信通过 Unix 域套接字对进行身份验证的独立进程是最明智的选择。它最容易使系统健壮,并且至少可以在 POSIX 和 BSD 系统之间移植。