什么可能导致socket()函数出现“Permission denied”错误?

15
在Android 4下,以下简单的本地C代码行在非root权限下运行时会因为权限被拒绝而失败。
online_socket = socket(AF_INET, SOCK_DGRAM, 0);

我确实拥有设备的 root 访问权限,但希望将进程以非特权用户身份运行。

请注意,在绑定套接字之前就发生了错误。

我猜测可能需要调整某些安全设置?有人能告诉我该去哪里查看吗?

在这种情况下,操作系统确实是 Android,但我猜问题实际上与 Linux 有关(因为 Android 基于 Linux 内核)。

对于那些好奇的人:这是在 Android 4 环境中运行的完整(debootstrap 安装的)Debian Jessie 中运行的自定义程序。

更新

我了解到 Android 内核有一个特殊的 CONFIG_ANDROID_PARANOID_NETWORK 扩展,只允许在 AID_INETAID_NET_RAW 组中的用户进行网络访问。

但是,即使将用户添加到这些组中,socket() 仍然被拒绝(顺便说一句,ping 似乎也存在相同的问题)。

uid=5(imp) gid=51(imp) groups=51(imp),3003(aid_inet),3004(aid_net_raw),3005(aid_admin),3001(aid_bt),3002(aid_bt_net)

由于我无法访问配置文件,因此无法确定该特定内核是否设置了 CONFIG_ANDROID_PARANOID_NETWORK 标志。

更新2

我发现即使是我的非特权用户imp,也可以成功调用socket(),但需要按照上述组设置来进行。

然而,使用seteuid()系统调用将进程从root切换到imp后,调用socket()会失败。有什么想法吗?


我在一台x68_64的笔记本电脑上使用Arch Linux没有出现错误。我怀疑这是一个Android的问题。 - user208139
你尝试过使用与“0”(第三个参数)不同的协议吗?例如:6表示TCP,17表示UDP。实际上,对于UDP数据报套接字,您必须使用协议17。 - gerhard d.
@gerhardd。- 刚试了将协议更改为17,但不幸的是这并没有帮助解决问题。需要指出的是,所涉及的程序在许多其他非Android平台上运行良好,包括内核从2.4到4.4不等。 - Udo G
2个回答

20

事实证明,Android使用了一个特殊的内核补丁,它通过CONFIG_ANDROID_PARANOID_NETWORK激活。该补丁允许属于某些特殊组的系统用户具有网络访问权限,并具有硬编码的ID。

groupadd -g 3001 aid_bt
groupadd -g 3002 aid_bt_net
groupadd -g 3003 aid_inet
groupadd -g 3004 aid_net_raw
groupadd -g 3005 aid_admin

这是因为 Android 通常仅在特定应用程序拥有网络权限时才将用户(即应用程序)添加到这些组中。

将用户添加到这些组中会授予其使用 socket() 的权限,如问题所述:

usermod -a -G aid_bt,aid_bt_net,aid_inet,aid_net_raw,aid_admin someuser

然而,当一个进程使用seteuid()root切换到非特权用户(例如someuser)时,这个有效的用户是否具有aid_*组成员身份已经不足够(或者可能无关紧要)。相反,root用户必须明确地成为这些组的成员:

usermod -a -G aid_bt,aid_bt_net,aid_inet,aid_net_raw,aid_admin root

这对我解决了问题。

请注意,我也尝试过使用setegid()等方法作为替代方案,但都没有帮助……


请注意,这些组名随时间变化(例如在Android 7中,看起来“inet”是您需要的组),但以root身份运行组会列出它所属的组,这些组大多是不言自明的。 - Ryan Pavlik
2
usermod命令在Android上不可用。我该如何在Android手机上执行此操作? - in3xes
@in3xes 我不确定 OP 的情况,但我正在 Android 10 中运行 Ubuntu 20.04 chroot。所以对我来说,这些命令将在 Ubuntu 环境中运行。 - aggregate1166877

3

对于在 Android 上使用 apt-get 时遇到问题的人(启用了CONFIG_ANDROID_PARANOID_NETWORK,该功能会限制网络访问权限仅供特定组的用户使用),有两种解决方法:

  1. groupadd -g 3003 aid_inet && usermod -G nogroup -g aid_inet _apt
  2. echo 'APT::Sandbox::User "root";' > /etc/apt/apt.conf.d/01-android-nosandbox

这是因为 apt-get 在受沙盒保护的用户下运行 http/https/gpgv 方法,默认情况下为 _apt 用户。

root      1465  0.0  0.0  31408  4956 pts/0    S    11:48   0:00  |   |       \_ -bash
root     23814  0.1  0.1  65300 10124 pts/0    T    18:58   0:00  |   |           \_ apt-get update
_apt     23818  0.0  0.1  90208  8852 pts/0    T    18:58   0:00  |   |           |   \_ /usr/lib/apt/methods/http
_apt     23819  0.0  0.1  90208  8828 pts/0    T    18:58   0:00  |   |           |   \_ /usr/lib/apt/methods/https
...

天啊,自定义chroot太复杂了。谢谢朋友,我在使用Android 10 -> chrooted Ubuntu 20.04,它对我很有帮助。 - aggregate1166877
非常感谢!天啊,Ubuntu 太复杂了,Arch Linux 只需要编辑 resolv.conf 文件,一切都可以直接使用。 - 0xB00B
  1. 组已存在
  2. 文件不存在
- undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接