以用户“apache”运行的 Perl 无法加载 DBD::mysql 而其他用户可以

Posted

技术标签:

【中文标题】以用户“apache”运行的 Perl 无法加载 DBD::mysql 而其他用户可以【英文标题】:Perl running as user "apache" cannot load DBD::mysql while other users can 【发布时间】:2020-08-06 01:33:42 【问题描述】:

我管理的站点有一些 CGI 脚本运行以下形式的脚本:

#!/usr/bin/env bash

perl my-script.pl

my-script.pl 使用 DBD::mysql

use DBD::mysql;

我的脚本使用了许多 CPAN 模块,我不想污染 Linux 发行版安装的“系统”Perl (5.16)。我们的安全策略要求 httpd 以用户“apache”身份运行,并且 apache 在我们的服务器上没有主目录,所以我的解决方案是在我可以访问的不同主目录下安装 Perl 和 perlbrew。然后虚拟主机的 Apache 配置文件设置一些环境变量来访问它。

SetEnv PATH /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/bin:$PATH
SetEnv PERL5LIB /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib  # this may not be needed

这足以加载大多数模块。比如apache可以运行:

perl -mDateTime -e 'print $DateTime::VERSION' # prints "1.52"

但如果 apache 尝试:

perl -mDBD::mysql -e 'print $DBD::mysql::VERSION'

它呕吐:

Can't locate loadable object for module DBD::mysql in @INC (@INC contains: /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2/x86_64-linux /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2 /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/5.30.2/x86_64-linux /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/5.30.2) at -e line 0.
Compilation failed in require.
BEGIN failed--compilation aborted.

错误消息“无法定位...”具有误导性。我确认 DBD::mysql 可从@INC 的第三条路径获得:

$ find ~user1/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2  -name mysql -ls
16540213    4 drwxr-x---   2 user1   user1       4096 Apr 21 12:51 /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2/x86_64-linux/auto/DBD/mysql
16540211    4 drwxr-xr-x   2 user1   user1       4096 Apr 21 11:26 /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2/x86_64-linux/DBD/mysql

此外,user1 可以毫无问题地加载 DBD::mysql:

 perl -mDBD::mysql -e 'print $DBD::mysql::VERSION'  # prints 4.050

因此,我怀疑上面的错误信息应该是“Can't load libmysqlclient.so ...”

libmysqlclient.so 位于 /usr/lib64/mysql/

 ls -l /usr/lib64/mysql/
total 3076
lrwxrwxrwx  1 root root      17 Apr 16 11:59 libmysqlclient_r.so -> libmysqlclient.so
lrwxrwxrwx  1 root root      20 Apr 16 11:59 libmysqlclient.so -> libmysqlclient.so.18
lrwxrwxrwx  1 root root      24 Apr 16 11:57 libmysqlclient.so.18 -> libmysqlclient.so.18.0.0
-rwxr-xr-x  1 root root 3135664 Aug 18  2019 libmysqlclient.so.18.0.0
-rwxr-xr-x  1 root root    6758 Aug 18  2019 mysql_config
drwxr-xr-x. 2 root root    4096 Apr 16 11:57 plugin

如果 user1 运行 perl -V,链接器和动态链接部分将显示以下内容:

  Linker and Libraries:
    ld='cc'
    ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib /lib/../lib64 /usr/lib/../lib64 /lib /lib64 /usr/lib64 /usr/local/lib64
    libs=-lpthread -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.17.so
    so=so
    useshrplib=false
    libperl=libperl.a
    gnulibc_version='2.17'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E'
    cccdlflags='-fPIC'
    lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong'

如果我运行与 apache 相同的 perl,它将产生相同的结果:

sudo -u apache bash
PATH=~user1/perl5/perlbrew/perls/perl-5.30.2/bin:/usr/local/bin:/usr/bin:/usr/X11R6/bin
perl -V
...
  Linker and Libraries:
    ld='cc'
    ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib /lib/../lib64 /usr/lib/../lib64 /lib /lib64 /usr/lib64 /usr/local/lib64
    libs=-lpthread -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.17.so
    so=so
    useshrplib=false
    libperl=libperl.a
    gnulibc_version='2.17'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E'
    cccdlflags='-fPIC'
    lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong'

