JDK-4052517 : (process) Runtime.exec won't execute programs belonging to other groups on Unix
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.1.1,1.4.1,1.4.2,1.4.2_05,1.4.2_19
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS:
    linux,linux_redhat_3.0,solaris_2.5.1,solaris_8,solaris_9 linux,linux_redhat_3.0,solaris_2.5.1,solaris_8,solaris_9
  • CPU: x86,sparc,itanium
  • Submitted: 1997-05-16
  • Updated: 2006-05-08
  • Resolved: 2006-04-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6
1.4.2_14Fixed 6 b81Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
User gets IOException when attempting to invoke a shell script from
Java. User can invoke the shell script from the Unix command prompt.


Believed cause:

User's primary group is not the same as the group of the shell script,
even though user is a member of that group.


Further info:

This problem occurs on Solaris 2.5.1 sparc and x86 hardware.


------------------------------------------------------------------------

$ ls -lagL ./test.sh 
-rwxrwx---   1 root     t3proj         52 May 12 11:43 ./test.sh
$ ./test.sh 
        id
uid=101(henryg) gid=10(staff)
        groups
staff sysadmin osecomms oselibs ship terse termsim ada bnalib bnautils bpoll t27 uts consult t3proj
 
        echo executing $0
executing ./test.sh
$ java exec test.sh
IOException: test.sh: cannot execute
$ uname -a
SunOS thredbo 5.5.1 Generic_103640-03 sun4m sparc SUNW,SPARCstation-10,SX
$

------------------------------------------------------------------------

Enclosures:

exec.class	the class file
exec.java	the java source file
test.sh		the shell script


Name: nt126004			Date: 06/28/2002


FULL PRODUCT VERSION :
Java(TM) 2 SDK, Standard Edition
Version 1.4.1 Beta


FULL OPERATING SYSTEM VERSION :
glibc-2.1.92-14
Linux 2.2.16-22smp i686
Red Hat Linux release 7.0 (Guinness)

