fn icon indicating copy to clipboard operation
fn copied to clipboard

Files in tmpfs are not executable

Open denismakogon opened this issue 7 years ago • 8 comments

Description

Here's the idea: imagine that function needs certain *.so (or binary executable) file during its runtime. The only place where a function can write the data is: /tmp. In case of Go plugins, they have to be stored as a files somewhere be loaded through the its file path.

In my case i cannot load the *.so file from because tmpfs mounted with noexec by default. Server logs:

Oct 08 20:36:29 linuxkit-025000000001 app_id=01CQR004HQNG8G00GZJ0000001,fn_id=01CS33AR73NG8G00GZJ00000:  2018/10/08 17:36:29 temp file /tmp/63edccae-9421-45d6-ac1c-4df4752de7dd-157150367.so created 
Oct 08 20:36:30 linuxkit-025000000001 app_id=01CQR004HQNG8G00GZJ0000001,fn_id=01CS33AR73NG8G00GZJ00000:  2018/10/08 17:36:30 /tmp/63edccae-9421-45d6-ac1c-4df4752de7dd-157150367.so access rights: -rwxr-xr-x 
Oct 08 20:36:30 linuxkit-025000000001 app_id=01CQR004HQNG8G00GZJ0000001,fn_id=01CS33AR73NG8G00GZJ00000:  2018/10/08 17:36:30 plugin.Open("/tmp/63edccae-9421-45d6-ac1c-4df4752de7dd-157150367.so"): /tmp/63edccae-9421-45d6-ac1c-4df4752de7dd-157150367.so: failed to map segment from shared object 

Steps to reproduce the issue:

I wrote a function (https://github.com/denismakogon/awesome-fn/tree/master/go-plugin-func) that downloads pre-compiled Go plugin and attempts to invoke a method out of that. Function's code works fine (see test script).

  1. Deploy a function
  2. Trigger a function: curl -v -X POST http://localhost:8080/t/testapp/go-plugin-func-trigger -d @payload.json
  3. See the result.

Describe the results you received:

*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /t/testapp/go-plugin-func-trigger HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 116
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 116 out of 116 bytes
< HTTP/1.1 500 Internal Server Error
< Content-Type: text/plain; charset=utf-8
< Fn-Call-Id: 01CSACE64QNG8G00GZJ0000005
< Date: Mon, 08 Oct 2018 17:43:48 GMT
< Content-Length: 167
< 
* Connection #0 to host localhost left intact
plugin.Open("/tmp/76899499-bed2-4858-bb73-5fac85d1e98a-279465297.so"): /tmp/76899499-bed2-4858-bb73-5fac85d1e98a-279465297.so: failed to map segment from shared objectDeniss-MBP-2:go-plugin-func 

Describe the results you expected:

Has to be 200 OK with some dummy text.

Output of fn version (CLI command):

Client version is latest version: 0.5.15
Server version:  0.3.591

Notes

If i get it right, the fix itself is not complex, but docker doesn't support yet exec for tmpfs.

denismakogon avatar Oct 08 '18 17:10 denismakogon

why would a user do this at runtime? this seems to defeat a lot of the benefits of building docker images, which is kinda the idea here, where this wouldn't be an issue at all?

rdallman avatar Oct 08 '18 21:10 rdallman

The idea is to have a general-purpose function that is capable to run custom code that is defined at the runtime.

At the very beginning I started with a python prototype where as a developer I can create and call a function at the runtime by executing deserialized callable objects (in python there’s a protocol called Pickle that does marshaling/unmarshaling no matter what kind of object that is, i.e., even if an object based on CPython).

Now I decided to do the same thing but with Go, the only way that I am aware of is Go plugins. So, my idea was to let function download *.so file and call the particular entity that complies to the particular interface.

Such feature allows developers to create the general-purpose function that can run whatever the developer what’s without actually creating/bumping/publishing a new container.

denismakogon avatar Oct 08 '18 21:10 denismakogon

that's fine about go modules... but why not do this in the Dockerfile? A large benefit of the docker registry ecosystem is immutable images under versioned tags, this just seems to fart in the face of that... I can't discern any benefits, this just pushes users to do their own versioning of artifacts to download at runtime and makes users end up solving the same problem registry images already solve. if it's really such a pain in the ass to version functions, we should fix that (please elaborate if so) instead of trying to enable use cases that push lots of extra work onto users that we don't necessarily want to recommend...

rdallman avatar Oct 08 '18 21:10 rdallman

Well, as a developer I don’t see a problem in our versioning, but in versioning UX as well as testing. While you do an application development there is no way to do function testing at the appropriate level especially when we’re talking about chaining, so, every developer ends up cleaning his own docker registry too often because of numerous tags being populated. As a developer I’d like to get GIT-like experience while developing an application, i.e., I don’t want use a bunch of CLI flags, I want CLI only do a function build if code changes and I want make it happen by default.

denismakogon avatar Oct 08 '18 21:10 denismakogon

There are a lot of use cases where work is stored in the writable space, and that writable space needs to be marked executable, a quintessential example is https://github.com/jnr and most of these pieces won't exist during container creation but will be done during runtime

tjfontaine avatar Oct 08 '18 21:10 tjfontaine

Personally I see no reason actually mounting tmpfs with no exec option. And there’s no technical reasons not making Fn do that, volume isolations is not a concern here.

Maybe my use case looks weird, but it does exist. Imagine that a user wants to bring his own container as a function (with hot wrapper or just in the default manner) and that container runs a process that for some reason needs an /tmp mounted with exec option (or just needs to run some execs with a binary that is in /tmp).

With noexec we’re basically saying you can’t do that. An the obvious question is “why?”.

What’s the technical clarification for not mounting tmpfs with exec option?

denismakogon avatar Oct 08 '18 22:10 denismakogon

Good point, we should consider other use cases as well. I do not know offhand, re-opening though.

rdallman avatar Oct 09 '18 07:10 rdallman

I hope Docker 19.03 release will support TMPFS options and we would be able to enable exec mode for tmpfs, as well as other options if necessary.

denismakogon avatar Nov 06 '18 17:11 denismakogon