Skip to content

Commit

Permalink
Include Windows OS in Bootstrap initializeNatives() check for definit…
Browse files Browse the repository at this point in the history
…elyRunningAsRoot() (#4656)

* Bump jna from 5.11.0 to 5.12.1

Signed-off-by: Daniel Widdis <[email protected]>

* Include Windows OS in check for definitelyRunningAsRoot()

Signed-off-by: Daniel Widdis <[email protected]>

* Combine try/catch blocks

Signed-off-by: Daniel Widdis <[email protected]>

* Someone sniped my PR number between predicting and pushing

Signed-off-by: Daniel Widdis <[email protected]>

* Update SHAs

Signed-off-by: Daniel Widdis <[email protected]>

Signed-off-by: Daniel Widdis <[email protected]>
  • Loading branch information
dbwiddis authored Oct 5, 2022
1 parent e189179 commit 3941226
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,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 ([#4656](https://github.com/opensearch-project/OpenSearch/pull/4656))

### Changed

Expand All @@ -64,6 +65,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() ([#4656](https://github.com/opensearch-project/OpenSearch/pull/4656))
- Add APIs (GET/PUT) to decommission awareness attribute ([#4261](https://github.com/opensearch-project/OpenSearch/pull/4261))
- Improve Gradle pre-commit checks to pre-empt Jenkins build ([#4660](https://github.com/opensearch-project/OpenSearch/pull/4660))
- Update to Apache Lucene 9.4.0 ([#4661](https://github.com/opensearch-project/OpenSearch/pull/4661))
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ dependencies {
api 'com.netflix.nebula:gradle-info-plugin:11.3.3'
api 'org.apache.rat:apache-rat:0.13'
api 'commons-io:commons-io:2.7'
api "net.java.dev.jna:jna:5.11.0"
api "net.java.dev.jna:jna:5.12.1"
api 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2'
api 'org.jdom:jdom2:2.0.6.1'
api 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10'
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/version.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ slf4j = 1.7.36
asm = 9.3

# when updating the JNA version, also update the version in buildSrc/build.gradle
jna = 5.5.0
jna = 5.12.1

netty = 4.1.79.Final
joda = 2.10.13
Expand Down
1 change: 1 addition & 0 deletions server/licenses/jna-5.12.1.jar.sha1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b1e93a735caea94f503e95e6fe79bf9cdc1e985d
1 change: 0 additions & 1 deletion server/licenses/jna-5.5.0.jar.sha1

This file was deleted.

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");
}
}
}
44 changes: 40 additions & 4 deletions 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 @@ -185,13 +190,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
}
try {
if (Constants.WINDOWS) {
JNAKernel32Library kernel32 = JNAKernel32Library.getInstance();
JNAAdvapi32Library advapi32 = JNAAdvapi32Library.getInstance();

// 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).
Pointer 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());
}
}
// For unix-based systems, check 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
// this will have already been logged by Native Library, no need to repeat it
return false;
}
}
Expand Down

0 comments on commit 3941226

Please sign in to comment.