diff --git a/.github/workflows/X-Reusable-Build-Security-Agent.yml b/.github/workflows/X-Reusable-Build-Security-Agent.yml index 0d3779123..516344f99 100644 --- a/.github/workflows/X-Reusable-Build-Security-Agent.yml +++ b/.github/workflows/X-Reusable-Build-Security-Agent.yml @@ -61,7 +61,8 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - java-version: [ 8, 11, 17 ] + java-version: [ 8 ] +# java-version: [ 8, 11, 17 ] steps: - name: Checkout CSEC Repo diff --git a/Changelog.md b/Changelog.md index d796bf158..1cfb63cde 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,15 @@ Noteworthy changes to the agent are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.2.1] - 2024-4-19 +### Fixes +- [NR-259467](https://new-relic.atlassian.net/browse/NR-259467) Fix issue of nested event generation from CSEC's agent itself [PR-230](https://github.com/newrelic/csec-java-agent/pull/230) + +### Changes +- [NR-256459](https://new-relic.atlassian.net/browse/NR-256459) Exclude JAX RS 4.0.0-M2 version from Instrumentation [PR-231](https://github.com/newrelic/csec-java-agent/pull/231) +- [NR-256461](https://new-relic.atlassian.net/browse/NR-256461) Exclude mssql-jdbc version 12.7.0 from Instrumentation [PR-232](https://github.com/newrelic/csec-java-agent/pull/232) +- [NR-260369](https://new-relic.atlassian.net/browse/NR-260369) Dependency version bump of commons-compress:1.21 to commons-compress:1.26.0 + ## [1.2.0] - 2024-3-28 ### Changes - Json Version bump to 1.2.0 due to [NR-235776](https://new-relic.atlassian.net/browse/NR-235776) implementation. diff --git a/README.md b/README.md index 51e0ea935..3da04edb1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The IAST capability should only be used in pre-production environments and never ## **Installation** -This project is built and published as a dependency for use in [newrelic-java-agent](https://github.com/newrelic/newrelic-java-agent) only. Hence this can not be used directly. Typically, most users use the version auto-installed by the APM agent. You can see agent install instructions [here](https://github.com/newrelic/java-newrelic#installation-and-getting-started). +This project is built and published as a dependency for use in [newrelic-java-agent](https://github.com/newrelic/newrelic-java-agent) only. Hence this can not be used directly. Typically, most users use the version auto-installed by the APM agent. You can see agent install instructions [here](https://docs.newrelic.com/docs/iast/install/). ## **Supported Java Versions** - Java version 8 and above diff --git a/gradle.properties b/gradle.properties index 4fa7e073f..1515da4a9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # The agent version. -agentVersion=1.2.0 +agentVersion=1.2.1 jsonVersion=1.2.0 # Updated exposed NR APM API version. nrAPIVersion=8.4.0 diff --git a/instrumentation-security/jax-rs-3.0/build.gradle b/instrumentation-security/jax-rs-3.0/build.gradle index 34040fc01..6a2e0b44b 100644 --- a/instrumentation-security/jax-rs-3.0/build.gradle +++ b/instrumentation-security/jax-rs-3.0/build.gradle @@ -19,6 +19,7 @@ jar { verifyInstrumentation { passesOnly 'jakarta.ws.rs:jakarta.ws.rs-api:[3.0-M1,)' + excludeRegex '.*-M[0-9]+' } compileJava { diff --git a/instrumentation-security/jdbc-sqlserver/build.gradle b/instrumentation-security/jdbc-sqlserver/build.gradle index 43ed7a152..788da54f3 100644 --- a/instrumentation-security/jdbc-sqlserver/build.gradle +++ b/instrumentation-security/jdbc-sqlserver/build.gradle @@ -9,7 +9,7 @@ jar { } verifyInstrumentation { - passes("com.microsoft.sqlserver:mssql-jdbc:[0,)") + passes("com.microsoft.sqlserver:mssql-jdbc:[0,12.7.0)") excludeRegex(".*jre9.*") excludeRegex(".*jre1\\d.*") excludeRegex(".*preview.*") diff --git a/newrelic-security-agent/build.gradle b/newrelic-security-agent/build.gradle index e45a2d3ed..98504e505 100644 --- a/newrelic-security-agent/build.gradle +++ b/newrelic-security-agent/build.gradle @@ -68,7 +68,7 @@ dependencies { shadowIntoJar 'commons-io:commons-io:2.7' shadowIntoJar 'org.apache.commons:commons-text:1.10.0' shadowIntoJar 'commons-net:commons-net:3.9.0' - shadowIntoJar 'org.apache.commons:commons-compress:1.21' + shadowIntoJar 'org.apache.commons:commons-compress:1.26.0' shadowIntoJar 'com.squareup.okhttp3:okhttp:4.10.0' shadowIntoJar 'org.apache.commons:commons-collections4:4.4' shadowIntoJar 'org.unbescape:unbescape:1.1.6.RELEASE' diff --git a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java index 3b298e080..fb508054c 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/Agent.java @@ -10,6 +10,7 @@ import com.newrelic.agent.security.intcodeagent.filelogging.FileLoggerThreadPool; import com.newrelic.agent.security.intcodeagent.filelogging.LogFileHelper; import com.newrelic.agent.security.intcodeagent.utils.EncryptorUtils; +import com.newrelic.api.agent.security.instrumentation.helpers.*; import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.agent.security.intcodeagent.logging.HealthCheckScheduleThread; import com.newrelic.agent.security.intcodeagent.logging.IAgentConstants; @@ -22,10 +23,6 @@ import com.newrelic.agent.security.util.IUtilConstants; import com.newrelic.api.agent.NewRelic; import com.newrelic.api.agent.Transaction; -import com.newrelic.api.agent.security.instrumentation.helpers.GrpcHelper; -import com.newrelic.api.agent.security.instrumentation.helpers.AppServerInfoHelper; -import com.newrelic.api.agent.security.instrumentation.helpers.InstrumentedClass; -import com.newrelic.api.agent.security.instrumentation.helpers.LowSeverityHelper; import com.newrelic.api.agent.security.schema.*; import com.newrelic.api.agent.security.schema.operation.RXSSOperation; import com.newrelic.api.agent.security.schema.policy.AgentPolicy; @@ -249,60 +246,69 @@ private void deactivateSecurityServices(){ @Override public void registerOperation(AbstractOperation operation) { // added to fetch request/response in case of grpc requests - SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); - if (securityMetaData!=null && securityMetaData.getRequest().getIsGrpc()){ - securityMetaData.getRequest().setBody( - new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_REQUEST_DATA, List.class)))); - securityMetaData.getResponse().setResponseBody( - new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_RESPONSE_DATA, List.class)))); - } - // end + boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + if(lockAcquired) { + SecurityMetaData securityMetaData = NewRelicSecurity.getAgent().getSecurityMetaData(); + if (securityMetaData != null && securityMetaData.getRequest().getIsGrpc()) { + securityMetaData.getRequest().setBody( + new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_REQUEST_DATA, List.class)))); + securityMetaData.getResponse().setResponseBody( + new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_RESPONSE_DATA, List.class)))); + } + // end - if (operation == null || operation.isEmpty()) { - return; - } - String executionId = ExecutionIDGenerator.getExecutionId(); - operation.setExecutionId(executionId); - operation.setStartTime(Instant.now().toEpochMilli()); - if(securityMetaData!=null && securityMetaData.getFuzzRequestIdentifier().getK2Request()){ - logger.log(LogLevel.FINEST, String.format("New Event generation with id %s of type %s", operation.getExecutionId(), operation.getClass().getSimpleName()), Agent.class.getName()); - } - if (operation instanceof RXSSOperation) { - operation.setStackTrace(securityMetaData.getMetaData().getServiceTrace()); - } else { - StackTraceElement[] trace = Thread.currentThread().getStackTrace(); - operation.setStackTrace(Arrays.copyOfRange(trace, 2, trace.length)); - } + if (operation == null || operation.isEmpty()) { + return; + } + String executionId = ExecutionIDGenerator.getExecutionId(); + operation.setExecutionId(executionId); + operation.setStartTime(Instant.now().toEpochMilli()); + if (securityMetaData != null && securityMetaData.getFuzzRequestIdentifier().getK2Request()) { + logger.log(LogLevel.FINEST, String.format("New Event generation with id %s of type %s", operation.getExecutionId(), operation.getClass().getSimpleName()), Agent.class.getName()); + } + if (operation instanceof RXSSOperation) { + operation.setStackTrace(securityMetaData.getMetaData().getServiceTrace()); + } else { + StackTraceElement[] trace = Thread.currentThread().getStackTrace(); + operation.setStackTrace(Arrays.copyOfRange(trace, 2, trace.length)); + } - // added to fetch request/response in case of grpc requests - if (securityMetaData.getRequest().getIsGrpc()){ - securityMetaData.getRequest().setBody( - new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_REQUEST_DATA, List.class)))); - securityMetaData.getResponse().setResponseBody( - new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_RESPONSE_DATA, List.class)))); - } + // added to fetch request/response in case of grpc requests + if (securityMetaData.getRequest().getIsGrpc()) { + securityMetaData.getRequest().setBody( + new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_REQUEST_DATA, List.class)))); + securityMetaData.getResponse().setResponseBody( + new StringBuilder(JsonConverter.toJSON(securityMetaData.getCustomAttribute(GrpcHelper.NR_SEC_GRPC_RESPONSE_DATA, List.class)))); + } - if(checkIfNRGeneratedEvent(operation)) { - logger.log(LogLevel.FINEST, DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL + - JsonConverter.toJSON(operation), - Agent.class.getName()); - return; - } + if (checkIfNRGeneratedEvent(operation)) { + logger.log(LogLevel.FINEST, DROPPING_EVENT_AS_IT_WAS_GENERATED_BY_K_2_INTERNAL_API_CALL + + JsonConverter.toJSON(operation), + Agent.class.getName()); + return; + } - logIfIastScanForFirstTime(securityMetaData.getFuzzRequestIdentifier(), securityMetaData.getRequest()); + logIfIastScanForFirstTime(securityMetaData.getFuzzRequestIdentifier(), securityMetaData.getRequest()); - setRequiredStackTrace(operation, securityMetaData); - operation.setUserClassEntity(setUserClassEntity(operation, securityMetaData)); - processStackTrace(operation); + setRequiredStackTrace(operation, securityMetaData); + operation.setUserClassEntity(setUserClassEntity(operation, securityMetaData)); + processStackTrace(operation); // boolean blockNeeded = checkIfBlockingNeeded(operation.getApiID()); // securityMetaData.getMetaData().setApiBlocked(blockNeeded); - if (needToGenerateEvent(operation.getApiID())) { - DispatcherPool.getInstance().dispatchEvent(operation, securityMetaData); - if (!firstEventProcessed.get()) { - logger.logInit(LogLevel.INFO, - String.format(EVENT_ZERO_PROCESSED, securityMetaData.getRequest()), - this.getClass().getName()); - firstEventProcessed.set(true); + if (needToGenerateEvent(operation.getApiID())) { + DispatcherPool.getInstance().dispatchEvent(operation, securityMetaData); + if (!firstEventProcessed.get()) { + logger.logInit(LogLevel.INFO, + String.format(EVENT_ZERO_PROCESSED, securityMetaData.getRequest()), + this.getClass().getName()); + firstEventProcessed.set(true); + } + } + } + } finally { + if(lockAcquired){ + ThreadLocalLockHelper.releaseLock(); } } } @@ -439,21 +445,30 @@ private static void setAPIId(AbstractOperation operation, List traceFor @Override public void registerExitEvent(AbstractOperation operation) { - if (operation == null) { - return; - } - K2RequestIdentifier k2RequestIdentifier = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier(); - HttpRequest request = NewRelicSecurity.getAgent().getSecurityMetaData().getRequest(); - - // TODO: Generate for only native payloads - if (!request.isEmpty() && !operation.isEmpty() && k2RequestIdentifier.getK2Request()) { - if (StringUtils.equals(k2RequestIdentifier.getApiRecordId(), operation.getApiID()) - && StringUtils.equals(k2RequestIdentifier.getNextStage().getStatus(), IAgentConstants.VULNERABLE)) { - ExitEventBean exitEventBean = new ExitEventBean(operation.getExecutionId(), operation.getCaseType().getCaseType()); - exitEventBean.setK2RequestIdentifier(k2RequestIdentifier.getRaw()); - logger.log(LogLevel.FINER, "Exit event : " + exitEventBean, this.getClass().getName()); - DispatcherPool.getInstance().dispatchExitEvent(exitEventBean); - AgentInfo.getInstance().getJaHealthCheck().incrementExitEventSentCount(); + boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + if(lockAcquired) { + if (operation == null) { + return; + } + K2RequestIdentifier k2RequestIdentifier = NewRelicSecurity.getAgent().getSecurityMetaData().getFuzzRequestIdentifier(); + HttpRequest request = NewRelicSecurity.getAgent().getSecurityMetaData().getRequest(); + + // TODO: Generate for only native payloads + if (!request.isEmpty() && !operation.isEmpty() && k2RequestIdentifier.getK2Request()) { + if (StringUtils.equals(k2RequestIdentifier.getApiRecordId(), operation.getApiID()) + && StringUtils.equals(k2RequestIdentifier.getNextStage().getStatus(), IAgentConstants.VULNERABLE)) { + ExitEventBean exitEventBean = new ExitEventBean(operation.getExecutionId(), operation.getCaseType().getCaseType()); + exitEventBean.setK2RequestIdentifier(k2RequestIdentifier.getRaw()); + logger.log(LogLevel.FINER, "Exit event : " + exitEventBean, this.getClass().getName()); + DispatcherPool.getInstance().dispatchExitEvent(exitEventBean); + AgentInfo.getInstance().getJaHealthCheck().incrementExitEventSentCount(); + } + } + } + } finally { + if(lockAcquired){ + ThreadLocalLockHelper.releaseLock(); } } } diff --git a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/NewRelicSecurity.java b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/NewRelicSecurity.java index c99aed0a2..cfe7f0b2e 100644 --- a/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/NewRelicSecurity.java +++ b/newrelic-security-agent/src/main/java/com/newrelic/api/agent/security/NewRelicSecurity.java @@ -8,6 +8,7 @@ package com.newrelic.api.agent.security; import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.security.instrumentation.helpers.ThreadLocalLockHelper; import com.newrelic.api.agent.security.schema.SecurityMetaData; import org.apache.commons.lang3.StringUtils; @@ -34,7 +35,7 @@ public static SecurityAgent getAgent(){ * {@code false} otherwise. */ public static boolean isHookProcessingActive(){ - return isAgentInitComplete && Agent.getInstance().isSecurityActive() && !isInternalThread() + return !ThreadLocalLockHelper.isLockHeldByCurrentThread() && isAgentInitComplete && Agent.getInstance().isSecurityActive() && !isInternalThread() && NewRelic.getAgent().getTransaction() != null && NewRelic.getAgent().getTransaction().getSecurityMetaData() instanceof SecurityMetaData; // (Agent.getInstance().getSecurityMetaData() != null); diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/FileHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/FileHelper.java index a6d21bbf4..2349d6a34 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/FileHelper.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/FileHelper.java @@ -65,12 +65,21 @@ public class FileHelper { public static final String FILE_OPERATION = "FILE_OPERATION"; public static boolean skipExistsEvent(String filename) { - String extension = getFileExtension(filename); - if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && - NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled()) && - extension != null && !extension.trim().isEmpty() && - (SOURCE_EXENSIONS.contains(extension) || ALLOWED_EXTENSIONS.contains(extension))) { - return true; + boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + if(lockAcquired) { + String extension = getFileExtension(filename); + if (!(NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getEnabled() && + NewRelicSecurity.getAgent().getCurrentPolicy().getVulnerabilityScan().getIastScan().getEnabled()) && + extension != null && !extension.trim().isEmpty() && + (SOURCE_EXENSIONS.contains(extension) || ALLOWED_EXTENSIONS.contains(extension))) { + return true; + } + } + } finally { + if(lockAcquired){ + ThreadLocalLockHelper.releaseLock(); + } } return false; @@ -89,39 +98,58 @@ public static String getFileExtension(String fileName) { } public static FileIntegrityOperation createEntryOfFileIntegrity(String fileName, String className, String methodName) { - File file = Paths.get(fileName).toFile(); - String extension = getFileExtension(file); - if (SOURCE_EXENSIONS.contains(extension) && - !NewRelicSecurity.getAgent().getSecurityMetaData().getFileLocalMap().containsKey(fileName)) { - long lastModified = file.exists()? file.lastModified() : -1; - String permissions = StringUtils.EMPTY; - try { - if(file.exists()) { - PosixFileAttributes fileAttributes = Files.readAttributes(Paths.get(file.getPath()), PosixFileAttributes.class); - Set permissionSet = fileAttributes.permissions(); - permissions = permissionSet.toString(); + boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + if(lockAcquired) { + File file = Paths.get(fileName).toFile(); + String extension = getFileExtension(file); + if (SOURCE_EXENSIONS.contains(extension) && + !NewRelicSecurity.getAgent().getSecurityMetaData().getFileLocalMap().containsKey(fileName)) { + long lastModified = file.exists() ? file.lastModified() : -1; + String permissions = StringUtils.EMPTY; + try { + if (file.exists()) { + PosixFileAttributes fileAttributes = Files.readAttributes(Paths.get(file.getPath()), PosixFileAttributes.class); + Set permissionSet = fileAttributes.permissions(); + permissions = permissionSet.toString(); + } + } catch (IOException e) { + } + long fileLength = file.length(); + FileIntegrityOperation fbean = new FileIntegrityOperation(file.exists(), fileName, className, + methodName, lastModified, permissions, fileLength); + NewRelicSecurity.getAgent().getSecurityMetaData().getFileLocalMap().put(fileName, + fbean); + return fbean; } - } catch (IOException e) { } - long fileLength = file.length(); - FileIntegrityOperation fbean = new FileIntegrityOperation(file.exists(), fileName, className, - methodName, lastModified, permissions, fileLength); - NewRelicSecurity.getAgent().getSecurityMetaData().getFileLocalMap().put(fileName, - fbean); - return fbean; + } finally { + if(lockAcquired){ + ThreadLocalLockHelper.releaseLock(); + } } return null; + } public static void checkEntryOfFileIntegrity(List fileNames) { - for (String fileName : fileNames) { - File file = Paths.get(fileName).toFile(); - if(NewRelicSecurity.getAgent().getSecurityMetaData().getFileLocalMap().containsKey(fileName)){ - FileIntegrityOperation fbean = NewRelicSecurity.getAgent().getSecurityMetaData().getFileLocalMap().get(fileName); - if(fbean.isIntegrityBreached(file)){ - NewRelicSecurity.getAgent().registerOperation(fbean); + boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); + try { + if(lockAcquired) { + for (String fileName : fileNames) { + File file = Paths.get(fileName).toFile(); + if(NewRelicSecurity.getAgent().getSecurityMetaData().getFileLocalMap().containsKey(fileName)){ + FileIntegrityOperation fbean = NewRelicSecurity.getAgent().getSecurityMetaData().getFileLocalMap().get(fileName); + if(fbean.isIntegrityBreached(file)){ + NewRelicSecurity.getAgent().registerOperation(fbean); + } + } } } + } finally { + if(lockAcquired) { + ThreadLocalLockHelper.releaseLock(); + } } } diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/ThreadLocalLockHelper.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/ThreadLocalLockHelper.java new file mode 100644 index 000000000..5e758f1a0 --- /dev/null +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/instrumentation/helpers/ThreadLocalLockHelper.java @@ -0,0 +1,34 @@ +package com.newrelic.api.agent.security.instrumentation.helpers; + +import java.util.concurrent.locks.ReentrantLock; + +public class ThreadLocalLockHelper { + + private static final ThreadLocal csecOperationLock = ThreadLocal.withInitial(ReentrantLock::new); + + public static boolean isLockHeldByCurrentThread() { + ReentrantLock lock = csecOperationLock.get(); + return lock.isHeldByCurrentThread(); + } + + public static boolean acquireLock() { + ReentrantLock lock = csecOperationLock.get(); + synchronized (lock) { + if(!lock.isHeldByCurrentThread()){ + lock.lock(); + return true; + } + } + return false; + } + + public static void releaseLock() { + ReentrantLock lock = csecOperationLock.get(); + synchronized (lock) { + if(lock.isHeldByCurrentThread()){ + lock.unlock(); + } + } + } + +} diff --git a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/FileIntegrityOperation.java b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/FileIntegrityOperation.java index b73e0c740..d334a4158 100644 --- a/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/FileIntegrityOperation.java +++ b/newrelic-security-api/src/main/java/com/newrelic/api/agent/security/schema/operation/FileIntegrityOperation.java @@ -1,5 +1,6 @@ package com.newrelic.api.agent.security.schema.operation; +import com.newrelic.api.agent.security.instrumentation.helpers.ThreadLocalLockHelper; import com.newrelic.api.agent.security.schema.AbstractOperation; import com.newrelic.api.agent.security.schema.StringUtils; import com.newrelic.api.agent.security.schema.VulnerabilityCaseType; @@ -143,18 +144,26 @@ public void setPermissionString(String permissionString) { } public boolean isIntegrityBreached(File file){ - Boolean exists = file.exists(); - long lastModified = exists? file.lastModified() : -1; - String permissions = StringUtils.EMPTY; - long length = file.length(); + boolean lockAcquired = ThreadLocalLockHelper.acquireLock(); try { - if(exists) { - PosixFileAttributes fileAttributes = Files.readAttributes(Paths.get(file.getPath()), PosixFileAttributes.class); - Set permissionSet = fileAttributes.permissions(); - permissions = permissionSet.toString(); + if(lockAcquired) { + Boolean exists = file.exists(); + long lastModified = exists ? file.lastModified() : -1; + String permissions = StringUtils.EMPTY; + long length = file.length(); + if (exists) { + PosixFileAttributes fileAttributes = Files.readAttributes(Paths.get(file.getPath()), PosixFileAttributes.class); + Set permissionSet = fileAttributes.permissions(); + permissions = permissionSet.toString(); + } + return (exists != this.exists || lastModified != this.lastModified || !StringUtils.equals(permissions, this.permissionString) || length != this.length); } } catch (IOException e) { + } finally { + if(lockAcquired) { + ThreadLocalLockHelper.releaseLock(); + } } - return (exists != this.exists || lastModified != this.lastModified || !StringUtils.equals(permissions, this.permissionString) || length != this.length); + return false; } }