On Sat, Apr 10, 2021 at 08:38:58AM +0200, tlaro...@polynum.com wrote: > Hello Robert, > > On Sat, Apr 10, 2021 at 08:34:51AM +0700, Robert Elz wrote: > > Sometime, in the now moderately distant past, I recall a notable > > NetBSD developer say that the one useful thing missing from our /bin/sh > > that is present in bash & ksh (and zsh) is {var}>whatever type redirects. > > > > I have been hesitant about implementing this as I could not think > > of a way (in our shell) to do it safely. > > > > For anyone unaware, this kind of redirect does the redirect, picks > > a "random" fd, ("random" here just means unknown to the script writer, no > > mathematical randomness properties implied, or implemented) and assigns > > its value to the variable named in the braces. It is particularly useful > > in functions, where a temporary fd is needed, but where it is unknown > > which fds the application might be using (so the function cannot simply > > safely pick fd=7 (or some other number) and hope). > > > > Our problem is what "random" fd to assign? Traditionally, shells > > have simply assigned anything (currently unused) >= 10, and with ksh > > that works fine, as users are only allowed to use (in redirects) fds > > between 0 and 9 (incl) - that is, a single digit. We don't have that > > limitation, so I have always been worried about how to avoid > > > > exec {var}>/some/hidden/file ; # sh assigns var=10 and fd 10 is open > > # some arbitrary amount of intervening code here > > exec 10>/other/public/file > > > > echo secret text > ${var} > > > > I could never see a way to stop that from happening. Other shell internal > > use fd's the shell can simply renumber when the user attempts to use the > > same fd for the script's use (and we do that) - but that's not possible here > > as we cannot tell what the user might have done with the contents of var > > > > Eg: > > exec {var}>/some/hidden/file > > echo $var >/some/hidden/fd-number > > > > and then later > > > > echo whatever > "$(cat /some/hidden/fd-number)" > > > > This kind of thing might seem particularly perverse, but it is perfectly > > legal, and should work, and be safe. > > > > I am still unable to think of a way to make this safe ... bash is currently > > the only shell that has this problem, and there it is simply ignored. > > It hasn't caused any reported problems, but that may be because most > > shells still don't allow explicit use of an fd >= 10, so most scripts > > simply don't attempt to do that. > > Wouldn't be possible to flag "var" as being a "fd_var" (or whatever) and > disallow a direct or indirect redirection to a fd that is superior or > equal to some upper limit (see below) that is the minimum value > of the range reserved for this kind of redirection, unless it is given > as "$var"? > > > > > Relying on that kind of "works much of the time" has never been good > > enough for me. > > > > While I still cannot think of a way to automatically handle this, I > > do have a way to allow the script to tell the shell the biggest fd > > it will ever use, after which the shell simply always assigns fds > > bigger than that when using this new kind of redirect. If the script > > never explicitly uses fds >= 10, then it need do nothing (this is the > > normal case), otherwise it should make some explicit reference to the > > fd in code that is seen by the parser (it doesn't need to actually be > > executed) before the {var}> type redirect is first executed. > > > > Why not simply use fd the same way as memory is used, i.e. starting by both > ends, to have variable stack and heap concurrently using the mem. > > Starting from 0 and increasing will be > the range to be used directly by the script; starting from the end and > decreasing will be the range for {var}>/some/file. The variable lower bound of > the latter will be the limit to test against in the above security > concern you have mentioned.
And to address the questions this could introduce, one could stipulate: 1) A var such as: exec {var}>/some/file is called a "named fd" since it shall be referred to by the variable and not by it's implementation defined value; 2) A "named fd" var once set is neither writable nor directly readable by the script; it is read-only except it is only "readable" by the implementation; 3) Redirections are only allowed such as ">$var" via the name and not directly by the value (since "echo $var" gives "\n"), the following construction being the only one allowed for "variables" named fds: if some_condition; then this_fd=var1 else this_fd=var2 fi echo "something" > eval \$$this_fd 4) The current lower limit of named fds allocated can be retrieved by the variable NAMEDFD_WATERMARK (or whatever). New named fds are only allocated if there is room between the current upper limit of users allocated fds and the NAMEDFD_WATERMARK. The named fds range grows downward. The implementation only guarantees that fds strictly less than NAMEDFD_WATEMARK are at the user disposition (at the moment) but doesn't necessarily give the last value attributed to a named fd. Hoping this makes some sense. Best, -- Thierry Laronde <tlaronde +AT+ polynum +dot+ com> http://www.kergis.com/ http://kertex.kergis.com/ http://www.sbfa.fr/ Key fingerprint = 0FF7 E906 FBAF FE95 FD89 250D 52B1 AE95 6006 F40C