Details
-
Bug
-
Resolution: Fixed
-
P4
-
8, 11, 17, 18
-
b20
-
generic
-
generic
-
Verified
Description
ADDITIONAL SYSTEM INFORMATION :
The tests were run inside the openjdk:17-jdk docker image to easily supply the nameless user.
The docker daemon was running on an Ubuntu 21.04 instance (based on the Linux 5.11.0-37-generic kernel) under a x86-64 architecture.
A DESCRIPTION OF THE PROBLEM :
The 'com.sun.security.auth.module.UnixSystem' class fails to correctly provider a users uid, gid or groups if the username of that user cannot be found.
This issue, while uncommon on servers or desktop setups, is found mostly when running java inside a container (e.g. docker), as these may be configured with an user id that was not created prior to prevent any form of writing inside the container.
An example of this on the docker platform would be `docker run --rm -it --user 999:999 openjdk:17-jdk bash`.
--Potential causes/Solutions--
Unix.c (https://github.com/openjdk/jdk/blob/master/src/jdk.security.auth/unix/native/libjaas/Unix.c#L99) presumably jumps to 'cleanUpAndReturn' early if no username could be found for the current user uid, skipping the uid, gid and group assignments. As the effective uid and gid are already known they should, at least in my mind, still be assigned to the UnixSystem fields.
--Context--
This issue was found while attempting to implement a root user detection for https://github.com/PaperMC/Paper. As the UnixSystem utility falls back to uid 0 in the case of a missing name, users without a username were incorrectly flagged as the root user.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
As it is easier to create this inside a docker container, I'll provide the steps required for this setup.
By accessing a container with a uid/gid that do not exist/have no permission, all files must be mounted in as the user will not have any write permissions.
1) Create a small sample application on the docker host ( such as https://gist.github.com/lynxplay/52f836dd53b8885c4d4d58fb21189d03 )
2) Run a docker container with a user that is not defined in the image and mount the sample application created in step 1 into it (e.g. 'docker run --rm -it --user 998:998 -v "/path/to/my/app:/path/inside/container" openjdk:17-jdk bash')
3) Execute the sample application (through `java -jar sample.jar` or `java Sample.java`)
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect the username to be null, as the user that started the process does not have a username, yet I expect the uid, gid and groups to be correctly set.
ACTUAL -
The example application will show a uid/gid of 0 and a null groups array.
---------- BEGIN SOURCE ----------
public class UnixSystemNameless {
public static void main(String[] args) {
final var unixSystem = new com.sun.security.auth.module.UnixSystem();
System.out.printf("username: %s%n", unixSystem.getUsername());
System.out.printf("uid: %d%n", unixSystem.getUid());
System.out.printf("gid: %d%n", unixSystem.getGid());
System.out.printf("groups: %s%n", java.util.Arrays.toString(unixSystem.getGroups()));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
A current temporary workout is the usage of the `id` binary available on most linux based distributions which may be called using a plain java process and the `-u` parameter to fetch the current `uid` which is enough for validating if the process is run by the root user.
FREQUENCY : always
The tests were run inside the openjdk:17-jdk docker image to easily supply the nameless user.
The docker daemon was running on an Ubuntu 21.04 instance (based on the Linux 5.11.0-37-generic kernel) under a x86-64 architecture.
A DESCRIPTION OF THE PROBLEM :
The 'com.sun.security.auth.module.UnixSystem' class fails to correctly provider a users uid, gid or groups if the username of that user cannot be found.
This issue, while uncommon on servers or desktop setups, is found mostly when running java inside a container (e.g. docker), as these may be configured with an user id that was not created prior to prevent any form of writing inside the container.
An example of this on the docker platform would be `docker run --rm -it --user 999:999 openjdk:17-jdk bash`.
--Potential causes/Solutions--
Unix.c (https://github.com/openjdk/jdk/blob/master/src/jdk.security.auth/unix/native/libjaas/Unix.c#L99) presumably jumps to 'cleanUpAndReturn' early if no username could be found for the current user uid, skipping the uid, gid and group assignments. As the effective uid and gid are already known they should, at least in my mind, still be assigned to the UnixSystem fields.
--Context--
This issue was found while attempting to implement a root user detection for https://github.com/PaperMC/Paper. As the UnixSystem utility falls back to uid 0 in the case of a missing name, users without a username were incorrectly flagged as the root user.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
As it is easier to create this inside a docker container, I'll provide the steps required for this setup.
By accessing a container with a uid/gid that do not exist/have no permission, all files must be mounted in as the user will not have any write permissions.
1) Create a small sample application on the docker host ( such as https://gist.github.com/lynxplay/52f836dd53b8885c4d4d58fb21189d03 )
2) Run a docker container with a user that is not defined in the image and mount the sample application created in step 1 into it (e.g. 'docker run --rm -it --user 998:998 -v "/path/to/my/app:/path/inside/container" openjdk:17-jdk bash')
3) Execute the sample application (through `java -jar sample.jar` or `java Sample.java`)
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect the username to be null, as the user that started the process does not have a username, yet I expect the uid, gid and groups to be correctly set.
ACTUAL -
The example application will show a uid/gid of 0 and a null groups array.
---------- BEGIN SOURCE ----------
public class UnixSystemNameless {
public static void main(String[] args) {
final var unixSystem = new com.sun.security.auth.module.UnixSystem();
System.out.printf("username: %s%n", unixSystem.getUsername());
System.out.printf("uid: %d%n", unixSystem.getUid());
System.out.printf("gid: %d%n", unixSystem.getGid());
System.out.printf("groups: %s%n", java.util.Arrays.toString(unixSystem.getGroups()));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
A current temporary workout is the usage of the `id` binary available on most linux based distributions which may be called using a plain java process and the `-u` parameter to fetch the current `uid` which is enough for validating if the process is run by the root user.
FREQUENCY : always