无法通过调用 JNI 在 java 中设置 euid
Fail to seteuid in java by calling JNI
我的应用程序需要 运行 作为 none-root 用户,但需要切换到其他用户才能执行一些命令。
我试过:
写一个JNI,
JNIEXPORT void JNICALL Java_SetUIDJNI_setuid(JNIEnv *env, jobject thisObj,jstring uname) {
const char *name = jstringTostring(env,uname);
int pid;
struct passwd *p;
show_ids();
if ((p = getpwnam(name)) == NULL) {
perror(name);
exit(EXIT_FAILURE);
}
pid = (int) p->pw_uid;
printf("pid=%d\n",pid);
if (seteuid (pid) < 0) {
perror ("setuid");
exit (EXIT_FAILURE);
}
show_ids();
}
将其构建为 root 和 chmod u+s
-rwsr-xr-x 1 root root 76155 Aug 7 16:56 libsetuid.so*
在java
中调用
api = new SetUIDJNI(); // invoke the native method
api.setuid("slurm");
但是如果运行它作为none-root,它不起作用
/opt/jdk1.8/jre/bin/java -Djava.library.path=../jni HelloJNI
The real user ID is: 1000
The effective user ID is :1000 <= which expected is 0
setuid: Operation not permitted
但是如果 运行ner 是 root
The real user ID is: 0
The effective user ID is :0
pid=1002The real user ID is: 0
The effective user ID is :1002
这里有什么问题吗?
更新
修改JNI部分为可执行文件c
void show_ids (void)
{
printf ("The real user ID is: %d\n", getuid());
printf ("The effective user ID is :%d\n", geteuid());
}
int main(void)
{
show_ids();
if (seteuid (1002) < 0) {
perror ("setuid");
exit (EXIT_FAILURE);
}
show_ids();
return (0);
}
将其构建为 root 和 运行 chmod u+s
-rwsr-xr-x 1 root root 8814 Aug 9 11:44 a.out*
运行 它作为普通用户并且工作
./a.out
The real user ID is: 1000
The effective user ID is :0
The real user ID is: 1000
The effective user ID is :1002
seteuid
无法从 JNI 为您工作的原因是 JVM 进程的有效用户 ID 不是 0(root)。
您显然试图通过在您的本机库上设置 "setuid" 位来创建有效的用户 ID。那行不通的。同样,将 JAR 文件(或 class 文件)设置为 setuid 将不起作用。 setuid 位仅对可执行文件有意义;即 OS 本身 知道如何执行的文件。
那么我们如何为 Java 程序实现 "setuid root behavior"?
理论上,您可以将 /usr/bin/java
标记为 root 的 setuid。 不要那样做! 如果你那样做,你 运行 的每个 Java 程序都将 运行 为 root。那可就糟了。
理论上,您可以编写 shell 脚本来启动您的应用程序;例如
#!/bin/sh
java some.pkg.Main "$@"
并将脚本标记为 root 的 setuid。 不要那样做! Setuid shell 脚本存在安全风险。 (在某些版本的 Linux / UNIX 中,setuid 位无论如何都不被 shell 脚本使用。)
解决方案是用本机代码编写自定义 JVM 启动器,编译并 link 它,并使启动器可执行 setuid。请注意,必须 非常仔细地 编写启动程序,以防止有人破坏它。例如:
它应该忽略 CLASSPATH 环境变量,并且不应允许以任何其他方式提供 class路径。
不应将用户提供的JAR文件作为参数。
应该注意用户不能通过干扰 JAR 文件的路径来欺骗它进入 运行 错误的 Java 代码。
还有其他的……我没想到的!
事实上,运行 Java 应用程序作为特权用户可能更安全......并且根本不依赖 "setuid root"。
我的应用程序需要 运行 作为 none-root 用户,但需要切换到其他用户才能执行一些命令。
我试过:
写一个JNI,
JNIEXPORT void JNICALL Java_SetUIDJNI_setuid(JNIEnv *env, jobject thisObj,jstring uname) { const char *name = jstringTostring(env,uname); int pid; struct passwd *p; show_ids(); if ((p = getpwnam(name)) == NULL) { perror(name); exit(EXIT_FAILURE); } pid = (int) p->pw_uid; printf("pid=%d\n",pid); if (seteuid (pid) < 0) { perror ("setuid"); exit (EXIT_FAILURE); } show_ids(); }
将其构建为 root 和 chmod u+s
-rwsr-xr-x 1 root root 76155 Aug 7 16:56 libsetuid.so*
在java
中调用api = new SetUIDJNI(); // invoke the native method api.setuid("slurm");
但是如果运行它作为none-root,它不起作用
/opt/jdk1.8/jre/bin/java -Djava.library.path=../jni HelloJNI
The real user ID is: 1000
The effective user ID is :1000 <= which expected is 0
setuid: Operation not permitted
但是如果 运行ner 是 root
The real user ID is: 0
The effective user ID is :0
pid=1002The real user ID is: 0
The effective user ID is :1002
这里有什么问题吗?
更新
修改JNI部分为可执行文件c
void show_ids (void)
{
printf ("The real user ID is: %d\n", getuid());
printf ("The effective user ID is :%d\n", geteuid());
}
int main(void)
{
show_ids();
if (seteuid (1002) < 0) {
perror ("setuid");
exit (EXIT_FAILURE);
}
show_ids();
return (0);
}
将其构建为 root 和 运行 chmod u+s
-rwsr-xr-x 1 root root 8814 Aug 9 11:44 a.out*
运行 它作为普通用户并且工作
./a.out
The real user ID is: 1000
The effective user ID is :0
The real user ID is: 1000
The effective user ID is :1002
seteuid
无法从 JNI 为您工作的原因是 JVM 进程的有效用户 ID 不是 0(root)。
您显然试图通过在您的本机库上设置 "setuid" 位来创建有效的用户 ID。那行不通的。同样,将 JAR 文件(或 class 文件)设置为 setuid 将不起作用。 setuid 位仅对可执行文件有意义;即 OS 本身 知道如何执行的文件。
那么我们如何为 Java 程序实现 "setuid root behavior"?
理论上,您可以将
/usr/bin/java
标记为 root 的 setuid。 不要那样做! 如果你那样做,你 运行 的每个 Java 程序都将 运行 为 root。那可就糟了。理论上,您可以编写 shell 脚本来启动您的应用程序;例如
#!/bin/sh java some.pkg.Main "$@"
并将脚本标记为 root 的 setuid。 不要那样做! Setuid shell 脚本存在安全风险。 (在某些版本的 Linux / UNIX 中,setuid 位无论如何都不被 shell 脚本使用。)
解决方案是用本机代码编写自定义 JVM 启动器,编译并 link 它,并使启动器可执行 setuid。请注意,必须 非常仔细地 编写启动程序,以防止有人破坏它。例如:
它应该忽略 CLASSPATH 环境变量,并且不应允许以任何其他方式提供 class路径。
不应将用户提供的JAR文件作为参数。
应该注意用户不能通过干扰 JAR 文件的路径来欺骗它进入 运行 错误的 Java 代码。
还有其他的……我没想到的!
事实上,运行 Java 应用程序作为特权用户可能更安全......并且根本不依赖 "setuid root"。