Skip to content

Commit

Permalink
Include Windows OS in check for definitelyRunningAsRoot()
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Widdis <widdis@gmail.com>
  • Loading branch information
dbwiddis committed Sep 30, 2022
1 parent 45f999e commit 50cd0be
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Bumps `reactor-core` from 3.4.18 to 3.4.23 ([#4548](https://github.com/opensearch-project/OpenSearch/pull/4548))
- Bumps `jempbox` from 1.8.16 to 1.8.17 ([#4550](https://github.com/opensearch-project/OpenSearch/pull/4550))
- Bumps `hadoop-hdfs` from 3.3.3 to 3.3.4 ([#4644](https://github.com/opensearch-project/OpenSearch/pull/4644))
- Bumps `jna` from 5.11.0 to 5.12.1 ([#4655](https://github.com/opensearch-project/OpenSearch/pull/4655))

### Changed
- Dependency updates (httpcore, mockito, slf4j, httpasyncclient, commons-codec) ([#4308](https://github.com/opensearch-project/OpenSearch/pull/4308))
Expand All @@ -55,6 +56,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Further simplification of the ZIP publication implementation ([#4360](https://github.com/opensearch-project/OpenSearch/pull/4360))
- Relax visibility of the HTTP_CHANNEL_KEY and HTTP_SERVER_CHANNEL_KEY to make it possible for the plugins to access associated Netty4HttpChannel / Netty4HttpServerChannel instance ([#4638](https://github.com/opensearch-project/OpenSearch/pull/4638))
- Load the deprecated master role in a dedicated method instead of in setAdditionalRoles() ([#4582](https://github.com/opensearch-project/OpenSearch/pull/4582))
- Include Windows OS in Bootstrap initializeNatives() check for definitelyRunningAsRoot() ([#4655](https://github.com/opensearch-project/OpenSearch/pull/4655))

### Deprecated

Expand Down
124 changes: 124 additions & 0 deletions server/src/main/java/org/opensearch/bootstrap/JNAAdvapi32Library.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.bootstrap;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.Structure;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.util.Constants;

import java.util.List;

/**
* Library for Windows/Advapi32
*
* @opensearch.internal
*/
final class JNAAdvapi32Library {

private static final Logger logger = LogManager.getLogger(JNAAdvapi32Library.class);

private static final class Holder {
private static final JNAAdvapi32Library instance = new JNAAdvapi32Library();
}

private JNAAdvapi32Library() {
if (Constants.WINDOWS) {
try {
Native.register("advapi32");
logger.debug("windows/Advapi32 library loaded");
} catch (NoClassDefFoundError e) {
logger.warn("JNA not found. native methods and handlers will be disabled.");
} catch (UnsatisfiedLinkError e) {
logger.warn("unable to link Windows/Advapi32 library. native methods and handlers will be disabled.");
}
}
}

static JNAAdvapi32Library getInstance() {
return Holder.instance;
}

/**
* Access right required to query an access token.
* Used by {@link #OpenProcessToken(Pointer, int, PointerByReference)}.
*
* https://learn.microsoft.com/en-us/windows/win32/secauthz/access-rights-for-access-token-objects
*/
public static final int TOKEN_QUERY = 0x0008;

/**
* TOKEN_INFORMATION_CLASS enumeration value that specifies the type of information being assigned to or retrieved from an access token.
* Used by {@link #GetTokenInformation(Pointer, int, Structure, int, IntByReference)}.
*
* https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-token_information_class
*/
public static final int TOKEN_ELEVATION = 0x14;

/**
* Native call to the Advapi32 API to open the access token associated with a process.
*
* @param processHandle Handle to the process whose access token is opened.
* The process must have the PROCESS_QUERY_INFORMATION access permission.
* @param desiredAccess Specifies an access mask that specifies the requested types of access to the access token.
* These requested access types are compared with the discretionary access control list (DACL) of the token to determine which accesses are granted or denied.
* @param tokenHandle Pointer to a handle that identifies the newly opened access token when the function returns.
* @return If the function succeeds, the return value is true.
* If the function fails, the return value is false.
* To get extended error information, call GetLastError.
*/
native boolean OpenProcessToken(Pointer processHandle, int desiredAccess, PointerByReference tokenHandle);

/**
* Retrieves a specified type of information about an access token.
* The calling process must have appropriate access rights to obtain the information.
*
* @param tokenHandle Handle to an access token from which information is retrieved.
* If TokenInformationClass specifies TokenSource, the handle must have TOKEN_QUERY_SOURCE access.
* For all other TokenInformationClass values, the handle must have TOKEN_QUERY access.
* @param tokenInformationClass Specifies a value from the TOKEN_INFORMATION_CLASS enumerated type to identify the type of information the function retrieves.
* @param tokenInformation Pointer to a buffer the function fills with the requested information.
* The structure put into this buffer depends upon the type of information specified by the TokenInformationClass parameter.
* @param tokenInformationLength Specifies the size, in bytes, of the buffer pointed to by the TokenInformation parameter.
* If TokenInformation is NULL, this parameter must be zero.
* @param returnLength Pointer to a variable that receives the number of bytes needed for the buffer pointed to by the TokenInformation parameter.
* If this value is larger than the value specified in the TokenInformationLength parameter, the function fails and stores no data in the buffer.
* @return If the function succeeds, the return value is true.
* If the function fails, the return value is zero.
* To get extended error information, call GetLastError.
*/
native boolean GetTokenInformation(
Pointer tokenHandle,
int tokenInformationClass,
Structure tokenInformation,
int tokenInformationLength,
IntByReference returnLength
);

/**
* The TOKEN_ELEVATION structure indicates whether a token has elevated privileges.
*
* https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_elevation
*/
public static class TokenElevation extends Structure {
/**
* A nonzero value if the token has elevated privileges; otherwise, a zero value.
*/
public int TokenIsElevated;

@Override
protected List<String> getFieldOrder() {
return List.of("TokenIsElevated");
}
}
}
42 changes: 41 additions & 1 deletion server/src/main/java/org/opensearch/bootstrap/JNANatives.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,19 @@
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.util.Constants;
import org.opensearch.bootstrap.JNAAdvapi32Library.TokenElevation;
import org.opensearch.monitor.jvm.JvmInfo;

import java.nio.file.Path;

import static org.opensearch.bootstrap.JNAAdvapi32Library.TOKEN_ELEVATION;
import static org.opensearch.bootstrap.JNAAdvapi32Library.TOKEN_QUERY;
import static org.opensearch.bootstrap.JNAKernel32Library.SizeT;

/**
Expand Down Expand Up @@ -186,9 +191,44 @@ static String rlimitToString(long value) {
/** Returns true if user is root, false if not, or if we don't know */
static boolean definitelyRunningAsRoot() {
if (Constants.WINDOWS) {
return false; // don't know
JNAKernel32Library kernel32 = JNAKernel32Library.getInstance();
JNAAdvapi32Library advapi32 = JNAAdvapi32Library.getInstance();
Pointer process = null;
try {
// Fetch a pseudo handle for the current process.
// The pseudo handle need not be closed when it is no longer needed (calling CloseHandle is a no-op).
process = kernel32.GetCurrentProcess();
PointerByReference hToken = new PointerByReference();
// Fetch the process token for the current process, for which we know we have the access rights
if (!advapi32.OpenProcessToken(process, TOKEN_QUERY, hToken)) {
logger.warn(
"Unable to open the Process Token for the current process [" + JNACLibrary.strerror(Native.getLastError()) + "]"
);
return false;
}
// We have successfully opened the token. Ensure it gets closed after we use it.
try {
TokenElevation elevation = new TokenElevation();
IntByReference returnLength = new IntByReference();
if (!advapi32.GetTokenInformation(hToken.getValue(), TOKEN_ELEVATION, elevation, elevation.size(), returnLength)) {
logger.warn(
"Unable to get TokenElevation information for the current process ["
+ JNACLibrary.strerror(Native.getLastError())
+ "]"
);
return false;
}
// Nonzero value means elevated privileges
return elevation.TokenIsElevated > 0;
} finally {
kernel32.CloseHandle(hToken.getValue());
}
} catch (final UnsatisfiedLinkError e) {
return false; // don't know
}
}
try {
// effective user ID of process
return JNACLibrary.geteuid() == 0;
} catch (UnsatisfiedLinkError e) {
// this will have already been logged by Kernel32Library, no need to repeat it
Expand Down

0 comments on commit 50cd0be

Please sign in to comment.