mirror of
https://github.com/wnlen/clash-for-linux.git
synced 2026-10-10 04:03:04 +08:00
Fix tun on: recognize setcap capability and block sudo on user install (#267)
Problem 1 - can_manage_tun_safely() missed setcap grants: - Add kernel_binary_has_cap_net_admin(): use getcap to detect file capability cap_net_admin on the kernel binary, so a user who ran 'setcap cap_net_admin,cap_net_raw+ep mihomo' is allowed through. - Extend can_manage_tun_safely() to call this check after the existing capsh (current-shell) check. - In cmd_tun_on(), add a process-level fallback via the existing tun_process_has_cap_net_admin() for cases where getcap is unavailable but the running process already holds the capability. Problem 2 - sudo clashctl corrupts runtime file ownership: - Add guard_sudo_on_user_install(): detects root + SUDO_USER + stored install scope == user, refuses with a clear message and instructs the user to run as the install user directly. - Call the guard at the entry of both cmd_tun_on() and cmd_tun_off() so neither write path can corrupt runtime/ file ownership.
This commit is contained in:
@@ -4916,6 +4916,8 @@ cmd_tun_on() {
|
||||
local verify_result
|
||||
local container_mode risk_reason
|
||||
|
||||
guard_sudo_on_user_install "on" || return 1
|
||||
|
||||
prepare
|
||||
|
||||
container_mode="$(tun_container_mode 2>/dev/null || echo unknown)"
|
||||
@@ -4944,12 +4946,21 @@ cmd_tun_on() {
|
||||
esac
|
||||
|
||||
if ! can_manage_tun_safely; then
|
||||
echo
|
||||
echo "❗ Tun 模式无法开启"
|
||||
echo "🚨 原因:当前环境不满足基础 Tun 条件"
|
||||
echo "👉 下一步:clashctl tun doctor"
|
||||
echo
|
||||
return 1
|
||||
# Fallback: check if the running mihomo process already has CAP_NET_ADMIN
|
||||
# (covers the case where setcap was applied after the binary check fails
|
||||
# due to getcap being unavailable, or the process received the capability
|
||||
# through another mechanism).
|
||||
local _fb_backend
|
||||
_fb_backend="$(runtime_backend 2>/dev/null || echo unknown)"
|
||||
if ! tun_process_has_cap_net_admin "$_fb_backend" 2>/dev/null; then
|
||||
echo
|
||||
echo "❗ Tun 模式无法开启"
|
||||
echo "🚨 原因:当前环境不满足基础 Tun 条件"
|
||||
echo "💡 若已通过 setcap 授权 mihomo,请确认 getcap 已安装并重试"
|
||||
echo "👉 下一步:clashctl tun doctor"
|
||||
echo
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$(tun_kernel_support_level 2>/dev/null || echo unknown)" in
|
||||
@@ -4996,6 +5007,8 @@ cmd_tun_on() {
|
||||
cmd_tun_off() {
|
||||
local verify_result
|
||||
|
||||
guard_sudo_on_user_install "off" || return 1
|
||||
|
||||
prepare
|
||||
|
||||
if ! sync_tun_target_state "off" "false"; then
|
||||
|
||||
@@ -2030,6 +2030,14 @@ has_ip_command() {
|
||||
command -v ip >/dev/null 2>&1
|
||||
}
|
||||
|
||||
kernel_binary_has_cap_net_admin() {
|
||||
local _bin
|
||||
_bin="$(runtime_kernel_bin 2>/dev/null || true)"
|
||||
[ -n "${_bin:-}" ] && [ -x "${_bin}" ] || return 1
|
||||
command -v getcap >/dev/null 2>&1 || return 1
|
||||
getcap "$_bin" 2>/dev/null | grep -q 'cap_net_admin'
|
||||
}
|
||||
|
||||
can_manage_tun_safely() {
|
||||
if ! tun_device_exists; then
|
||||
return 1
|
||||
@@ -2039,10 +2047,37 @@ can_manage_tun_safely() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Current shell has CAP_NET_ADMIN
|
||||
if has_cap_net_admin; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Kernel binary has file capability cap_net_admin (setcap)
|
||||
if kernel_binary_has_cap_net_admin; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Guard: refuse to run a tun action as root via sudo when the installation
|
||||
# was done in user scope. Writing runtime files as root corrupts their
|
||||
# ownership and breaks subsequent systemctl --user operations.
|
||||
guard_sudo_on_user_install() {
|
||||
local _action="${1:-on}"
|
||||
is_root_user || return 0
|
||||
[ -n "${SUDO_USER:-}" ] || return 0
|
||||
|
||||
local _stored_scope
|
||||
_stored_scope="$(install_env_scope 2>/dev/null || true)"
|
||||
[ "${_stored_scope:-}" = "user" ] || return 0
|
||||
|
||||
echo
|
||||
echo "❗ 操作被拒绝:user 安装模式不支持以 sudo 运行"
|
||||
echo "🚨 原因:sudo 会将 runtime 文件写成 root:root,导致 systemctl --user 无法访问"
|
||||
echo "👤 请以安装用户(${SUDO_USER})直接执行:"
|
||||
echo " clashctl tun ${_action}"
|
||||
echo
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user