su - oracle切换到oracle用户卡住

一、问题现象

环境情况:Red Hat Enterprise Linux 6.9 Oracle 11g

数据库宕机需要手工启动服务器和监听,发现无法通过su - oracle、su oracle切换到oracle用户 ,执行后直接卡死,无报错、也不退出。

通过su - oracle -c 'bash --noprofile --norc'绕开环境变量登录也卡住。

最后发现sudo -u oracle /bin/sh 仅延迟20多秒,可以正常进入,常规检查:

  • 非登录式切换、跳过环境配置的切换命令依旧卡死,排除用户环境脚本问题
  • 服务器无资源爆满、无磁盘IO阻塞、主机名解析正常,常规排查无异常

新增共性故障:测试切换系统其他普通用户(如 test、ora11203等),全部出现相同卡死现象,并非 oracle 用户单独故障,证明是root全局环境异常导致的系统性问题,非单一用户配置故障。

二、排除常规故障点

为精准定位问题,我们逐层排除全网最常见的 su 卡顿原因,缩小故障范围。

1. 排除 /etc/hosts 主机名解析问题

su 登录式切换会反向解析主机名,DNS/hosts 配置错误是卡顿高发原因。检查本机配置:

|-------------------------|
| hostname cat /etc/hosts |

本机 hosts 已正确配置本机 IP+主机名,localhost 解析正常,彻底排除 DNS 解析阻塞问题

2. 排除用户登录脚本阻塞

常规认知中,su - 加载登录环境(bash_profile/bashrc)、sudo 不加载,若脚本中有网络探测、挂载、休眠命令会导致卡顿。

本次测试:无参数普通切换 su oracle(不加载登录脚本)依然卡死,新增用户也卡死,排除用户环境脚本阻塞问题。

3. 排除 PAM 认证模块异常

依次检查 /etc/pam.d/su、/etc/pam.d/system-auth 配置:

bash 复制代码
[root@yikuer ~]# cat /etc/pam.d/su

#%PAM-1.0

auth            sufficient      pam_rootok.so

# Uncomment the following line to implicitly trust users in the "wheel" group.

#auth           sufficient      pam_wheel.so trust use_uid

# Uncomment the following line to require a user to be in the "wheel" group.

#auth           required        pam_wheel.so use_uid

auth            include         system-auth

account         sufficient      pam_succeed_if.so uid = 0 use_uid quiet

account         include         system-auth

password        include         system-auth

session         include         system-auth

session         optional        pam_xauth.so

[root@yikuer ~]# cat /etc/pam.d/system-auth

#%PAM-1.0

# This file is auto-generated.

# User changes will be destroyed the next time authconfig is run.

auth        required      pam_env.so

auth        sufficient    pam_fprintd.so

auth        sufficient    pam_unix.so nullok try_first_pass

auth        requisite     pam_succeed_if.so uid >= 500 quiet

auth        required      pam_deny.so



account     required      pam_unix.so

account     sufficient    pam_localuser.so

account     sufficient    pam_succeed_if.so uid < 500 quiet

account     required      pam_permit.so



password    requisite     pam_cracklib.so try_first_pass retry=3 type=

password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok

password    required      pam_deny.so



session     optional      pam_keyinit.so revoke

#session     required      pam_limits.so

session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid

session     required      pam_unix.so
  • 无 sssd、ldap、winbind 远程认证模块,纯本地认证配置
  • 无 pam_systemd、异常会话模块
  • 临时注释 pam_limits.so 资源限制模块,故障依旧

同时排查 lastlog、faillock 日志文件,文件大小正常、无损坏、无登录锁定,排除 PAM 认证与日志文件故障

4. 排除系统服务与资源限制

依次重启 dbus、systemd-logind、nscd 等会话与解析服务,清空登录缓存,调整用户资源限制,故障均未恢复。

三、strace 抓包锁定根因

常规排查全部无效后,使用 strace 追踪系统调用,精准定位卡死环节:

|------------------------------------------------------------------------------|
| strace -tt -o su_trace su oracle # 卡住20秒后 Ctrl+C 终止,查看日志末尾 tail -30 su_trace |

bash 复制代码
[root@yikuer ~]# tail -30 su_trace

02:24:49.865114 mprotect(0x7f80a5169000, 2093056, PROT_NONE) = 0

02:24:49.865217 mmap(0x7f80a5368000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0x9000) = 0x7f80a5368000

