Skip to content

Commit

Permalink
Extend operator control over the UDF threading model
Browse files Browse the repository at this point in the history
Patch by marcuse; reviewed by Sam Tunnicliffe and Benedict Elliott Smith for CASSANDRA-17352
  • Loading branch information
krummas committed Feb 7, 2022
1 parent 242f7f9 commit 5c9ba06
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 1 deletion.
13 changes: 13 additions & 0 deletions src/java/org/apache/cassandra/config/Config.java
Expand Up @@ -334,8 +334,21 @@ public class Config
* "tell" a user that there's something really wrong with the UDF.
* When you disable async UDF execution, users MUST pay attention to read-timeouts since these may indicate
* UDFs that run too long or forever - and this can destabilize the cluster.
*
* This requires allow_insecure_udfs to be true
*/
public boolean enable_user_defined_functions_threads = true;

/**
* Set this to true to allow running insecure UDFs.
*/
public boolean allow_insecure_udfs = false;

/**
* Set this to allow UDFs accessing java.lang.System.* methods, which basically allows UDFs to execute any arbitrary code on the system.
*/
public boolean allow_extra_insecure_udfs = false;

/**
* Time in milliseconds after a warning will be emitted to the log and to the client that a UDF runs too long.
* (Only valid, if enable_user_defined_functions_threads==true)
Expand Down
16 changes: 16 additions & 0 deletions src/java/org/apache/cassandra/config/DatabaseDescriptor.java
Expand Up @@ -755,6 +755,12 @@ else if (conf.native_transport_max_frame_size_in_mb >= 2048)
if (seedProvider.getSeeds().size() == 0)
throw new ConfigurationException("The seed provider lists no seeds.", false);

if (!conf.allow_insecure_udfs && !conf.enable_user_defined_functions_threads)
throw new ConfigurationException("To be able to set enable_user_defined_functions_threads: false you need to set allow_insecure_udfs: true - this is an unsafe configuration and is not recommended.");

if (conf.allow_extra_insecure_udfs)
logger.warn("Allowing java.lang.System.* access in UDFs is dangerous and not recommended. Set allow_extra_insecure_udfs: false to disable.");

if (conf.user_defined_function_fail_timeout < 0)
throw new ConfigurationException("user_defined_function_fail_timeout must not be negative", false);
if (conf.user_defined_function_warn_timeout < 0)
Expand Down Expand Up @@ -2175,6 +2181,16 @@ public static void setUserDefinedFunctionWarnTimeout(long userDefinedFunctionWar
conf.user_defined_function_warn_timeout = userDefinedFunctionWarnTimeout;
}

public static boolean allowInsecureUDFs()
{
return conf.allow_insecure_udfs;
}

public static boolean allowExtraInsecureUDFs()
{
return conf.allow_extra_insecure_udfs;
}

public static boolean enableMaterializedViews()
{
return conf.enable_materialized_views;
Expand Down
Expand Up @@ -36,6 +36,7 @@
import ch.qos.logback.classic.spi.TurboFilterList;
import ch.qos.logback.classic.turbo.ReconfigureOnChangeFilter;
import ch.qos.logback.classic.turbo.TurboFilter;
import org.apache.cassandra.config.DatabaseDescriptor;

/**
* Custom {@link SecurityManager} and {@link Policy} implementation that only performs access checks
Expand Down Expand Up @@ -69,6 +70,7 @@ public Enumeration<Permission> elements()
private static final RuntimePermission CHECK_MEMBER_ACCESS_PERMISSION = new RuntimePermission("accessDeclaredMembers");
private static final RuntimePermission MODIFY_THREAD_PERMISSION = new RuntimePermission("modifyThread");
private static final RuntimePermission MODIFY_THREADGROUP_PERMISSION = new RuntimePermission("modifyThreadGroup");
private static final RuntimePermission SET_SECURITY_MANAGER_PERMISSION = new RuntimePermission("setSecurityManager");

private static volatile boolean installed;

Expand Down Expand Up @@ -236,6 +238,9 @@ public void checkAccess(ThreadGroup g)

public void checkPermission(Permission perm)
{
if (!DatabaseDescriptor.enableUserDefinedFunctionsThreads() && !DatabaseDescriptor.allowExtraInsecureUDFs() && SET_SECURITY_MANAGER_PERMISSION.equals(perm))
throw new AccessControlException("Access denied");

if (!isSecuredThread())
return;

Expand Down
19 changes: 18 additions & 1 deletion src/java/org/apache/cassandra/cql3/functions/UDFunction.java
Expand Up @@ -149,6 +149,11 @@ public abstract class UDFunction extends AbstractFunction implements ScalarFunct
"java/util/zip/",
};

private static final String[] disallowedPatternsSyncUDF =
{
"java/lang/System.class"
};

static boolean secureResource(String resource)
{
while (resource.startsWith("/"))
Expand All @@ -157,14 +162,26 @@ static boolean secureResource(String resource)
for (String allowed : allowedPatterns)
if (resource.startsWith(allowed))
{

// resource is in allowedPatterns, let's see if it is not explicitly disallowed
for (String disallowed : disallowedPatterns)
{
if (resource.startsWith(disallowed))
{
logger.trace("access denied: resource {}", resource);
return false;
}
}
if (!DatabaseDescriptor.enableUserDefinedFunctionsThreads() && !DatabaseDescriptor.allowExtraInsecureUDFs())
{
for (String disallowed : disallowedPatternsSyncUDF)
{
if (resource.startsWith(disallowed))
{
logger.trace("access denied: resource {}", resource);
return false;
}
}
}

return true;
}
Expand Down

0 comments on commit 5c9ba06

Please sign in to comment.