Skip to content

fix(install): prevent infinite su recursion when running as root#55

Merged
noFloat merged 1 commit into
Tencent:mainfrom
YOMXXX:fix/install-root-su-recursion
May 20, 2026
Merged

fix(install): prevent infinite su recursion when running as root#55
noFloat merged 1 commit into
Tencent:mainfrom
YOMXXX:fix/install-root-su-recursion

Conversation

@YOMXXX
Copy link
Copy Markdown
Contributor

@YOMXXX YOMXXX commented May 18, 2026

Summary | 摘要

修复 #20:root 用户直接跑 `install_hermes_memory_tencentdb.sh` 会触发 `su - root` 无限递归。改为只在目标用户非 root 时 `su -` 切换;如果当前 root 且目标也是 root,直接以 root 跑安装。顺带支持 `SUDO_USER` 与 `INSTALL_AS_USER` env override,让 sudo 场景与管理员场景都正确。

Fix #20: running `install_hermes_memory_tencentdb.sh` as root triggered `su - root` infinite recursion. Now only `su`-switches when the target user is not root; if both are root, installs in place. Also honors `SUDO_USER` and `INSTALL_AS_USER` env overrides so `sudo` and admin scenarios pick the right target.

Root cause

`scripts/install_hermes_memory_tencentdb.sh` (before):

```bash
USERNAME=$(whoami) # → "root" when invoked by root
...
if [ "$(id -u)" -eq 0 ]; then
echo "Running as root, switching to $USERNAME for installation..."
su - $USERNAME -c "bash $TEMP_SCRIPT" # → su - root → loops
fi
```

`su - root` 进入一个新 root shell 重新跑这个脚本,新 shell 看到 `id -u == 0` 又 `su -`,永远停不下来。Issue 报告者 @cuiweiyou 的现象:

```
[memory-tencentdb] Running as root, switching to root for installation...
[memory-tencentdb] Running as root, switching to root for installation...
... (只能 Ctrl+C)
```

Fix

1. USERNAME 解析优先级链

```bash
USERNAME="${INSTALL_AS_USER:-${SUDO_USER:-$(whoami)}}"
```

  • `INSTALL_AS_USER` —— 管理员显式 override("我以 root 跑但想给 bar 用户安装")
  • `SUDO_USER` —— `sudo bash install.sh` 调用时 sudo 自动设置,让我们切回原用户而不是 root
  • `whoami` —— 兜底(裸跑、无 sudo 也无 override)

2. 把 `if` 拆成两条分支

```bash
if [ "$(id -u)" -eq 0 ] && [ "$USERNAME" != "root" ]; then
# 当前 root + 目标非 root → su 切换(原有逻辑)
...
elif [ "$(id -u)" -eq 0 ]; then
# 当前 root + 目标也是 root → 直接 inline 安装,不 su(避免 #20 递归)
echo "Running as root; target user is also root — installing in place."
fi
```

第二条 `elif` 故意让控制流落到下方 "用户阶段(核心安装逻辑)",以 root 身份直接跑剩下的安装步骤。

Compatibility | 兼容性

Dry-run 模拟 5 个场景行为:

场景 分支 USERNAME
root SSH 直接跑(#20 复现路径) INLINE root
普通用户直接跑 NORMAL(fall through)
`sudo bash install.sh` 从 user `foo` SU foo
root + `INSTALL_AS_USER=bar` SU bar
root + `INSTALL_AS_USER=root`(显式 admin) INLINE root

dry-run 脚本见 PR description 之外的本地验证(见 commit message)。

`INSTALL_AS_USER` / `SUDO_USER` 是的输入;既有用户没设这两个的情况下,`USERNAME` 仍然 fall back 到 `whoami` —— 即所有非 root 用户的现有行为完全不变。

Manual test plan

```bash

Before fix(复现 #20):

sudo su - # root shell
bash scripts/install_hermes_memory_tencentdb.sh

→ 反复输出 "Running as root, switching to root..." 直到 Ctrl+C

After fix:

sudo su -
bash scripts/install_hermes_memory_tencentdb.sh

→ 输出 "Running as root; target user is also root — installing in place."

→ 继续正常安装

sudo 场景(顺带改进):

sudo bash scripts/install_hermes_memory_tencentdb.sh

→ 输出 "Running as root, switching to for installation..."

→ 之前会以 root 安装;现在会切回原用户安装

```

Out of scope

  • 不动 `install_hermes_ubuntu.sh`(它有同样模式但是另一个仓库的 issue),虽然脚本顶部注释提到"与 install_hermes_ubuntu.sh 保持一致"。腾讯团队若同意,可以同步那边。
  • 不引入 shell test 框架(bats);用 dry-run 验证 + manual test plan 覆盖。

DCO

Commit 带 `Signed-off-by: 李冠辰 liguanchen@xiaomi.com`。

Closes #20.

If install_hermes_memory_tencentdb.sh is invoked directly by the root
user (e.g. fresh server with root SSH login), the prior logic:

  USERNAME=$(whoami)             # → "root"
  if [ "$(id -u)" -eq 0 ]; then
      su - $USERNAME -c "bash $TEMP_SCRIPT"   # → su - root → root → loops
  fi

would spin forever: ``su - root`` enters a fresh root shell that re-runs
the script, which sees EUID=0 again and ``su -``-s itself once more.
Symptom (per issue Tencent#20):

  [memory-tencentdb] Running as root, switching to root for installation...
  [memory-tencentdb] Running as root, switching to root for installation...
  ...   (only Ctrl+C stops it)

Fix:

  1. ``USERNAME`` resolution adds two precedence steps before
     ``$(whoami)`` so admins running ``sudo bash install.sh`` end up
     installing for the original user instead of for root:
       a. ``INSTALL_AS_USER`` env override (explicit admin choice)
       b. ``SUDO_USER`` (sudo's own record of the calling user)
       c. ``whoami`` (final fallback)

  2. The ``id -u == 0`` branch now skips the ``su -`` step when the
     target user is also root — that's the recursion-trigger case. The
     script proceeds inline as root for the rest of the install.

  3. A new ``elif`` arm logs a clear ``"Running as root; target user is
     also root — installing in place."`` so the operator sees what's
     happening.

Verified by dry-run simulation of 5 scenarios:

  | Case                                    | Branch        | USERNAME |
  | --------------------------------------- | ------------- | -------- |
  | root SSH direct (Tencent#20 reproducer)        | INLINE        | root     |
  | non-root user direct                    | NORMAL        | <user>   |
  | sudo bash install.sh from non-root user | SU            | <user>   |
  | root + INSTALL_AS_USER=bar              | SU            | bar      |
  | root + INSTALL_AS_USER=root             | INLINE        | root     |

Closes Tencent#20.

Signed-off-by: 李冠辰 <liguanchen@xiaomi.com>
@Maxwell-Code07
Copy link
Copy Markdown
Collaborator

Hi @YOMXXX

已收到关于 root 安装递归问题的修复 PR,感谢贡献!我们会内部评审后回复。

@noFloat noFloat merged commit f81b79e into Tencent:main May 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

install_hermes_memory_tencentdb.sh 以 root 执行时会 su - root 递归

3 participants