02:24:49.865325 mmap(0x7f80a536a000, 61648, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f80a536a000

02:24:49.865438 close(5)                = 0

02:24:49.865547 open("/oracle/glibc-2.14/lib/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)

02:24:49.865654 open("tls/x86_64/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)

02:24:49.865755 open("tls/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)

02:24:49.865857 open("x86_64/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)

02:24:49.865958 open("libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory)

02:24:49.866061 open("/lib64/libglib-2.0.so.0", O_RDONLY) = 5

02:24:49.866165 read(5, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300l\201\3174\0\0\0"..., 832) = 832

02:24:49.866266 fstat(5, {st_mode=S_IFREG|0755, st_size=1142944, ...}) = 0

02:24:49.866371 mmap(NULL, 3237912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0) = 0x7f80a4e48000

02:24:49.866475 mprotect(0x7f80a4f5d000, 2097152, PROT_NONE) = 0

02:24:49.866583 mmap(0x7f80a515d000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0x115000) = 0x7f80a515d000

02:24:49.866692 mmap(0x7f80a515e000, 2072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f80a515e000

02:24:49.866794 close(5)                = 0

02:24:49.867101 mprotect(0x7f80a5368000, 4096, PROT_READ) = 0

02:24:49.867374 mprotect(0x7f80a59e1000, 4096, PROT_READ) = 0

02:24:49.867584 mprotect(0x7f80a5c26000, 4096, PROT_READ) = 0

02:24:49.867903 set_tid_address(0x7f80a78899d0) = 15179

02:24:49.868000 set_robust_list(0x7f80a78899e0, 24) = 0

02:24:49.868096 futex(0x7fff1564a5bc, FUTEX_WAKE_PRIVATE, 1) = 0

02:24:49.868259 futex(0x7fff1564a5bc, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 1, NULL, 7f80a7889700) = -1 EAGAIN (Resource temporarily unavailable)

02:24:49.868377 rt_sigaction(SIGRTMIN, {0x7f80a57cfb40, [], SA_RESTORER|SA_SIGINFO, 0x7f80a57d95e0}, NULL, 8) = 0

02:24:49.868496 rt_sigaction(SIGRT_1, {0x7f80a57cfbc0, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x7f80a57d95e0}, NULL, 8) = 0

02:24:49.868579 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0

02:24:49.868680 getrlimit(RLIMIT_STACK, {rlim_cur=10240*1024, rlim_max=RLIM64_INFINITY}) = 0

02:25:10.347868 --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL, si_value={int=0, ptr=0x100000000}} ---

02:25:10.348168 +++ killed by SIGINT +++

关键异常日志

|---------------------------------------------------------------------------------------------------|
| open("/oracle/glibc-2.14/lib/libglib-2.0.so.0", O_RDONLY) = -1 ENOENT (No such file or directory) |

日志明确显示:su 切换用户时,系统动态链接器持续遍历 /oracle/glibc-2.14/lib 目录

root@yikuer \~# ls -ld /oracle/glibc-2.14/lib/

drwxr-xr-x 4 root root 4096 Mar 9 2022 /oracle/glibc-2.14/lib/

root@yikuer \~# ls -l /oracle/glibc-2.14/lib/libglib-2.0.so.0

ls: cannot access /oracle/glibc-2.14/lib/libglib-2.0.so.0: No such file or directory

该目录真实存在,但目录内缺失关键的 libglib-2.0.so.0 库文件。动态链接器会反复重试检索、遍历子目录匹配库文件,持续耗时20秒以上,最终表现为 su 命令卡死无响应。

四、su 卡、sudo 正常 原因

这是本次故障的核心关键点,也是最容易被忽略的运维盲区:

1. su 命令特性

su 会完整继承当前 root 终端的所有环境变量,包括畸形的 LD_LIBRARY_PATH。系统动态链接器 ld.so 会强制遍历环境变量中定义的所有库目录,目录不存在时会反复重试、遍历子目录,造成长时间阻塞卡死。

2. sudo 命令特性

sudo 具备安全净化机制,默认自动清空、过滤高危环境变量,主动丢弃错误的 LD_LIBRARY_PATH,不会遍历无效目录,因此仅轻微延迟、可以正常进入用户环境。

五、临时 永久 解决

1. 临时应急修复(立即生效)

清空当前 root 终端的异常库路径环境变量,即刻恢复 su 切换:

|----------------------------------------------|
| unset LD_LIBRARY_PATH LD_PRELOAD su - oracle |

执行后切换用户秒进,无任何卡顿,验证根因完全匹配。

2. 永久根治(彻底解决复发)

异常变量来源于 root 用户的开机自启配置,需彻底删除错误配置:

步骤1:定位异常变量配置文件

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| root@yikuer \~# grep -r "/oracle/glibc-2.14" /etc/profile /etc/profile.d/ /root/.bash* /root/.bash_history:../configure --prefix=/oracle/glibc-2.14 /root/.bash_history:export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:LD_LIBRARY_PATH /root/.bash_history:export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:LD_LIBRARY_PATH /root/.bash_profile:export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH |

检索结果:异常路径写入了 /root/.bash_profile,每次 root 登录都会自动加载错误 LD_LIBRARY_PATH。

步骤2:删除错误配置

|---------------------------------------------------------------------------------------------------------------|
| # 一键删除异常行 sed -i '/\/oracle\/glibc-2.14\/lib/d' /root/.bash_profile # 重载配置,生效永久 source /root/.bash_profile |

步骤3:验证彻底修复

|-----------------------------------------|
| # 新开终端或直接执行,秒进无卡顿 su - oracle su oracle |

六、 环境变量 配置 glibc-2.14 原因

结合本次服务器历史操作命令:

bash 复制代码
[root@yikuer ~]# history

  493  tar -xf glibc-2.14.tar

  495  cd glibc-2.14

  498  ./configure --prefix=/oracle/glibc-2.14

  499  make -j4

  500  make install

  503  cd /orcale

  506  cd glibc-2.14/

  509  export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH

  510  strings /lib64/libc.so.6 |grep GLIBC_

  539  strings /lib64/libc.so.6 |grep GLIBC_

  540  mpstat

  541  export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH

  542  mpstat

  543  vi ~/.bash_profile

  544  source ~/.bash_profile

可以精准锁定本次手动编译 glibc-2.14、配置全局 LD_LIBRARY_PATH 的直接诱因:RHEL 6.9 系统自带 glibc2.12 版本过低,无法运行新版 mpstat压测工具

bash 复制代码
[root@yikuer ~]# mpstat

mpstat: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by mpstat)

[root@yikuer ~]# export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH

[root@yikuer ~]# mpstat

Linux 2.6.32-696.el6.x86_64 (yikuer)    06/30/26        _x86_64_        (8 CPU)



05:43:45     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle

05:43:45     all    0.50    0.01    0.11    0.09    0.00    0.00    0.02    0.00    0.00   99.26

1. 服务器原生系统限制

服务器系统为 Red Hat Enterprise Linux 6.9 ,系统原生自带 glibc 版本仅为 2.12 ,版本老旧、兼容性极差。大量新版压测工具、系统监控组件、第三方二进制程序、Oracle 附属工具,编译依赖 GLIBC_2.14 及以上版本符号,系统原生库完全无法满足。

2. 从历史日志 及客户沟通了解

当时完整操作流程如下:

  • 首先通过 yum、源码包反复安装stress、sysstat 压力测试工具
  • 运行 mpstat / pidstat / stress 等系统性能工具时,触发了 GLIBC_2.14 版本缺失报错
  • RHEL6.9 官方 yum 源无高版本 glibc,无法通过 yum 升级补齐 GLIBC_2.14 依赖
  • 因此手动下载 glibc-2.14.tar.gz 源码包
  • 手动创建 build 编译目录,自定义安装路径:--prefix=/oracle/glibc-2.14
  • 编译安装完成后,临时写入环境变量:export LD_LIBRARY_PATH=/oracle/glibc-2.14/lib:$LD_LIBRARY_PATH
  • 为了永久生效,写入 /root/.bash_profile
  • 重新 source 加载,用于正常运行 stress、sysstat、监控工具

4. 故障的真相

  • 业务测试结束后,客户清理操作:rm -rf glibc-2.14*
  • 只删除了源码包、编译缓存
  • 没有删除 /oracle/glibc-2.14/ 安装目录
  • 没有删除 .bash_profile 中的 LD_LIBRARY_PATH 变量
  • 久而久之目录残留、变量残留,但内部关键 .so 库文件缺失
  • 最终导致:所有 su 切换用户触发 ld.so 遍历卡死

、故障复盘与运维总结

1. 故障根源

服务器为适配mpstat、 stress压测工具(依赖 GLIBC_2.14),在 RHEL6.9 原生 glibc2.12 不兼容的情况下,手动编译安装 glibc-2.14,并将库路径写入 root 全局环境变量实现临时兼容。压测实验结束后,仅删除了编译源码与临时文件,未清理全局 LD_LIBRARY_PATH 变量、未删除残留安装目录,导致系统动态链接器每次执行 su 切换用户时,遍历无效库路径反复重试,最终造成命令卡死。

2. 核心区别总结

  • su:继承全部环境变量,无净化机制,易受异常变量影响卡死
  • sudo:自动净化环境变量,规避大部分变量导致的卡顿问题

3. 运维避坑建议

  • 临时测试的环境变量,切勿写入 root 全局开机配置,避免长期残留故障
  • 遇到 su 卡顿、sudo 正常的差异化故障,优先排查 LD_LIBRARY_PATH 路径存在但库文件缺失的场景,这是极易被忽略的隐性故障点
  • 常规排查无效时,优先使用 strace 追踪系统调用,精准定位阻塞环节,避免盲目排查
  • 自定义编译系统依赖库后,需及时清理无用环境变量与残留配置