为什么 user1 perl 可以加载 DBD::mysql 而 apache 却不能,即使两者都运行相同的 Perl 和相同的 @INC 路径,并且它们的动态库加载路径看起来相同?有谁知道我还能做些什么来解决这个问题?

【问题讨论】:

【参考方案1】:

对于初学者,你不应该这样做

SetEnv PERL5LIB /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib 

如果您使用.../perl-5.30.2/bin/perl,它将知道在.../perl-5.30.2/lib 中查找,并且这是唯一应该在该目录中查找的perl


理想情况下,您也不会执行以下操作:

SetEnv PATH /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/bin:$PATH

脚本的 shebang 应该指向它打算使用的 perl(它已经过测试并且已知可以工作)。

换句话说,在bash 脚​​本中使用以下内容:

./my-script.pl

并在my-script.pl 中使用以下shebang:

#!/export/home/user1/perl5/perlbrew/perls/perl-5.30.2/bin/perl

你目前正在做的事情并不可怕,但如果你尝试升级某些东西,可能会咬你。


最后perl因为权限问题找不到模块。假设apache 用户不是user1 组的成员,您表明apache 用户无法访问lib/site_perl/5.30.2/x86_64-linux/auto/DBD/mysql(它也可能无法访问其他相关文件)。

修复:

chmod go+X \
   /export \
   /export/home \
   /export/home/user1\
   /export/home/user1/perl5 \
   /export/home/user1/perl5/perlbrew \
   /export/home/user1/perl5/perlbrew/perls
chmod -R go+rX /export/home/user1/perl5/perlbrew/perls/perl-5.30.2

【讨论】:

配置应该是“SetEnv PATH /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/bin:$PATH”。我试图混淆真实的用户名,但我想我不够小心。我的错。如果您不介意,请在您的回复中更改它,以便我可以遵守我雇主的安全政策。 非常感谢。我将不理会历史。我只是不想留下“欢迎”的牌子。同时,我尝试了这个: env -i bash -c 'source apache-path;环境 |排序; perl -mDBD::mysql -e "print \$DBD::mysql::VERSION" ' 并且它起作用了,因此如果从命令行运行,apache 可以加载 DBD::mysql。文件 apache-path 设置 PATH 环境变量。 根据您显示的内容设置错误(没有名为 ~user1 的目录)。您确定在您的测试中执行了正确的perl 吗?您应该使用sudo -u apache /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/bin/perl -mDBD::mysql -e1 进行测试无论如何,您显示auto/ 的权限为drwxr-x--- user1 user1。这显然是错误的。您是否按照我的回答中的详细说明解决了这个问题? 我再次运行它以更好地控制环境。这次:“无法在 INC 中找到模块 DBD::mysql 的可加载对象(INC 包含:/export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2/x86_64 -linux /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2 /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/5.30 .2/x86_64-linux /export/home/user1/perl5/perlbrew/perls/perl-5.30.2/lib/5.30.2)" 这次INC里面没有"auto"。 DBD/mysql.pm 在第一个路径中可用。 @inktomi,错误消息说“无法找到模块 DBD::mysql 的可加载对象 ...”我仍然认为这意味着 Perl 它无法找到 mysql 的 .so 文件由阿帕奇运行。它在那里:“-rwxr-xr-x 1 root root 3135664 Aug 18 2019 /usr/lib64/mysql/libmysqlclient.so.18.0.0”。 Perl 从命令行以 user1 身份运行时可以成功加载它。当我在服务器上从我自己的个人帐户运行它时,它也可以工作。只有 apache 有问题,即使从命令行也是如此。

以上是关于以用户“apache”运行的 Perl 无法加载 DBD::mysql 而其他用户可以的主要内容,如果未能解决你的问题,请参考以下文章

如何配置 Apache 2 以运行 Perl CGI 脚本?

Apache服务器中运行CGI程序的方法,文中以Perl脚本作为示例

如何以 root 身份运行 Perl 脚本但仍会影响用户 gconf 设置

出现错误无法为模块 Wx 加载“/usr/local/lib64/perl5/auto/Wx/Wx.so”

Apache 无法启动 - 表示 httpd 模块已加载但未运行

Perl Apache 脚本按预期从 browser-perfroms 运行关闭正在运行的 perl 实例,但是当尝试启动新的 perl 实例时它啥也不做