A DESCRIPTION OF THE PROBLEM :
When a java program is launched by root, cannot execute
external program (using Java's runtime class) owned by
another user/group without other's executable permission.

On linux system, root must be able to execute any program
that has at least an executable permission and that belong
to any group or user.

It should be the same for a java program launched by root
that wants to execute an external program.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.
# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3
(sys),4(adm),6(disk),10(wheel)
# more TestRoot.java
public class TestRoot {
    public static void main(String[] args)
    {
	try
	{
		String cmd = args[0];
		Process p = Runtime.getRuntime().exec(cmd);
		p.waitFor();
	}
	catch (Throwable t)
		{
		t.printStackTrace();
	}
    }
}
# /usr/java/j2sdk1.4.1/bin/javac TestRoot.java
# ls -l /usr/bin/X11/xterm
-rwxr-xr-x    1 root     root       200724 Aug 30
2000 /usr/bin/X11/xterm
# /usr/java/j2sdk1.4.1/bin/java TestRoot /usr/bin/X11/xterm

2.
# chown user1:group1 /usr/bin/X11/xterm
# chmod o-x /usr/bin/X11/xterm
# ls -l /usr/bin/X11/xterm
-rwxr-xr--    1 user1  group1    200724 Aug 30
2000 /usr/bin/X11/xterm
# xterm

3.
# /usr/java/j2sdk1.4.1/bin/java TestRoot /usr/bin/X11/xterm
java.io.IOException:
java.io.IOException: /usr/bin/X11/xterm: cannot execute
	at java.lang.UNIXProcess.<init>(UNIXProcess.java:143)
	at java.lang.Runtime.execInternal(Native Method)
	at java.lang.Runtime.exec(Runtime.java:566)
	at java.lang.Runtime.exec(Runtime.java:428)
	at java.lang.Runtime.exec(Runtime.java:364)
	at java.lang.Runtime.exec(Runtime.java:326)
	at TestRoot.main(TestRoot.java:7)


EXPECTED VERSUS ACTUAL BEHAVIOR :
1. First step compiling a small java program that execute
any command. When executing /usr/bin/X11/xterm from java
program, an xterm appears (note that by default xterm has
execution permission for root)

2. Now we change the owner and permissions
on /usr/bin/X11/xterm so that it doesn't belongs to root or
root's group, and so that other's executable permission is
disabled. When executing xterm from the prompt, an xterm
appears

3. Now we try to execute /usr/bin/X11/xterm from the java
program, an IOException occurs and obviously the xterm
doesn't appear. We think that it should have worked.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.io.IOException: java.io.IOException: /usr/bin/X11/xterm: cannot execute
	at java.lang.UNIXProcess.<init>(UNIXProcess.java:143)
	at java.lang.Runtime.execInternal(Native Method)
	at java.lang.Runtime.exec(Runtime.java:566)
	at java.lang.Runtime.exec(Runtime.java:428)
	at java.lang.Runtime.exec(Runtime.java:364)
	at java.lang.Runtime.exec(Runtime.java:326)
	at TestRoot.main(TestRoot.java:7)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10
(wheel)
# more TestRoot.java
public class TestRoot {
    public static void main(String[] args)
    {
	try
	{
		String cmd = args[0];
		Process p = Runtime.getRuntime().exec(cmd);
		p.waitFor();
	}
	catch (Throwable t)
		{
		t.printStackTrace();
	}
    }
}
# /usr/java/j2sdk1.4.1/bin/javac TestRoot.java
# ls -l /usr/bin/X11/xterm
-rwxr-xr-x    1 root     root       200724 Aug 30 2000 /usr/bin/X11/xterm
# /usr/java/j2sdk1.4.1/bin/java TestRoot /usr/bin/X11/xterm
# chown user1:group1 /usr/bin/X11/xterm
# chmod o-x /usr/bin/X11/xterm
# ls -l /usr/bin/X11/xterm
-rwxr-xr--    1 user1  group1    200724 Aug 30  2000 /usr/bin/X11/xterm
# xterm
# /usr/java/j2sdk1.4.1/bin/java TestRoot /usr/bin/X11/xterm
java.io.IOException: java.io.IOException: /usr/bin/X11/xterm: cannot execute
	at java.lang.UNIXProcess.<init>(UNIXProcess.java:143)
	at java.lang.Runtime.execInternal(Native Method)
	at java.lang.Runtime.exec(Runtime.java:566)
	at java.lang.Runtime.exec(Runtime.java:428)
	at java.lang.Runtime.exec(Runtime.java:364)
	at java.lang.Runtime.exec(Runtime.java:326)
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
I don't have any workaround to provide. The only solution
is to set grants and ownership so that the "root" user can
launch the expected program as if it was a normal user.
(Review ID: 158634)
======================================================================

Comments
EVALUATION We finally fixed this bug the Right Way, by using a pipe to communicate failure (and the reason for failure) from the child process back to the parent. Success of child's exec can also be communicated back to the parent, by using the close-on-exec bit on the pipe. This fixes other bugs as well, including some not explicitly in the bug database, such as failure to properly respect Unix ACLs. This fix seems too risky for a backport. We should do something more conservative there.
10-04-2006

PUBLIC COMMENTS On Solaris, <code>Runtime.exec()</code> fails if the primary group id of the Java process doing the exec, and the group id of the executable being exec'ed, are not the same. Workaround is to rely only on primary group id based permissions, and refrain from depending on secondary group ids based permissions for executables that are being exec'ed with <code>Runtime.exec()</code>.
11-09-2004

EVALUATION Turns out that we make a check against the primary gid (in statExecutable) -- we are trying to pre-empt any exec() failures by doing permissions checks very early. A hack would be to check for other gid's that the java processes euid might be in. But a correct fix (as Tom Rodriguez points) out would be to setup a pipe through which it can be communicated to the java process that the exec failed -- that way we don't have to do any of the permission checks statExecutable can go away). Giving to Tom Rodriguez because he is very comfortable writing this kind of nasty stuff. anand.palaniswamy@Eng 1997-08-13 The only truly correct way to check whether an operation will succeed is to try it, and try to communicate the failure mode, as pointed out above. But this is much more work than using a better executable file access checking mechanism. In lieu of this completely correct method... Much better than checking the actual bits, which fails in the presence of multiple groups and ACLs, is to use the access(2) function, which is designed to test for access rights. return access (filename, X_OK) > 0 access(2) isn't quite right because it uses the real uid and gid, rather than the effective ones. It would be better if we had eaccess(2), but that isn't implemented on many platforms. The best short term fix is to use access in statExecutable() instead of fiddling with gids directly. ###@###.### 2003-04-14
14-04-2003