5ec1cff


Гео и язык канала: не указан, не указан
Категория: не указана


internalFlow.filter { it.useful }.asSharedFlow()
https://github.com/5ec1cff
BTR 搬运: @btr_channel5
魔法纪录【归档】: @android_magic

Связанные каналы  |  Похожие каналы

Гео и язык канала
не указан, не указан
Категория
не указана
Статистика
Фильтр публикаций


ZygiskOnKernelSU 一直以来都存在着一个奇怪的 bug ,至今已经收到无数起汇报(可能最早的一例)。这些汇报的共同特征是:都来自 oplus 或者 coloros 系统;都出现了 zygiskd32 崩溃的现象;崩溃的堆栈基本上都来自 malloc ;都只有 release 构建出现问题。

早期的分析发现,崩溃的线程是处理 daemon socket 启动的线程,其中一个命令是根据不同 root 实现去查询某 uid 是否具有 root 权限,而问题似乎来自这里,因为每次执行完这个命令后,就会发生崩溃。当时一个看似可行的修复方法是将相关代码禁止内联

而近期 root profile 推出后,zygisksu 也做出了相应修改,在这个提交中,never inline 被去掉,于是又出现了上述问题的汇报。

经过讨论 [1] ,怀疑是内核的 bool size 和 rust 中的 bool size 不一致的问题,rust 的 bool size 是 1,如果内核的 bool size 是 4,可能导致内存被破坏。而利用 prctl 查询 root 权限,需要传入一个 bool 指针,由内核改写返回值,问题可能就在这里。因此随后的一个 CI 进行了修改,并且有人汇报此 CI 的 release 版本正常 'https://t.me/KernelSU_group/3252/101247' rel='nofollow'>[2] 。

于是主线也做了类似的修正,不过没有用到上述 CI 的提交。但这个修正的 CI 的 release 仍有人汇报仍然出现崩溃。

实际上上述猜测是有问题的,因为随后的实验又发现,内核的 bool size 为 1 ,看起来和 rust 是一致的。后来又有人提出 copy_to_user 在长度小于 16 的时候可能出现覆盖现象。总之,问题看上去就是某种意外的内存覆写导致的。

然而想要解释问题的具体原因难度很大,因为 release 构建缺少调试信息,而且崩溃的堆栈回溯大部分帧都来自 libc ,难以从 zygiskd 自身的代码发现问题。不论如何,我还是发了一个带有 debug info 的 release 版本,等待有问题的用户参与调查。

就在最近有 ColorOS 用户积极参与了问题调查,真相似乎终于揭开。

为了验证 bool size 的问题,我给那个用户发了一个程序,检测 prctl 是否会覆写,结论是没有错误覆写 [3]

虽然 bool 没有问题,但是种种迹象表明,应该就是这个 prctl 调用出现的问题,而且一定产生了意外的内存覆写。于是我看了看 kernelsu 的源码,发现了蹊跷之处。

在执行 CMD_UID_GRANTED_ROOT 的时候,kernelsu 会将 prctl 的 arg5 当作一个用户指针,尝试写入一个 reply_ok 返回值。这个返回值区别于 arg4 ,arg4 是命令的 bool 返回值(即 uid 是否具有 root)。

而 zygisksu 中忽略了 arg5 ,且调用 prctl 仅仅传了 4 个参数,因此可以在 dmesg 看到大量的 reply err ,因为 arg5 的地址非法。

不过调用的时候不写 arg5 ,不代表它就没有值了,32 位 arm 的调用约定是 r0~r3 作为前四个参数,之后的参数由调用者放到栈上。现在调用者没有把 arg5 放到栈上,因此取到的值就不是我们能控制的了,这种随机性也和问题报告中,崩溃点各不相同的现象相对应。

将 prctl 的参数列表补全后,release 版本终于能够正常使用

虽然没有让参与调查者在自己的设备上跟踪有问题版本 zygiskd 的系统调用,不过我在自己的设备上测试,发现 32 位的 prctl 调用的第五个参数确实是一个合法地址,甚至是 libc malloc 内存区域的地址。当 zygiskd32 调用了 uid_granted_root 后,KernelSU 也没有打出 reply err 的日志,说明这个地址确实被覆写了,至于为什么没有崩溃,以我目前的能力尚不能解释,只能当作玄学了。可想而知,有多少看似能正常运行着 zygisksu 的系统,他们的 zygiskd32 的内存其实已经被破坏了。

可以说,zygisksu 到这个问题发现为止一直运行在 bug 上。

zygisksu 的教训告诉我们:调用 prctl 这样的函数时一定要将不用的参数填上 0 ,否则可能出现意想不到的未定义行为。

另外,从 arm64 的系统调用跟踪发现,arg5 是 0 ,也许是因为 64 位上这个参数来自寄存器。


Репост из: 【NSFW️】陰キャネット
Видео недоступно для предпросмотра
Смотреть в Telegram
google 搜索框的傻逼设计:如果某个关键词联想出了右边的卡片,鼠标刚好悬停在那的时候会自动把那个关键词填上去
有时候还会出现这种情况:没法删除文字,因为删除文字后,如果剩余文字还能得到卡片,那么马上又会触发 mouseover 事件把卡片的关键词填上去

一个简单的 UserScript 解决这个问题帮 Google 擦屁股:

