Skip to content

Commit

Permalink
J9 Allow attachment as root (#1631)
Browse files Browse the repository at this point in the history
* Allow attachment as root

* Add javadoc for getUserId
  • Loading branch information
FelixMarxIBM authored May 3, 2024
1 parent 01ed75b commit 156ba85
Showing 1 changed file with 66 additions and 36 deletions.
102 changes: 66 additions & 36 deletions byte-buddy-agent/src/main/java/net/bytebuddy/agent/VirtualMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -1660,49 +1660,23 @@ protected ForOpenJ9(Socket socket) {
* @throws IOException If an IO exception occurs during establishing the connection.
*/
public static VirtualMachine attach(String processId) throws IOException {
return attach(processId, false);
}

/**
* Attaches to the supplied process id using the default JNA implementation.
*
* @param processId The process id.
* @param ignoreUser {@code true} if VM processes that are owned by different users should be considered.
* @return A suitable virtual machine implementation.
* @throws IOException If an IO exception occurs during establishing the connection.
*/
public static VirtualMachine attach(String processId, boolean ignoreUser) throws IOException {
return attach(processId, 5000, Platform.isWindows()
? new Dispatcher.ForJnaWindowsEnvironment()
: new Dispatcher.ForJnaPosixEnvironment(15, 100, TimeUnit.MILLISECONDS));
}

/**
* Attaches to the supplied process id. This method will not consider attaching to VMs owned by
* different users than the current user.
*
* @param processId The process id.
* @param timeout The timeout for establishing the socket connection.
* @param dispatcher The connector to use to communicate with the target VM.
* @return A suitable virtual machine implementation.
* @throws IOException If an IO exception occurs during establishing the connection.
*/
public static VirtualMachine attach(String processId, int timeout, Dispatcher dispatcher) throws IOException {
return attach(processId, timeout, dispatcher, false);
}

/**
* Attaches to the supplied process id.
*
* @param processId The process id.
* @param timeout The timeout for establishing the socket connection.
* @param dispatcher The connector to use to communicate with the target VM.
* @param ignoreUser {@code true} if VM processes that are owned by different users should be considered.
* @return A suitable virtual machine implementation.
* @throws IOException If an IO exception occurs during establishing the connection.
*/
public static VirtualMachine attach(String processId, int timeout, Dispatcher dispatcher, boolean ignoreUser) throws IOException {
public static VirtualMachine attach(String processId, int timeout, Dispatcher dispatcher) throws IOException {
File directory = new File(System.getProperty(IBM_TEMPORARY_FOLDER, dispatcher.getTemporaryFolder(processId)), ".com_ibm_tools_attach");
long userId = dispatcher.userId();
RandomAccessFile attachLock = new RandomAccessFile(new File(directory, "_attachlock"), "rw");
try {
FileLock attachLockLock = attachLock.getChannel().lock();
Expand All @@ -1716,10 +1690,9 @@ public static VirtualMachine attach(String processId, int timeout, Dispatcher di
if (vmFolder == null) {
throw new IllegalStateException("No descriptor files found in " + directory);
}
long userId = dispatcher.userId();
virtualMachines = new ArrayList<Properties>();
for (File aVmFolder : vmFolder) {
if (aVmFolder.isDirectory() && (ignoreUser || dispatcher.getOwnerIdOf(aVmFolder) == userId)) {
if (aVmFolder.isDirectory() && isFileOwnedByUid(dispatcher, aVmFolder, userId)) {
File attachInfo = new File(aVmFolder, "attachInfo");
if (attachInfo.isFile()) {
Properties virtualMachine = new Properties();
Expand All @@ -1730,12 +1703,7 @@ public static VirtualMachine attach(String processId, int timeout, Dispatcher di
inputStream.close();
}
int targetProcessId = Integer.parseInt(virtualMachine.getProperty("processId"));
long targetUserId;
try {
targetUserId = Long.parseLong(virtualMachine.getProperty("userUid"));
} catch (NumberFormatException ignored) {
targetUserId = 0L;
}
long targetUserId = getUserId(virtualMachine);
if (userId != 0L && targetUserId == 0L) {
targetUserId = dispatcher.getOwnerIdOf(attachInfo);
}
Expand Down Expand Up @@ -1782,10 +1750,14 @@ public static VirtualMachine attach(String processId, int timeout, Dispatcher di
key = Long.toHexString(SECURE_RANDOM.nextLong());
}
File reply = new File(receiver, "replyInfo");
long targetUserId = getUserId(target);
try {
if (reply.createNewFile()) {
dispatcher.setPermissions(reply, 0600);
}
if (0 == userId && 0 != targetUserId) {
dispatcher.chownFileToTargetUid(reply, targetUserId);
}
FileOutputStream outputStream = new FileOutputStream(reply);
try {
outputStream.write(key.getBytes("UTF-8"));
Expand Down Expand Up @@ -1867,6 +1839,31 @@ public static VirtualMachine attach(String processId, int timeout, Dispatcher di
}
}

/**
* Returns the userUid present in the virtualMachine properties file
* @param virtualMachine Properties of the J9 attachInfo file
* @return the userUid if it can be parsed, <code>0L</code> otherwise.
*/
private static long getUserId(Properties virtualMachine) {
long targetUserId;
try {
targetUserId = Long.parseLong(virtualMachine.getProperty("userUid"));
} catch (NumberFormatException ignored) {
targetUserId = 0L;
}
return targetUserId;
}

/**
* Check if the file is owned by the UID. Note that UID 0 "owns" all files.
* @param aVmFolder File or directory
* @param userId user UID.
* @return true if the uid owns the file or uid == 0.
*/
private static boolean isFileOwnedByUid(Dispatcher dispatcher, File aVmFolder, long userId) {
return 0 == userId || dispatcher.getOwnerIdOf(aVmFolder) == userId;
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -2077,6 +2074,13 @@ public interface Dispatcher {
*/
void decrementSemaphore(File directory, String name, boolean global, int count);

/**
* change the ownership of a file. Can be called only if this process is owned by root.
* @param path path to the file
* @param targetUserId effective userid
*/
void chownFileToTargetUid(File path, long targetUserId);

/**
* A connector implementation for a POSIX environment using JNA.
*/
Expand Down Expand Up @@ -2214,6 +2218,14 @@ public void decrementSemaphore(File directory, String name, boolean global, int
notifySemaphore(directory, name, count, (short) -1, (short) (PosixLibrary.SEM_UNDO | PosixLibrary.IPC_NOWAIT), true);
}

/**
* {@inheritDoc}
*/
@Override
public void chownFileToTargetUid(File file, long targetUserId) {
library.chown(file.getAbsolutePath(), targetUserId);
}

/**
* Notifies a POSIX semaphore.
*
Expand Down Expand Up @@ -2319,6 +2331,16 @@ protected interface PosixLibrary extends Library {
*/
int chmod(String path, int mode) throws LastErrorException;

/**
* Runs the {@code chown} command.
*
* @param path The file path.
* @param uid The userid to set.
* @return The return code.
* @throws LastErrorException If an error occurred.
*/
int chown(String path, long uid) throws LastErrorException;

/**
* Runs the {@code ftok} command.
*
Expand Down Expand Up @@ -2502,6 +2524,14 @@ public void decrementSemaphore(File directory, String name, boolean global, int
}
}

/**
* {@inheritDoc}
*/
@Override
public void chownFileToTargetUid(File path, long targetUserId) {
/* do nothing */
}

/**
* Opens a semaphore for signaling another process that an attachment is performed.
*
Expand Down

0 comments on commit 156ba85

Please sign in to comment.