FarCry 7.2.12 in a shared hosting environment (sandbox security)

In order to mitigate the issues I ran into while trying to find a solution for an alleged memory issue in the FarCry core, I enabled the sandbox security feature in the ColdFusion 2018 administrator, disabled the CFExecute() and CFRegistry() tags, restricted the access to the application web root and its subdirectories, and left the default entries for the CF Functions – disabling CreateObject(java) – as well as the createClassLoader runtime permission.
Alas, this did not turn out to be a good idea.

I immediately witnessed the FarCry 7.2.12 core crash on run-up. As I was able to figure out so far, the issues are threefold:

  1. The FarCry core uses the CF GetTempDirectory() function to handle CDN, 3S, file and image uploads. Unfortunately, the GetTempDirectory() returns a path outside the application’s realm, somewhere in the CF 2018 application file-tree.
    So far I was able to resolve this issue for the front-end by adding an application variable bUseSandbox, adding a /temporary directory in the web root, and making adjustments in the CDN section, the file and image CFC, and a few others. This seems to work.
    [Edit: The backend, however, still crashes during an image upload when trying to resize it in local.cfc:ioFileWrite() (around line 163) in the CF imageWrite() function with java.io error that a file or directory cannot be accessed.]
    If anybody is interested, I’ll be happy to share what I figured out so far. (I don’t use the CDN and S3 functions myself but some testing will show where I erred.)

  2. When FarCry starts up the first time after the server being (re)started with or without the ?updateapp=<your_secret_key> URl extenson, it throws an exception in /core/application.cfc when trying to load the plugins in line 184:
    <cfloop list="#(this.plugins ?: "")#" index="plugin">
    The exception reads as follows:
    java.security.AccessControlException: access denied ("java.io.FilePermission" "/Applications/ColdFusion2018/cfusion/wwwroot/WEB-INF/cfclasses/cfApplication2ecfc42533848$func_CF_ANONYMOUSCLOSURE_ELVIS0.class" "read")
    If you change anything in the /core/application.cfc file (for example, by adding a <cfdump> tag) and hitting the browser load button again, FarCry starts up just fine.
    It seems that if you move the plugins preset <cfparam name="this.plugins" default="" /> (it should have been set to include farcrycms in the farcryConstructor.cfm file which will be processed before), prior to calling the setupJARPaths() function, remove the ternary operator from the <cfloop> tag, and remove the preset from the initApplicationScope function, everything seems to be fine.
    [Edit: The same seems to hold true for the ternary operator when calling the addJARPath() function. Here too, I found it necessary to properly preset this.projectDirectoryName before the function all.]
    (Again: I’m happy to share the code.)

  3. To me, it seems that if a hosting provider denies runtime permission for the createClassLoader and/or the use of CreateObject(java), you are screwed. (Or do you know about a shared hosting company which allows to use those CF features?

I am curious if anybody has been playing with the sandbox security and what your experience is. As always, any pointers in the right direction will be greatly appreciated.

Re your question about hosts that allow those tags. Maybe try Hostek. According to the features list they don’t allow CreateObject on the Personal plan but do on the plans above that. BTW you can sign up for a month for free to try them.

ColdFusion Hosting - ColdFusion VPS Hosting - ColdFusion Host Plans | HOSTEK

I haven’t used the CF2018 Sandbox but I’ll answer your questions as best I can;

1 . Yes, GetTempDirectory() is required and the sandbox should be providing access to somewhere on the file system to write temporary files to so that temporary file operations can work. We would not want to write temporary files inside the webroot, such as /temporary because this is a security risk; temporary files should be written somewhere that is not web accessible.

2 . This almost looks like another file system permission issue;

java.security.AccessControlException: access denied ("java.io.FilePermission" "/Applications/ColdFusion2018/cfusion/wwwroot/WEB-INF/cfclasses/cfApplication2ecfc42533848$func_CF_ANONYMOUSCLOSURE_ELVIS0.class" "read")

I’m not sure that declaring this.plugins in a different place would truly be the fix for that exception if it’s a more general problem; The class name is directly related to the Elvis operator, but the compiled class file being unreadable is the underlying issue and so it might also surface in other places that use the Elvis operator as well?

If you have a diff or a copy of the file that you’ve changed then I’m happy to look at it to see if there’s something we can/need to fix.

3 . Yes, FarCry Core requires access to Java classes so hosting providers need to support these functions. If that was a problem I would suggest looking for a better host and/or consider hosting on Lucee rather than Adobe ColdFusion. As Mark says Hostek is probably one of the better choices, but that’s as far as my knowledge extends on shared hosts as I typically host everything myself on DigitalOcean / Vultr / AWS / Azure / others.

Hope that helps :slight_smile:

@ Mark: Thank you for the pointer. I’ll give hostek.com a thorough look later this week. At the first glance, it looks promising, though.

@ Justin: Well, then this means going back to the drawing board…
Is there a possibility to upload the /farcry/core/Application.cfc file?

After months of trial & error, a very supportive SysAdmin at my hosting company and I found a workable solution on how to run the FarCry CMS 7.2.12 in a shared hosting environment. Here is what we found out when hosting at ColdFusion 2018 on an MS Windows 2016 server:

  • If you host a small site only and you intend to go with a shared hosting plan, you definitely should activate the sandbox security feature on your development/test box to make sure everything works as intended.

  • On the sandbox security panel, set the heap for a maximum available free “heap” of 30% of the memory you application uses. Make sure that the garbage collection is on. (This option should be on by default.)

  • Shared hosting usually comes with restrictions to CF tags, CF functions, Java functions, and server directories. Inform yourself upfront which tags and functions have been disabled. If you are not allowed to use the createObject(Java) function, you are out of luck: FarCry CMS heavily depends on it.

  • When it comes to CF tags and functions, keep in mind that some CF tags and function will call others. If your hosting company disabled one or more of the underlying CF tags/functions, your application will throw exceptions. Few system administrators know enough about ColdFusion to help you with that, so: Keep looking on the web.
    CF tags like CFExecute, CFRegistry, and CFSchedule are almost always disabled for security reasons.

  • On the “Files/DIR” section, make sure you have full permissions for the folder where your site files are. Also, set up Read, Write, and Delete access to the ColdFusion folder. In addition, set up a temporary folder with Read, Write, and Delete access. Finally, give access to the folder you have your fonts stored with Read, Write, and Delete access.

One of the candidates which might give you headaches is the GetTempDirectory() function. Usually, it will point to something like {coldfusion_root}/runtime/work/catalina/localhost/tmp on a MS Windows server. You might be allowed to read from and write to this directory, however, creating an <application_name>/ftp subdirectory for the FTP, CDN and other FarCry CFCs might be out of scope.
In order to circumvent this, I created a /temporary directory in the {web_root}, added an application scope property named bUseSandbox in {web_root}/farcryconstructor.cfm, and modified the FarCry CMS core components /core/Application.cfc, ftp.cfc, s3.cfc, farSkeleton.cfc, and cdn.cfc accordingly. (Please contact me if you are interested in those changes.) Whenever a reference to the GetTempDirectory() has been made, I modified the code as follows (example taken from ftp.cfc):

	<cfif NOT StructKeyExists(application, "bUseSandbox") OR NOT application.bUseSandbox>
		<cfif directoryExists(getTempDirectory() & application.applicationname)>
			<cfdirectory action="list" directory="#getTempDirectory()##application.applicationname#/ftpcache" recurse="true" type="file" name="qLeftovers" />
			<cfloop query="qLeftovers">
				<cffile action="delete" file="#qLeftovers.Directory#/#qLeftovers.name#" />
			</cfloop>
		</cfif>
	<cfelse>
		<cfif directoryExists(application.path.temporaryFilePath)>
			<cfdirectory action="list" directory="#application.path.temporaryFilePath#/ftpcache" recurse="true" type="file" name="qLeftovers" />
			<cfloop query="qLeftovers">
				<cffile action="delete" file="#qLeftovers.Directory#/#qLeftovers.name#" />
			</cfloop>
		</cfif>
	</cfif>

If the application scope property is set, FarCry CMS write to the /temporary directory; otherwise it will use the temporary directory down the {coldfusion_root} tree. This may not be the optimal solution, but it works. First of all, disk space is no longer a matter, and secondly, small sites usually don’t make heavy use of CDNs or FTP.

At that point, the site’s front-end worked like intended.

The back-end, however, remained a different story: While the file upload worked fine, the image upload threw Java security exceptions when I tried to upload an image. After days of frustration, I stumbled across a description of how to find out which temporary directory the ColdFusion <cfimage> custom tag and the ImageWrite() function use. And I guess you will not be surprised to learn that those temporary directories are usually not on your sandbox list of directories. (Hat tip to Russ Michaels for his explanation at CFIMAGE "Unable to create temporary file" error » The blog of Russ (snake) Michaels) On macOs, it might be a subdirectory of /var/folders, on MS Windows something unexpected like C:\Windows\TEMP. Oh, well.

With that out of the way, I tried another single image upload and opted for resizing via the ColdFusion ImageWrite() function in the image.cfc component. The ColdFusion ImageWrite() function requires some temporary space for the images to store it, to resize/process it by executing the underlying Java code, and to finally return the resulting image via the ImageWrite() function. (The underlying Java code is available at http://www.docjar.com/html/api/java/nio/file/TempFileHelper.java.html.) However, it seemed to lack the access rights to a temporary directory somewhere on the server. Days went by until a search of the Adobe ColdFusion tracker site unearthed a weird combination of a bug in ColdFusion’s function: Tracker. Adobe claims that this bug only bites you if you run ColdFusion 11, 2016 and 2018 pre-update 2 on an MS Windows server with the server locked down (sandbox security enabled), the image’s metadata contains the ExifByteOrder tag, the CF user has delete permissions on ImageWrite()'s destination directory, and the script is not called from the {web_root}. Then the ImageWrite() function’s destination image inherits file permissions from {coldfusion_root}\cfusion\tmpCache\CFFileServlet_cf_image (instead of from the destination directory). Adobe claims to have fixed that bug in CF 2018 Update 2. I would not be surprised to find out that it still exists on MS Windows 2016 servers. I did, however, not find the time yet to verify my suspicion.

Long story short: If you are willing to forego the image resize function, you should be able to get FarCry 7.2.12 runing in an MS Windows shared hosting environment.

If anybody else will be able to make good use of it, my time was not wasted.

This information is amazing Thomas, thanks for sharing your experience.

Blair

Agreed, that’s a hugely detailed writeup Thomas, especially the sandbox settings which I’m sure will help someone at some point, so thanks! I’m also glad you were able to work through the crucial problems.

If cfimage/ImageWrite() is supposedly fixed in newer CF versions then I guess I’m happy for that one to fall back on the engine if there’s no code workaround for those versions.

I’d be interested in taking a look at the files you’ve modified to get GetTempDirectory() working in the shared environment because it looks like we might be able to integrate that into Core in an easier way. That might at least help you avoid having to make custom changes to your copy of Core when the version is upgraded, while also helping others out of the box :slight_smile: If you can link to a Git repo where you’ve committed the changes that might be good, otherwise you can email me a zip of the files/copy of Core directly to justin (at) daemon.com.au.

Thank you all for your kind responses. I am glad if those findings will help others avoid falling into the same trap.

BTW, the entire issue seems to get more confusing by the day: I conjured a little script that takes an image residing in the {web_root}/cache directory. Mimicking the FarCry CMS core process, it resizes the image with a (manually preset) structure to the FarCry CMS thumbnail size (80 x 80 pixels). (And yes, the preset structure uses the very same parameters as the FarCry process. Believe me, folks.) This script, called from the {web_root}, works like a charm. The same operation, while being called during the image update process, fails with an IO exception.

To me, it seems as if the “secret” temporary directory which will be determined in the TempFileHelper Java class (see the source code at http://www.docjar.com/html/api/java/nio/file/TempFileHelper.java.html) points outside the secure realm of the security sandbox, causing the operation to fail with an Java IO exception. To verify this behavior, one would have to temporarily change the Java code, explicitly revealing the “secret” temporary directory, to inject this class into a running and locked-down ColdFusion 2018 server on MS Windows Server 2012, 216, and other, and to monitor the outcome. I confess that I am not that nerdy.

With respect to Adobe’s claims that the bug has been solved in CF 2018 Update 2 for all MS Windows Server, I’d use the same word one hears so often this days on U.S. Late Night shows: “allegedly.”

@ Justin: I sent the modified files via email.