lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Wed, Nov 25, 2015 at 15:52 -0800, William Ahern wrote:
> On Wed, Nov 25, 2015 at 12:54:25PM +0100, Mike Belopuhov wrote:
> > Hi,
> > 
> > As many of you have most probably stumbled upon the problem with fdopen
> > from the luaposix package on luajit and some of you have most probably
> > solved it one way or another, I'd like to post my solution to this problem
> > just for the purpose of archiving it and hopefully helping others.
> > 
> > But first a bit of a disclaimer: I do not consider myself an experienced
> > Lua programmer and perhaps there are better solutions to this problem (-;
> > 
> > local stdio = require("posix.stdio")
> > local unistd = require("posix.unistd")
> > 
> > function mikes_fdopen(fd)
> > 	local fh, rv
> > 
> > 	fh = io.tmpfile()
> > 	if (not fh) then
> > 		return nil
> > 	end
> > 	fh:flush()
> > 	rv = unistd.dup2(fd, stdio.fileno(fh))
> > 	if (not rv) then
> > 		fh:close()
> > 		return nil
> > 	end
> > 	unistd.close(fd)
> > 	return fh
> > end
> <snip>
> > I'm open to any public criticism or a public discussion regarding this.
> > Let me also say sorry in advance if this has already been presented
> > before, that would just mean that my google-fu wasn't strong enough.
> 
> Several people have come up with similar solutions, but I don't think that
> fact reflects poorly on your google-fu. ;)
> 
> Some comments:
> 
> 1) POSIX fdopen takes a mode argument. You're only partially implementing
> the interface by dup'ing the descriptor over the pre-existing descriptor.
> 
> 2) In jailed environments there may be no /tmp or even any writable
> directories at all.
>

All good points, indeed.

> The solution I arrived at in my own C-based Unix bindings module[1] is here
> 
> 	https://github.com/wahern/lunix/blob/tag-20150923/src/unix.c#L3642
>

Thanks for the link.  Building a C module is something we wanted to
avoid for now.  The other solution is obviously Foreign Function
Interface, however this is not portable to PUC-Rio Lua, and portability
was a primary objective for us.

> It attempts to open "." or "/dev/null" to get a blessed LuaJIT object using
> io.open. Visibility or read permissions aren't guaranteed, but more likely
> to work in a jailed environment. Then it replaces that FILE handle
> completely with a newly fdopen'd handle rather than dup'ing over the
> descriptor.
>

On our platform (OpenBSD) opening directories read-write (with open(2),
fopen(3) or io.open for that matter) doesn't work and generally speaking
would be a wrong thing to do anyways since there's no specified interface
for modifying directory entries via the write(2) system call.  "/dev/null"
is also generally not available in [proper] chroot environments, however
it can be created manually of course.

> [1] lunix is thread-safe[2], provides common extensions not defined by POSIX
> (with custom implementations if needed to make them "portable"), and is
> regularly tested on many non-Linux platforms--AIX, OS X, Solaris, and
> several different BSDs.
> 
> [2] At least as much as possible. The LuaJIT hack, for example, doesn't
> permit properly emulating the "x" (O_CLOEXEC) flag to fdopen, which could
> allow the temporary descriptor to be unintentionally inherited if another
> thread calls forks at the same time. Although I just realized that LuaJIT
> doesn't appear to check the contents of mode, so I should probably try to
> pass it through. (And maybe also add a runtime check to see if the x flag is
> supported by libc.)
> 

The lack of explicit CLOEXEC handling can be circumvented by calling
posix.fcntl with a F_SETFD and FD_CLOEXEC. This is a POSIX interface:
 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fcntl.h.html
and is implemented by luaposix since Jul 4, 2015.