7

所以我有以下问题:我有一个在 Linux 上的 Tomcat7 服务器内运行的 Web 服务。然而,Web 服务必须执行一些命令(主要是文件操作,例如复制和挂载)。我已经用 java.nio 替换了,但我认为没有mount.

所以我试图从我的 Tomcat Java 进程中执行 shell 命令。不幸的是,它不执行我的命令。我之前已经在 J​​ava 中实现了 shell 命令的执行。所以我的代码应该是正确的:

Process pr = Runtime.getRuntime().exec("mount -o loop -t iso9660 <myimage> <mymountpoint>");
pr.waitFor();

<myimage>并且<mymountpoint>是绝对路径,所以也没有问题。

  • 我已经调试了我的命令,它们在控制台上执行时正在工作。
  • 我试过发送其他命令。简单的命令,如idpwd正在工作!
  • 我试过使用/bin/bash -c "<command>",没有用。
  • 我试过执行一个shell脚本,它执行命令,但没有用。
  • 我尝试转义命令中的空格,但没有成功。

所以我已经深入挖掘,现在我怀疑一些 Tomcat 安全策略(沙盒?),它阻止我执行命令。由于安全性对我来说不是问题(它是一个内部系统,与外界完全隔离),我尝试了一种 hack,它最近变得非常流行:

System.setSecurityManager(null);

这也不起作用。我在 RHEL6 上使用 Java7 和 Tomcat7。Tomcat7刚刚解压!我在 /etc/.. 或除 /opt/tomcat/ 之外的任何其他文件夹中没有任何文件,我从 Tomcat 主页中提取了 zip。我在 /opt/tomcat/conf 文件夹中搜索了安全设置,但我能找到的只是文件 catalina.policy,我似乎无法为 shell 命令设置一些安全级别。

有任何想法吗?

4

5 回答 5

7

一些东西:

System.setSecurityManager(null);

您刚刚破坏了应用程序的安全性。

是的,Tomcat 以 root 身份运行。如果我执行 id 我也是 root 。

立即解决此问题!

现在谈谈这个问题。你不应该让 Tomcat 执行任何东西,你需要把它推迟到一个单独的进程,无论是一个 shell 脚本还是另一个 Java 程序。这也应该消除(我希望)对运行 Tomcat 的 root 的依赖。应该可以作为无法正常登录系统的非特权用户执行此命令。您可以通过配置/etc/fstab并为同一用户提供执行此操作的权限来执行此操作。从纯粹的安全 POV 来看,挂载的进程不应归 tomcat 用户所有。Tomcat 用户也不应该是 root。回顾一下:
1)停止以 root 身份运行 Tomcat
2)在 Tomcat 上下文之外创建一个单独的进程来运行这个挂载
3)创建一个tomcat用户,这个用户应该不能登录系统,也不能是特权用户(admin,超级用户等)
4)创建一个进程用户,这个用户应该完全配置为tomcat用户
5)编辑/etc/fstab为进程用户提供正确安装所需的权限。

于 2012-09-22T22:00:48.473 回答
6

使用Runtime.exec. 更好的选择是使用ProcessBuilder, 并自己拆分参数,而不是依赖 Java 为您拆分它们(它非常天真)。

ProcessBuilder pb = new ProcessBuilder("/bin/mount", "-o", "loop", /*...*/);
pb.redirectErrorStream(true); // equivalent of 2>&1
Process p = pb.start();

你说你在 RHEL 上,所以你有 selinux 活动吗?检查您的日志,看看这是否是阻止您的原因(我认为您正在寻找的是 audit.log,我使用 selinux 已经有几年了)。如果这确实是问题所在,那么您可能应该询问超级用户或服务器故障而不是 SO...

于 2012-09-21T21:26:33.243 回答
1

我不确定这是否是您遇到的问题,但是当使用 Runtime.exec() 而不读取关联的输出缓冲区时,我看到了问题。你可以在这里找到详细的解释和潜在的解决方案。读取输出和错误流还可以帮助您了解运行命令时操作系统级别发生的情况。

于 2012-09-21T20:23:58.787 回答
1

我最近不得不从 Swing 应用程序中执行类似的操作。

您可能可以使用 ProcessBuilder 来完成它,就像 Ian 的回答一样,但我发现一旦事情开始变得复杂,编写一个执行您想要的 shell 脚本会更容易,使您能够传递尽可能少的参数可能的。然后使用 ProcessBuilder 调用 shell 脚本。

如果您调用的任何内容都超过了真正的最小输出,那么您还必须读取输出和错误流,以防止在输出缓冲区填满时进程阻塞,因为您似乎已经在这样做了。

于 2012-09-22T01:19:03.587 回答
1

我使用sudo -Sbefore 命令和 tomcat7 用户:tomcat7 ALL=(ALL) NOPASSWD:ALL

于 2017-11-09T13:48:23.980 回答