
Hello, I am working on an application where I would like to chroot a thread, but I am not seeing a way to do it. I already have code which can run an IO action inside a chroot. The type signature is: fchroot :: FilePath -> IO a -> IO a The first argument is the new root, the second argument is the action to run with that root. You can see the implementation here if you are curious: http://src.seereason.com/build-env/Chroot.hs The problem with that function is that chroot affects the root of the whole process. In a single-threaded program this is (possibly) ok, because the original root is restored after the IO action completes (though with unsafeInterleaveIO, perhaps bad stuff will happen). In a multithreaded program it can be disasterous. As far as I know, the only solution would be to implement a function like fchroot which looks more like: pchroot :: FilePath -> IO () -> IO ExitCode Here the IO action would be forked off and run in a whole new process so that changing its root does not affect other 'threads'. Of course, you also can't use any of the nifty Haskell intra-thread communication stuff. Basically you can pass some values in and get back an exit code. However, I am not even sure how to implement a useful version of pchroot. In theory, I can just use forkProcess, but, the Giant Warning for forkProcess indicates that this will not be very useful in practice: forkProcess comes with a giant warning: since any other running threads are not copied into the child process, it's easy to go wrong: e.g. by accessing some shared resource that was held by another thread in the parent. Another example is the I/O manager thread: since the I/O manager isn't running in the child, attempting to do any Handle-based I/O will deadlock. Anyone have an ideas ? Thanks! - jeremy

On Sat, Dec 27, 2008 at 8:01 PM, Jeremy Shaw
The problem with that function is that chroot affects the root of the whole process.
Yeah. Maybe you want privilege separation. Instead of starting a thread to do the stuff that requires extra authority, make it a separate program and communicate with it with some simple protocol. qmail might be good to look at to get the intuition. You say you can only pass data and get back return codes, but really, you can send and receive whatever you want if the other process does I/O via a UNIX domain socket or something like that.

At Sat, 27 Dec 2008 22:41:58 -0600, brian wrote:
On Sat, Dec 27, 2008 at 8:01 PM, Jeremy Shaw
wrote: The problem with that function is that chroot affects the root of the whole process.
Yeah. Maybe you want privilege separation. Instead of starting a thread to do the stuff that requires extra authority, make it a separate program and communicate with it with some simple protocol. qmail might be good to look at to get the intuition.
In my case, it's not really a privilege / authority issue -- the goal is to be able to build chroot's to simulate different environments and then run code and applications in those environments. The primary use right now is an automated build system. The current solution has been to use 'system' and the chroot exectuable, but that has it's limitations.
You say you can only pass data and get back return codes, but really, you can send and receive whatever you want if the other process does I/O via a UNIX domain socket or something like that.
Yeah, I originally had some comments about forking off a seperate processing and talking to it via some sort of IPC. But, I left it out to see what other people would come up with :) Alas, fchroot is such a small, simple little function that can leverage the existing Haskell thread communication stuff. It is shame that to isolate the chroot to a single thread, requires such a significantly different approach. But, that is unix's fault not Haskell's. - jeremy

On Sun, 2008-12-28 at 00:22 -0500, Jeremy Shaw wrote:
At Sat, 27 Dec 2008 22:41:58 -0600, brian wrote:
On Sat, Dec 27, 2008 at 8:01 PM, Jeremy Shaw
wrote: The problem with that function is that chroot affects the root of the whole process.
Yeah. Maybe you want privilege separation. Instead of starting a thread to do the stuff that requires extra authority, make it a separate program and communicate with it with some simple protocol. qmail might be good to look at to get the intuition.
In my case, it's not really a privilege / authority issue -- the goal is to be able to build chroot's to simulate different environments and then run code and applications in those environments. The primary use right now is an automated build system.
What I've been considering for Cabal is a restricted IO monad. It would provide a bunch of the standard IO primitives for working with files and processes. Once we're using such a thing instead of IO directly then it is relatively easy to support a local/virtual working directory or indeed checking to support something like chroot. Indeed there are lots of things that can be added including logging, interactive debugging etc. I've been considering doing it in the style where the restricted IO monad generates a data structure with embedded continuations. The data structure is then interpreted to get real IO. Changing the interpreter allows for lots of different capabilities. As Lane pointed out, how hard this is depends on how many primitive operations you need. Duncan

Well, IIUC, chroot operates at the process level. I don't think that chrooting a lightweight haskell thread using FFI can ever make sense. I see two cases here: 1) You actually want to chroot lightweight threads. In this case, write a little ChRoot wrapper monad around IO that supports chrooted implementations of all of the operations you need. Depending on how much you need and how elegant it needs to be it might be a lot of work. 2) You want to launch non-haskell processes inside the chroot you just created. In this case, use forkProcess/fchroot/executeFile or even add chroot to the command line invocation. If you want to do both, do (2) inside (1). It would help to know on a broader level what your goal is. --Lane On Sat, 27 Dec 2008, Jeremy Shaw wrote:
Hello,
I am working on an application where I would like to chroot a thread, but I am not seeing a way to do it.
I already have code which can run an IO action inside a chroot. The type signature is:
fchroot :: FilePath -> IO a -> IO a
The first argument is the new root, the second argument is the action to run with that root.
You can see the implementation here if you are curious:
http://src.seereason.com/build-env/Chroot.hs
The problem with that function is that chroot affects the root of the whole process. In a single-threaded program this is (possibly) ok, because the original root is restored after the IO action completes (though with unsafeInterleaveIO, perhaps bad stuff will happen). In a multithreaded program it can be disasterous.
As far as I know, the only solution would be to implement a function like fchroot which looks more like:
pchroot :: FilePath -> IO () -> IO ExitCode
Here the IO action would be forked off and run in a whole new process so that changing its root does not affect other 'threads'. Of course, you also can't use any of the nifty Haskell intra-thread communication stuff. Basically you can pass some values in and get back an exit code.
However, I am not even sure how to implement a useful version of pchroot. In theory, I can just use forkProcess, but, the Giant Warning for forkProcess indicates that this will not be very useful in practice:
forkProcess comes with a giant warning: since any other running threads are not copied into the child process, it's easy to go wrong: e.g. by accessing some shared resource that was held by another thread in the parent. Another example is the I/O manager thread: since the I/O manager isn't running in the child, attempting to do any Handle-based I/O will deadlock.
Anyone have an ideas ?
Thanks! - jeremy _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (4)
-
brian
-
Christopher Lane Hinson
-
Duncan Coutts
-
Jeremy Shaw