feat(sec): 二期签名鉴权 2A 最小闭环 (agent-185) — meow_verify(Ed25519验签CLI,公钥固化,TweetNaCl+SHA256单文件) + meow_sign(宿主keygen/sign,尾部180B footer签名块,私钥仅.keys/不入库) + nyai/meow_pkg_install 验签分级(有签必验/os.meow.*无签拒装/第三方直装告警/三重绑定/原签存.mpk.src导出保留) + svc_power IPC鉴权(SO_PEERCRED→/proc/pid/exe→包名/系统身份allowlist,系统动作仅os.meow.*或系统身份) + cmd_upgrade同步签名分级防绕过
meow_verify 37e50606; nyai f2938d28; svc_power e0494eb7; launcher 24c9ee5d(含热重载) 宿主验证12项全过(正例/篡负载/篡包名/无签系统包拒/第三方直装/降级拒/导出round-trip byte-identical/verify缺失宁缺勿装/footer容忍/E2E PERM/鉴权分类) 出入: TweetNaCl替orlp/ed25519(任务允许同等实现); 读级暂仍uid==0(用户随后定案放宽到任意调用者,待改); 系统身份allowlist为启发式
This commit is contained in:
1 parent
f50abae02a
commit
3f57d7fd4f
22 files changed
+1978
-15
No files matched your search
@@ -10,8 +10,12 @@
|
||||
* 动作逻辑与 launcher `power_menu.c` 的 `sys_do_reboot`/`set_boot_default_hiby`/`bootmode.sh Recovery`
|
||||
* **同源 0-diff 搬移**,仅入口(CLI vs IPC)与鉴权层不同。
|
||||
*
|
||||
* 鉴权(一期基础校验):IPC 服务端受理 MSG_POWER_ACTION 前以 `SO_PEERCRED` 校验调用方 `uid==0`(root)
|
||||
* ——非 root 直接 `MEOW_ERR_PERM` 拒绝;完整 `os.meow.*` 包名鉴权(§5)留二期。CLI=root 免鉴权。
|
||||
* 鉴权(II 期,MPK_SIGNATURE_DESIGN §6):IPC 服务端按【连接级身份】分级——`SO_PEERCRED` 取 pid →
|
||||
* `readlink /proc/pid/exe` → 命中 `MeowAPPs/<pkg>/` 判定包名,或命中系统二进制 allowlist
|
||||
* (/usr/bin/meow_*、/usr/data/meow/meow*、MeowPanel 后端)判定为系统身份;其余为 OTHER。
|
||||
* 动作级策略:系统动作(shutdown/reboot/upgrade/back_hiby/set-default-*)仅放行 `os.meow.*` 包或系统身份;
|
||||
* 读/状态类(status/battery/reboot_reason/upgrade_status/screen/dac)放行所有 root 调用方;非 root 一律拒。
|
||||
* `MSG_HELLO` 自报 app_id 不在此作权威(仅交叉校验,见 §6.1)。CLI=root 免鉴权。
|
||||
*
|
||||
* 通知转储归属(§3.2/§3.3 已定案):通知存储为 launcher 进程内存(meow_notif.c g_slots[]),服务跨进程
|
||||
* 不可达——**转储由调用方 launcher 先做**,服务对关机/重启/升级一律 `sync()` 落盘,不重实现转储。
|
||||
@@ -593,15 +597,99 @@ static int send_power_status(int fd, uint32_t req_id, const m_power_status_t *st
|
||||
return send_frame(fd, MSG_POWER_STATUS, req_id, &s, sizeof s);
|
||||
}
|
||||
|
||||
/* ---------------- II 期:调用方身份解析(连接级,MPK_SIGNATURE_DESIGN §6.2) ---------------- */
|
||||
typedef enum { CALL_OTHER, CALL_PKG, CALL_SYS } caller_kind_t;
|
||||
typedef struct {
|
||||
caller_kind_t kind;
|
||||
char pkg[MEOW_APP_ID_MAX]; /* CALL_PKG=MeowAPPs/<pkg>/ 取包名;CALL_SYS=系统身份别名 */
|
||||
uid_t uid;
|
||||
} caller_t;
|
||||
|
||||
/* 系统动作(SYSTEM_FRAMEWORK_SERVICES §2.4 + 设计 §6.3 表):须 os.meow.* 包或系统身份。 */
|
||||
static int is_system_action(uint32_t cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case POWER_SHUTDOWN: case POWER_REBOOT: case POWER_UPGRADE:
|
||||
case POWER_BACK_HIBY: case POWER_SET_DEFAULT_MEOW: case POWER_SET_DEFAULT_HIBY:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 是否可信系统身份:CALL_SYS(受信系统二进制)或 CALL_PKG 且包前缀 os.meow.*。 */
|
||||
static int is_sys_identity(const caller_t *c)
|
||||
{
|
||||
if (c->kind == CALL_SYS) return 1;
|
||||
if (c->kind == CALL_PKG && !strncmp(c->pkg, "os.meow.", 8)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 由 exe 路径判身份(纯函数,便于宿主自测 + 生产共用)。前提:out 已 memset(kind 缺省 CALL_OTHER)。
|
||||
* - exe 前缀 /usr/data/mnt/sd_0/MeowAPPs/ → MeowAPP 包(kind=CALL_PKG,pkg=目录名)
|
||||
* - 否则命中系统二进制 allowlist → CALL_SYS
|
||||
* - 其余保持 CALL_OTHER
|
||||
* msg 自报 app_id 仅作交叉校验(不在此处做权威判定,见设计 §6.1/§6.5)。 */
|
||||
static void classify_exe(const char *exe, caller_t *out)
|
||||
{
|
||||
/* MeowAPPs/<pkg>/(与 app_launcher.c meow_pkg_name 同口径:去前缀取第一段目录名) */
|
||||
static const char *mp = "/usr/data/mnt/sd_0/MeowAPPs/";
|
||||
if (strncmp(exe, mp, strlen(mp)) == 0) {
|
||||
const char *p = exe + strlen(mp);
|
||||
if (*p == '/') p++;
|
||||
const char *end = strchr(p, '/');
|
||||
int plen = end ? (int)(end - p) : (int)strlen(p);
|
||||
if (plen > 0 && plen < MEOW_APP_ID_MAX) {
|
||||
memcpy(out->pkg, p, (size_t)plen); out->pkg[plen] = 0;
|
||||
out->kind = CALL_PKG;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 系统二进制 allowlist(/usr/bin/meow_*、/usr/data/meow_*、MeowPanel 后端) */
|
||||
char tmp[MEOW_APP_ID_MAX];
|
||||
if (strcmp(exe, "/usr/bin/meow_launcherd") == 0) {
|
||||
snprintf(tmp, sizeof tmp, "%s", "os.meow.launcher");
|
||||
} else if (strstr(exe, "/MeowPanel/") || strstr(exe, "meowpanel")) {
|
||||
snprintf(tmp, sizeof tmp, "%s", "os.meow.panel");
|
||||
} else if (strncmp(exe, "/usr/bin/meow_", 14) == 0) {
|
||||
/* 截取 "meow_xyz"(去 "/usr/bin/" 前缀)作近似别名 */
|
||||
size_t l = strlen(exe + 11);
|
||||
if (l >= sizeof tmp) l = sizeof tmp - 1;
|
||||
memcpy(tmp, exe + 11, l); tmp[l] = 0;
|
||||
} else if (strncmp(exe, "/usr/data/meow/", 15) == 0) {
|
||||
snprintf(tmp, sizeof tmp, "%s", "os.meow.core");
|
||||
} else {
|
||||
return; /* CALL_OTHER */
|
||||
}
|
||||
snprintf(out->pkg, sizeof out->pkg, "%s", tmp);
|
||||
out->kind = CALL_SYS;
|
||||
}
|
||||
|
||||
/* 由连接 SO_PEERCRED 取 pid → readlink /proc/<pid>/exe → classify_exe(连接创建时缓存,循环内复用)。 */
|
||||
static void classify_caller(int fd, caller_t *out)
|
||||
{
|
||||
memset(out, 0, sizeof *out);
|
||||
out->uid = (uid_t)-1;
|
||||
struct ucred cred;
|
||||
socklen_t cl = sizeof cred;
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &cl) != 0) return;
|
||||
out->uid = cred.uid;
|
||||
|
||||
char procpath[64], exe[256];
|
||||
snprintf(procpath, sizeof procpath, "/proc/%d/exe", (int)cred.pid);
|
||||
ssize_t n = readlink(procpath, exe, sizeof exe - 1);
|
||||
if (n <= 0) return;
|
||||
exe[n] = 0;
|
||||
classify_exe(exe, out);
|
||||
}
|
||||
|
||||
/* 处理单条连接(连接内循环读帧:客户端先 MSG_HELLO 握手,再 MSG_POWER_ACTION)。 */
|
||||
static void handle_conn(int c)
|
||||
{
|
||||
/* 基础鉴权:调用方 uid==0(root)才受理动作。 */
|
||||
struct ucred cred;
|
||||
socklen_t cl = sizeof cred;
|
||||
int uid0 = 0;
|
||||
if (getsockopt(c, SOL_SOCKET, SO_PEERCRED, &cred, &cl) == 0 && cred.uid == 0)
|
||||
uid0 = 1;
|
||||
/* II 期鉴权升级(MPK_SIGNATURE_DESIGN §6.2):uid==0 判定升级为连接级身份解析(pid→exe→包名/系统身份)。 */
|
||||
caller_t caller;
|
||||
classify_caller(c, &caller);
|
||||
|
||||
for (;;) {
|
||||
uint8_t hdr[MEOW_IPC_HDR_LEN];
|
||||
@@ -629,12 +717,20 @@ static void handle_conn(int c)
|
||||
memset(&a, 0, sizeof a);
|
||||
if (rlen > sizeof a) rlen = sizeof a;
|
||||
memcpy(&a, payload, rlen);
|
||||
if (!uid0) {
|
||||
/* 动作级策略(设计 §6.3):非 root 一律拒;系统动作须 os.meow.* 包或受信系统身份;
|
||||
* 读/状态类(STATUS/BATTERY/REBOOT_REASON/UPGRADE_STATUS/SCREEN/DAC)放行所有 root 调用方。 */
|
||||
int allow = 0;
|
||||
if (caller.uid == 0) {
|
||||
if (is_system_action(a.cmd)) allow = is_sys_identity(&caller);
|
||||
else allow = 1;
|
||||
}
|
||||
if (!allow) {
|
||||
m_power_status_t st;
|
||||
memset(&st, 0, sizeof st);
|
||||
st.code = MEOW_ERR_PERM;
|
||||
st.cmd = a.cmd;
|
||||
snprintf(st.msg, sizeof st.msg, "permission denied (uid!=0)");
|
||||
snprintf(st.msg, sizeof st.msg, "permission denied (caller kind=%d uid=%d)",
|
||||
(int)caller.kind, (int)caller.uid);
|
||||
send_power_status(c, req_id, &st);
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user