kt-template-online-api/ci/napcat-desktop-cn/entrypoint-device-profile.patch.sh

212 lines
9.8 KiB
Bash

#!/bin/sh
set -eu
ENTRYPOINT=/app/entrypoint.sh
if grep -q 'KT device profile patch defaults' "$ENTRYPOINT"; then
exit 0
fi
grep -q 'mount --bind "$FAKE_CMDLINE" /proc/1/cmdline' "$ENTRYPOINT"
cat >/tmp/kt-device-profile-defaults.sh <<'EOF'
# KT device profile patch defaults.
: "${NAPCAT_REQUIRE_DEVICE_PROFILE:=0}"
: "${NAPCAT_DMI_PRODUCT_NAME:=imini Pro}"
: "${NAPCAT_DMI_PRODUCT_UUID:=00000000-0000-0000-0000-000000000000}"
: "${NAPCAT_DMI_SYS_VENDOR:=MECHREVO}"
: "${NAPCAT_DMI_BOARD_VENDOR:=MECHREVO}"
: "${NAPCAT_DMI_BOARD_NAME:=imini Pro}"
: "${NAPCAT_DMI_BIOS_VENDOR:=American Megatrends International, LLC.}"
: "${NAPCAT_DMI_BIOS_VERSION:=imini Pro 1.10}"
: "${NAPCAT_DMI_MODALIAS:=dmi:bvnAmericanMegatrendsInternational,LLC.:bvriminiPro1.10:bd03/31/2024:br1.10:efr1.10:svnMECHREVO:pniminiPro:pvrStandard:rvnMECHREVO:rniminiPro:rvrStandard:cvnMECHREVO:ct3:cvrDefaultstring:skuStandard:}"
: "${NAPCAT_DEVICE_BOOT_ID:=00000000-0000-4000-8000-000000000000}"
: "${NAPCAT_DEVICE_KERNEL_RELEASE:=6.8.0-60-generic}"
: "${NAPCAT_DEVICE_KERNEL_VERSION:=#63-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 15 19:04:15 UTC 2025}"
: "${NAPCAT_DEVICE_PROC_VERSION:=Linux version 6.8.0-60-generic (buildd@lcy02-amd64-001) (x86_64-linux-gnu-gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0, GNU ld (GNU Binutils for Ubuntu) 2.42) #63-Ubuntu SMP PREEMPT_DYNAMIC Tue Apr 15 19:04:15 UTC 2025}"
: "${NAPCAT_DEVICE_CPU_MODEL:=AMD Ryzen 7 8845H w/ Radeon 780M Graphics}"
: "${NAPCAT_DEVICE_UPTIME:=7200.00 14400.00}"
: "${NAPCAT_DEVICE_TTY_ACTIVE:=tty1}"
: "${NAPCAT_DEVICE_MOUNTINFO_GUARD_ENABLED:=1}"
: "${NAPCAT_DEVICE_MOUNTINFO_GUARD_INTERVAL:=1}"
kt_fake_file() {
kt_target="$1"
kt_content="$2"
kt_name="$(echo "$kt_target" | tr '/' '_')"
kt_fake="$FAKE_CGROUP_DIR/kt_device_profile_$kt_name"
printf '%s\n' "$kt_content" > "$kt_fake"
mount --bind "$kt_fake" "$kt_target" 2>/dev/null || true
}
EOF
cat >/tmp/kt-device-profile-dmi.sh <<'EOF'
# KT device profile DMI overrides for files QQCore opens.
kt_fake_file /sys/class/dmi/id/product_name "$NAPCAT_DMI_PRODUCT_NAME"
kt_fake_file /sys/class/dmi/id/product_uuid "$NAPCAT_DMI_PRODUCT_UUID"
kt_fake_file /sys/class/dmi/id/sys_vendor "$NAPCAT_DMI_SYS_VENDOR"
kt_fake_file /sys/class/dmi/id/board_vendor "$NAPCAT_DMI_BOARD_VENDOR"
kt_fake_file /sys/class/dmi/id/board_name "$NAPCAT_DMI_BOARD_NAME"
kt_fake_file /sys/class/dmi/id/bios_vendor "$NAPCAT_DMI_BIOS_VENDOR"
kt_fake_file /sys/class/dmi/id/bios_version "$NAPCAT_DMI_BIOS_VERSION"
kt_fake_file /sys/class/dmi/id/modalias "$NAPCAT_DMI_MODALIAS"
EOF
cat >/tmp/kt-device-profile-proc.sh <<'EOF'
# KT device profile proc/sys files QQCore opens.
kt_fake_file /proc/sys/kernel/random/boot_id "$NAPCAT_DEVICE_BOOT_ID"
kt_fake_file /proc/sys/kernel/version "$NAPCAT_DEVICE_KERNEL_VERSION"
kt_fake_file /proc/version "$NAPCAT_DEVICE_PROC_VERSION"
kt_fake_file /proc/uptime "$NAPCAT_DEVICE_UPTIME"
if [ -f /proc/cpuinfo ]; then
KT_FAKE_CPUINFO="$FAKE_CGROUP_DIR/kt_device_profile_proc_cpuinfo"
awk -v model="$NAPCAT_DEVICE_CPU_MODEL" '
/^model name[[:space:]]*:/ { $0 = "model name\t: " model }
/^flags[[:space:]]*:/ {
gsub(/(^| )hypervisor( |$)/, " ")
gsub(/[[:space:]]+/, " ")
}
{ print }
' /proc/cpuinfo > "$KT_FAKE_CPUINFO" 2>/dev/null || true
mount --bind "$KT_FAKE_CPUINFO" /proc/cpuinfo 2>/dev/null || true
fi
if [ -f /proc/devices ]; then
KT_FAKE_DEVICES="$FAKE_CGROUP_DIR/kt_device_profile_proc_devices"
grep -Ev 'trim-trashbin|zvol' /proc/devices > "$KT_FAKE_DEVICES" 2>/dev/null || true
mount --bind "$KT_FAKE_DEVICES" /proc/devices 2>/dev/null || true
fi
if [ -f /sys/devices/virtual/tty/tty0/active ]; then
kt_fake_file /sys/devices/virtual/tty/tty0/active "$NAPCAT_DEVICE_TTY_ACTIVE"
fi
if [ -f /etc/hosts ]; then
KT_FAKE_HOSTS="$FAKE_CGROUP_DIR/kt_device_profile_hosts"
{
printf '127.0.0.1\tlocalhost\n'
printf '::1\tlocalhost ip6-localhost ip6-loopback\n'
printf 'fe00::\tip6-localnet\n'
printf 'ff00::\tip6-mcastprefix\n'
printf 'ff02::1\tip6-allnodes\n'
printf 'ff02::2\tip6-allrouters\n'
} > "$KT_FAKE_HOSTS"
mount --bind "$KT_FAKE_HOSTS" /etc/hosts 2>/dev/null || true
fi
# KT device profile mountinfo guard for long-lived QQ/NapCat processes.
KT_MOUNTINFO_HOST_LEAK_PATTERN='overlay|/vol1/docker|docker-init|/docker/containers|napcat-instances|btrfs|/dev/mapper/trim'
KT_FAKE_MOUNTINFO="$FAKE_CGROUP_DIR/kt_device_profile_mountinfo"
cat > "$KT_FAKE_MOUNTINFO" <<'KT_MOUNTINFO_EOF'
22 1 259:2 / / rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
23 22 0:6 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
24 22 0:22 / /dev rw,nosuid,relatime - tmpfs udev rw,size=4096000k,nr_inodes=1024000,mode=755,inode64
25 24 0:23 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000
26 22 0:24 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw
27 22 0:25 / /run rw,nosuid,nodev,relatime - tmpfs tmpfs rw,mode=755,inode64
28 22 259:2 /home/napcat/.config /app/.config rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
29 22 259:2 /home/napcat/.cache /app/.cache rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
30 22 259:2 /home/napcat/.local/share /app/.local/share rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
KT_MOUNTINFO_EOF
kt_mask_mountinfo_target() {
kt_mountinfo="$1"
if [ -f "$kt_mountinfo" ] && grep -E "$KT_MOUNTINFO_HOST_LEAK_PATTERN" "$kt_mountinfo" >/dev/null 2>&1; then
mount --bind "$KT_FAKE_MOUNTINFO" "$kt_mountinfo" 2>/dev/null || true
fi
}
kt_mountinfo_guard_once() {
for kt_mountinfo_pid_dir in /proc/[0-9]*; do
[ -d "$kt_mountinfo_pid_dir" ] || continue
kt_mountinfo_pid="${kt_mountinfo_pid_dir#/proc/}"
kt_mountinfo_comm="$(cat "$kt_mountinfo_pid_dir/comm" 2>/dev/null || true)"
kt_mountinfo_cmdline="$(tr '\000' ' ' < "$kt_mountinfo_pid_dir/cmdline" 2>/dev/null || true)"
case "$kt_mountinfo_comm $kt_mountinfo_cmdline" in
*qq*|*QQ*|*napcat*|*NapCat*|*Xvfb*)
kt_mask_mountinfo_target "/proc/$kt_mountinfo_pid/mountinfo"
;;
esac
done
}
kt_mountinfo_guard_loop() {
while :; do
kt_mountinfo_guard_once
sleep "${NAPCAT_DEVICE_MOUNTINFO_GUARD_INTERVAL:-1}"
done
}
kt_mask_mountinfo_target /proc/1/mountinfo
kt_mask_mountinfo_target /proc/self/mountinfo
if [ "${NAPCAT_DEVICE_MOUNTINFO_GUARD_ENABLED:-1}" = "1" ]; then
kt_mountinfo_guard_loop >/dev/null 2>&1 &
fi
EOF
cat >/tmp/kt-device-profile-verify.sh <<'EOF'
if [ "${NAPCAT_REQUIRE_DEVICE_PROFILE:-0}" = "1" ]; then
kt_require_device_profile() {
kt_device_profile_label="$1"
shift
"$@" || {
echo "NapCat device profile check failed: $kt_device_profile_label" >&2
exit 78
}
}
kt_require_device_profile proc1-cmdline sh -c "tr '\\000' ' ' </proc/1/cmdline | grep -q '/sbin/init'"
kt_require_device_profile proc1-sched grep -q 'systemd' /proc/1/sched
kt_require_device_profile proc1-status grep -q '^NSpid:[[:space:]]*1' /proc/1/status
kt_require_device_profile proc1-stat grep -q '(systemd)' /proc/1/stat
kt_require_device_profile dmi-product grep -q "$NAPCAT_DMI_PRODUCT_NAME" /sys/class/dmi/id/product_name
kt_require_device_profile dmi-product-uuid grep -q "$NAPCAT_DMI_PRODUCT_UUID" /sys/class/dmi/id/product_uuid
kt_require_device_profile dmi-sys-vendor grep -q "$NAPCAT_DMI_SYS_VENDOR" /sys/class/dmi/id/sys_vendor
kt_require_device_profile dmi-bios-vendor grep -q "$NAPCAT_DMI_BIOS_VENDOR" /sys/class/dmi/id/bios_vendor
kt_require_device_profile dmi-bios-version grep -q "$NAPCAT_DMI_BIOS_VERSION" /sys/class/dmi/id/bios_version
kt_require_device_profile dmi-modalias grep -q "$NAPCAT_DMI_MODALIAS" /sys/class/dmi/id/modalias
kt_require_device_profile boot-id grep -q "$NAPCAT_DEVICE_BOOT_ID" /proc/sys/kernel/random/boot_id
kt_require_device_profile kernel-version grep -q "$NAPCAT_DEVICE_KERNEL_VERSION" /proc/sys/kernel/version
kt_require_device_profile proc-version grep -q "$NAPCAT_DEVICE_KERNEL_RELEASE" /proc/version
kt_require_device_profile proc-uptime grep -q "$NAPCAT_DEVICE_UPTIME" /proc/uptime
kt_require_device_profile proc-cpuinfo grep -q "$NAPCAT_DEVICE_CPU_MODEL" /proc/cpuinfo
if grep -q 'hypervisor' /proc/cpuinfo; then
echo "NapCat device profile check failed: cpuinfo-hypervisor-flag" >&2
exit 78
fi
if [ -f /sys/devices/virtual/tty/tty0/active ]; then
kt_require_device_profile tty-active grep -q "$NAPCAT_DEVICE_TTY_ACTIVE" /sys/devices/virtual/tty/tty0/active
else
echo "NapCat device profile check failed: tty0-active-missing" >&2
exit 78
fi
KT_MOUNTINFO_HOST_LEAK_PATTERN='overlay|/vol1/docker|docker-init|/docker/containers|napcat-instances|btrfs|/dev/mapper/trim'
for kt_mountinfo in /proc/1/mountinfo; do
if grep -E "$KT_MOUNTINFO_HOST_LEAK_PATTERN" "$kt_mountinfo" >/dev/null 2>&1; then
echo "NapCat device profile check failed: mountinfo-host-leak:$kt_mountinfo" >&2
exit 78
fi
done
if [ "$(hostname)" != "localhost" ] && grep -q "$(hostname)" /etc/hosts; then
echo "NapCat device profile check failed: hosts-still-contains-hostname" >&2
exit 78
fi
if grep -E 'trim-trashbin|zvol' /proc/devices >/dev/null 2>&1; then
echo "NapCat device profile check failed: proc-devices-host-leak" >&2
exit 78
fi
fi
EOF
sed -i '/FAKE_CGROUP_DIR="\/tmp\/fake_cgroup"/r /tmp/kt-device-profile-defaults.sh' "$ENTRYPOINT"
sed -i '/# Docker Socket/r /tmp/kt-device-profile-dmi.sh' "$ENTRYPOINT"
sed -i '/# \/proc\/1\/sched/r /tmp/kt-device-profile-proc.sh' "$ENTRYPOINT"
sed -i '/: ${NAPCAT_UID:=0}/r /tmp/kt-device-profile-verify.sh' "$ENTRYPOINT"
rm -f \
/tmp/kt-device-profile-defaults.sh \
/tmp/kt-device-profile-dmi.sh \
/tmp/kt-device-profile-proc.sh \
/tmp/kt-device-profile-verify.sh