United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4052517 (process) Runtime.exec won't execute programs belonging to other groups on Unix
JDK-4052517 : (process) Runtime.exec won't execute programs belonging to other groups on Unix

Details
Type:
Bug
Submit Date:
1997-05-16
Status:
Resolved
Updated Date:
2006-05-08
Project Name:
JDK
Resolved Date:
2006-04-14
Component:
core-libs
OS:
solaris_9,solaris_8,linux_redhat_3.0,solaris_2.5.1,linux
Sub-Component:
java.lang
CPU:
itanium,x86,sparc
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.1.1,1.4.1,1.4.2,1.4.2_05,1.4.2_19
Fixed Versions:

Related Reports
Backport:
Backport:
Duplicate:
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:

Sub Tasks

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

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
                                     
2003-04-14
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>.
                                     
2004-09-11
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.
                                     
2006-04-10



Hardware and Software, Engineered to Work Together