Skip to content

Commit 50c49a7

Browse files
feat(aop): standard-allow low-risk entropy-device reads and default temp-file creation in the secure baseline
1 parent d33bf7e commit 50c49a7

2 files changed

Lines changed: 87 additions & 2 deletions

File tree

src/main/java/de/tum/cit/ase/ares/api/aop/java/aspectj/adviceandpointcut/JavaAspectJFileSystemAdviceDefinitions.aj

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ public aspect JavaAspectJFileSystemAdviceDefinitions extends JavaAspectJAbstract
932932
// A student can create and name their own directory tree, so a suffix-only
933933
// match would let them craft a path ending in one of those exact strings and
934934
// bypass pathsAllowedToBeCreated entirely.
935-
if (violation == null || isPathWithin(violation, TRUSTED_DEFAULT_TEMP_DIR)) {
935+
if (violation == null || isExplicitDirectoryTheTrustedDefaultTempDir(explicitDirectory)) {
936936
return true;
937937
}
938938
throw new SecurityException(localize("security.advice.illegal.file.execution", systemMethodToCheck, "create",
@@ -941,6 +941,49 @@ public aspect JavaAspectJFileSystemAdviceDefinitions extends JavaAspectJAbstract
941941
+ buildDenialReason(noAllowRuleConfigured)));
942942
}
943943

944+
/**
945+
* Returns {@code true} only when {@code explicitDirectory} resolves — after
946+
* following symlinks — to exactly the same real location as
947+
* {@link #TRUSTED_DEFAULT_TEMP_DIR} (itself resolved the same way). Only the
948+
* default temp directory itself is baseline-exempt from
949+
* {@code pathsAllowedToBeCreated}; a descendant, sibling, or symlink that
950+
* merely resolves lexically under it (e.g. a directory named
951+
* {@code link-to-forbidden} that is actually a symlink out of the temp root)
952+
* is not the default directory and must still be explicitly allow-listed —
953+
* {@link #isPathWithin}'s prefix match is deliberately not used here, since it
954+
* would treat every such descendant/symlink as exempt. Both sides are
955+
* resolved via {@link Path#toRealPath(LinkOption...)}, which performs real
956+
* filesystem access; that is safe here because the only caller,
957+
* {@link #checkTempFileCreationSpecialCase}, is reached exclusively from
958+
* inside {@link #checkFileSystemInteraction}'s re-entrancy guard, so any
959+
* advice re-entered by that filesystem access is a no-op, not unbounded
960+
* recursion. Any resolution failure (directory does not exist, permission
961+
* denied, a filesystem loop) is treated as "not proven equal" and fails
962+
* closed.
963+
*
964+
* @param explicitDirectory the directory argument as passed to
965+
* {@code createTempFile} (a {@code Path} or
966+
* {@code File})
967+
* @return {@code true} only if the explicit directory is exactly the trusted
968+
* default temp directory
969+
*/
970+
private static boolean isExplicitDirectoryTheTrustedDefaultTempDir(@Nonnull Object explicitDirectory) {
971+
if (TRUSTED_DEFAULT_TEMP_DIR == null) {
972+
return false;
973+
}
974+
try {
975+
Path candidate = variableToPath(explicitDirectory, true);
976+
if (candidate == null) {
977+
return false;
978+
}
979+
Path candidateReal = candidate.toRealPath();
980+
Path trustedReal = Path.of(TRUSTED_DEFAULT_TEMP_DIR).toRealPath();
981+
return candidateReal.equals(trustedReal);
982+
} catch (IOException | InvalidPathException ignored) {
983+
return false;
984+
}
985+
}
986+
944987
/**
945988
* Returns {@code true} when {@code java.io.tmpdir} still resolves to the same
946989
* location as {@link #TRUSTED_DEFAULT_TEMP_DIR}, the value captured at

src/main/java/de/tum/cit/ase/ares/api/aop/java/instrumentation/advice/JavaInstrumentationAdviceFileSystemToolbox.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,7 @@ private static boolean checkTempFileCreationSpecialCase(@Nonnull String action,
916916
// A student can create and name their own directory tree, so a suffix-only
917917
// match would let them craft a path ending in one of those exact strings and
918918
// bypass pathsAllowedToBeCreated entirely.
919-
if (violation == null || isPathWithin(violation, TRUSTED_DEFAULT_TEMP_DIR)) {
919+
if (violation == null || isExplicitDirectoryTheTrustedDefaultTempDir(explicitDirectory)) {
920920
return true;
921921
}
922922
throw new SecurityException(
@@ -926,6 +926,48 @@ private static boolean checkTempFileCreationSpecialCase(@Nonnull String action,
926926
+ " | " + buildDenialReason(noAllowRuleConfigured)));
927927
}
928928

929+
/**
930+
* Returns {@code true} only when {@code explicitDirectory} resolves — after
931+
* following symlinks — to exactly the same real location as
932+
* {@link #TRUSTED_DEFAULT_TEMP_DIR} (itself resolved the same way). Only the
933+
* default temp directory itself is baseline-exempt from
934+
* {@code pathsAllowedToBeCreated}; a descendant, sibling, or symlink that
935+
* merely resolves lexically under it (e.g. a directory named
936+
* {@code link-to-forbidden} that is actually a symlink out of the temp root) is
937+
* not the default directory and must still be explicitly allow-listed —
938+
* {@link #isPathWithin}'s prefix match is deliberately not used here, since it
939+
* would treat every such descendant/symlink as exempt. Both sides are resolved
940+
* via {@link Path#toRealPath(LinkOption...)}, which performs real filesystem
941+
* access; that is safe here because the only caller,
942+
* {@link #checkTempFileCreationSpecialCase}, is reached exclusively from inside
943+
* {@link #checkFileSystemInteraction}'s re-entrancy guard, so any advice
944+
* re-entered by that filesystem access is a no-op, not unbounded recursion. Any
945+
* resolution failure (directory does not exist, permission denied, a filesystem
946+
* loop) is treated as "not proven equal" and fails closed.
947+
*
948+
* @param explicitDirectory the directory argument as passed to
949+
* {@code createTempFile} (a {@code Path} or
950+
* {@code File})
951+
* @return {@code true} only if the explicit directory is exactly the trusted
952+
* default temp directory
953+
*/
954+
private static boolean isExplicitDirectoryTheTrustedDefaultTempDir(@Nonnull Object explicitDirectory) {
955+
if (TRUSTED_DEFAULT_TEMP_DIR == null) {
956+
return false;
957+
}
958+
try {
959+
Path candidate = variableToPath(explicitDirectory, true);
960+
if (candidate == null) {
961+
return false;
962+
}
963+
Path candidateReal = candidate.toRealPath();
964+
Path trustedReal = Path.of(TRUSTED_DEFAULT_TEMP_DIR).toRealPath();
965+
return candidateReal.equals(trustedReal);
966+
} catch (IOException | InvalidPathException ignored) {
967+
return false;
968+
}
969+
}
970+
929971
/**
930972
* Returns {@code true} when {@code java.io.tmpdir} still resolves to the same
931973
* location as {@link #TRUSTED_DEFAULT_TEMP_DIR}, the value captured at

0 commit comments

Comments
 (0)