麒麟 V10 SP1 踩坑:./startup.sh 报"解释器错误: 权限不够",根因是 KySec
一台麒麟 V10 SP1 的开发机,一个再普通不过的
./startup.sh start,先后试了sudo bash、chmod +x、换用户su,全卡在同一个报错上。最后发现拦路的是麒麟自带的 KySec------这篇把现象、误判点、根因、长期解法一次记清楚。
一、现象还原
脚本是一个 Spring Boot Jar 的启停封装(startup.sh),放在用户家目录下的 service/ 里:
bash
$ ./startup.sh start
-bash: ./startup.sh:/bin/bash:解释器错误: 权限不够
第一反应是权限问题,于是常规三连:
bash
$ ls -l startup.sh
-rwxrwxr-x 1 appuser appuser 3502 7月 1 17:13 startup.sh
# x 位明明在
$ chmod +x startup.sh
$ ./startup.sh start
# 照样报
$ sudo bash ./startup.sh start
KYSEC: 权限不够
# sudo 都不行,反而多了个 KYSEC 前缀
连 bash startup.sh start 也拦,基本可以排除:
- ❌ 脚本没 x 位
- ❌ shebang 写错(
#!/bin/bash没问题) - ❌ 所在分区
noexec(mount | grep noexec只命中 sysfs/proc/tmpfs/cgroup 这些伪文件系统,家目录不在列)
二、根因:KySec 的 exec control = enforcing
麒麟 V10 系列内置了一个叫 KySec 的内核安全模块,定位类似 SELinux,但策略更"国产桌面/服务器"向。其中有一个开关:
bash
$ getstatus
KySec status: enabled
exec control : enforcing ← 关键
net control : off
file protect : on
kmod protect : on
...
exec control = enforcing 的含义是:非白名单路径/非白名单文件,禁止 execve。
用户家目录 ~/service/startup.sh 不在 KySec 默认信任路径(/usr/bin、/opt/<规范厂商>/ 之类)里,于是:
| 执行方式 | 实际发生了什么 |
|---|---|
./startup.sh |
内核走 shebang 拉 /bin/bash 去 exec 脚本体 → KySec 拦 → bash 报"解释器错误: 权限不够" |
bash startup.sh |
bash 直接 exec 脚本 → KySec 拦 → 吐 KYSEC: 权限不够 |
sudo bash startup.sh |
KySec 不认 sudo 提权免检,照样拦 |
为什么 su appuser 再跑又能过?因为切换后的执行上下文落在 appuser 自家 $HOME 下已加入白名单(或 kysec 对属主自执行放宽) 的路径里,不是 sudo 上下文能比的。
三、临时绕过(验证用)
bash
sudo setstatus -f exectl off
./startup.sh start
# [OK] 启动成功
关掉 exectl 立刻能跑,证明判错 100% 在 KySec。但这个关法是临时的,重启会根据 /etc/kysec.conf 回弹回 enforcing,不适合生产长期挂着。
四、长期方案(按推荐度)
✅ 方案 A:给脚本打 KySec 白名单 xattr(最干净)
KySec 支持给单个文件打 security.kysec.exec 扩展属性,等于 per-file 放行:
bash
sudo setfattr -n security.kysec.exec -v "allowed" /home/appuser/service/startup.sh
sudo setfattr -n security.kysec.exec -v "allowed" /opt/myapp/service/startup.sh
验证:
bash
getfattr -n security.kysec.exec /home/appuser/service/startup.sh
# security.kysec.exec="allowed"
打完再把 exectl 开回 enforcing,脚本照跑,等保也过得去。
✅ 方案 B:迁到 /opt/<应用名>/ 规范路径
麒麟 KySec 对 /opt/<vendor>/ 下的 exec 默认放行程度高于家目录,具体看 /etc/kysec.conf 的 [exec] 段。把整套 service/ + jar 挪过去,启停路径跟着改,也能绕。
⚠️ 方案 C:warning 代替 off
bash
sudo setstatus -f exectl warning
warning 是拦但记日志 (dmesg / audit 可见),调试期友好;off 是完全不检,等保扫描可能扣分,不建议生产。
❌ 不推荐的:持久化 EXEC_CONTROL=off
bash
sudo sed -i 's/^EXEC_CONTROL=.*/EXEC_CONTROL=off/' /etc/kysec.conf
除非是纯内网开发机,否则别这么干,KySec 其他防护(file protect / kmod protect)还是有用的。
五、顺手提一句:改成 systemd 更省事
如果这个启停最终是要上服务器的,其实可以干脆把 startup.sh + jar 包成 systemd service:
ini
# /etc/systemd/system/myapp.service
[Unit]
Description=MyApp Service
After=network.target
[Service]
Type=forking
User=appuser
ExecStart=/opt/myapp/service/startup.sh start
ExecStop=/opt/myapp/service/startup.sh stop
PIDFile=/opt/myapp/service/myapp.pid
[Install]
WantedBy=multi-user.target
systemd 托管的服务,KySec 走的是另一套放行逻辑(跟着 service 上下文,不是用户 shell exec),连 exectl 这档事都不用操心:
bash
sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl enable myapp
六、一句话复盘
麒麟上报"解释器错误: 权限不够",
sudo都不行,但 x 位、noexec、shebang 都没问题时------先getstatus看一眼 KySec 的exec control。临时setstatus -f exectl off能验,长期用setfattr打白名单或用 systemd 托管,比一直关 exectl 稳。
环境:Kylin Linux Advanced Server V10 (SP1) / KySec 3.x。同款踩坑的可以对号入座。