// ==UserScript==
// @name Fuckgoogle
// @namespace Violentmonkey Scripts
// @match https://www.google.com/search
// @grant unsafeWindow
// @version 1.0
// @author 5ec1cff
// @description 2023/6/16 12:44:17
// ==/UserScript==

((window) => {
let form = null;
window.document.documentElement.addEventListener("mouseover", function (e) {
const te = e.toElement;
if (form == null) form = window.document.querySelector("form[role=search]");
if (form != null && form.contains(te)) e.stopPropagation();
}, true)
})(unsafeWindow)


现在是使用 bpf 程序 cgroupsock/inet/create 控制创建 socket 的权限

packages/modules/Connectivity/bpf_progs/netd.c
首次提交 于 2019 年

这个程序不再通过 groups 判断是否具有 网络权限 ,而是从 bpf 程序定义的 map (uid_permission_map) 中查找目标进程 uid (非 gid 或 groups)的权限记录,如果 map 有相应 uid 的记录,且记录中没有 网络权限,才会拒绝创建 socket 。
因此现在 gids 有 inet 也不一定能创建 socket ,而不存在于 pm 的 uid 反而具有 网络权限 。

你可以在 /sys/fs/bpf/netd_shared/map_netd_uid_permission_map 看到这个 map

map 由 系统服务 或 netd 负责更新,相关代码:
packages/modules/Connectivity/service/src/com/android/server/BpfNetMaps.java setNetPermForUids
packages/modules/Connectivity/service/native/TrafficController.cpp TrafficController::setPermissionForUids


https://github.com/firmianay/Life-long-Learner/blob/master/Android-Security-Internals/README.md#%E5%86%85%E6%A0%B8%E5%B1%82%E7%9A%84%E6%9D%83%E9%99%90%E6%89%A7%E8%A1%8C
以前一直好奇 android 是怎么根据有 gid 限制创建 socket 的权限的,现在才知道居然是魔改内核
内核选项:CONFIG_ANDROID_PARANOID_NETWORK
在我的 API 30 设备上内核还开启了这个选项,不过在 AVD 的 API 30 (5.4), API 31 (5.10) 以及之后的版本都没有这个选项了,可能是使用了别的实现


尝试给 zygisksu 的 release 版加上 debuginfo ,以便调试

https://doc.rust-lang.org/cargo/reference/profiles.html

在 cargo.toml 中配置 release 的 profile :

[profile.release]
# strip = true
opt-level = "z"
lto = true
debug = true

build: cargo ndk --platform 29 --bindgen -t x86_64 build --profile release

rustc 支持生成 split-debuginfo ,不过剥离出来的不知道怎么用,gdb 不识别


http://aospxref.com/

可以搜历史版本的代码,在这一点上就薄纱了 cs.android.com ,还有个好处就是没 cs 那么卡(不管是网络还是页面)


之所以这么绕有几个原因:
1. extension 似乎没有标准的 API 可以实现「打开一个页面,自动上传文件,提交表单」的操作,所以只能在某个网页中用 js 操作 DOM 模拟这个动作
2. 也没有任何标准 API 能实现直接获取 img 的(原始)二进制内容,或者得到 file 对象,用 canvas 可以得到图像数据,但是会有跨域问题,所以选择打开图像 url 对应的页面,注入 content script ,避免了跨域
3. 其实提交 url 给 saucenao 完全没问题,大部分情况下 url 都是可用的(比 google images 好),因此这个 extension 的意义主要就在于能实现来自 file url 的图片的自动上传


如此一来就可以利用 chrome 扩展实现提交任意图片给 saucenao 搜索了(包括来自 file url 的图片,因为图片数据直接上传而不是发送 url )

思路大致如下:

1. 注册 contextMenu ,接收图片 url
2. contextMenu 回调打开一个 tab ,url 是选择的图片
3. 在 tab 中执行 content script ,利用 canvas 得到图片数据,利用 DataTransfer 将数据转换为文件,并通过 js 创建表单提交给 saucenao

下面是使用 MV3 的实现:https://gist.github.com/5ec1cff/5f08e79e86edff5b0061f685d8042233




JS 中向表单填写文件的方法

https://stackoverflow.com/a/56447852

let list = new DataTransfer();
let file = new File(["content"], "filename.jpg");
list.items.add(file);

input.files = list.files;


这样的问题是没法访问 /Android/data ,有时候经常需要访问 QQ 下载的文件,普通用户的权限很难做到透过文件系统访问。

在 root 的情况下,虽然可以使用 root 启动 webdav ,不过为了确保最小权限,想了一个比较绕的方法:先 su ,通过 capsh 设置 groups 为 sdcard_rw(1015) 再降权回去。

su -c "PATH=$PATH $(which capsh) --groups=1015,9997,3003 --uid=$(id -u) -- -c 'exec rclone serve webdav /storage/emulated/0 --addr :8080'"

这里给了三个 groups:everybody(9997) 用于获得 /storage/emulated/0 的访问权,1015(sdcard_rw) 获得 /Android/data 的访问权, 3003(inet) 获得网络的访问权




Репост из: 【NSFW️】陰キャネット
rclone serve webdav /storage/emulated/0 --addr :8080

在 termux 里用 rclone webdav 服务实现共享文件,体验薄纱 SMB ,关键是不需要 root

https://rclone.org/commands/rclone_serve_webdav/

Windows 资源管理器使用 \\${ip}@8080\DavWWWRoot 访问



Показано 14 последних публикаций.

18

подписчиков
Статистика канала