2016-03-09
A sensible surprise (to me) in the Bourne shell's expansion of "$@"
I generally like to think that I'm pretty well up on the odd corners of the Bourne shell due to having around Unix for a fair while. Every so often I stumble over something that shows me that I'm wrong.
So let's start with the following, taken from something Jed Davis discovered about Bash:
$ set -- one two three $ for i in "front $@ back"; do echo $i; done front one two three back $
When I saw this, my first reaction was basically 'what?', because it didn't seem to make any sense. After I mumbled a bit on Twitter, Jed Davis found the explanation in the Single Unix Specification here:
When the expansion occurs within double-quotes, and where field splitting [...] is performed, each positional parameter shall expand as a separate field, with the provision that the expansion of the first parameter shall still be joined with the beginning part of the original word (assuming that the expanded parameter was embedded within a word), and the expansion of the last parameter shall still be joined with the last part of the original word.
The purpose of "$@"
is to preserve arguments that originally have
spaces in them as single arguments. So, for example:
$ set -- "one argument" "two argument" $ for i in "$@"; do echo $i; done one argument two argument $ for i in "$*"; do echo $i; done one argument two argument $
This is what the first part of the SuS specification describes (up
to 'shall expand as a separate field'). But this definition opens
up a question; what is result of expansion if you have not a simple
"$@"
but instead something with additional text inside the double
quotes? One answer would be to completely turn off the special
splitting and argument preserving behavior of "$@"
(making it
identical to "$*"
here), but that probably wouldn't be very
satisfying. Traditional Unix and thus SuS instead says that you
should continue field splitting but pretend that any front text is
attached to the first argument and any back text is attached to the
last one.
(Since it's still text inside a "..."
, the front and rear text
is not subject to any word splitting; it's attached untouched as
a single unit.)
When I saw this, my first and not well thought out expectation was that any leading and trailing text would be subject to regular word splitting and thus be taken as separate, additional arguments. Of course this doesn't actually make sense if I think about it for real, because there is normally no word splitting inside double quotes. Thus, the traditional Unix and SuS behavior is perfectly reasonable here and makes sense from an algorithmic perspective.
Given all this, the result of the following is not really surprising:
$ set -- one two three $ for i in "$@ $@"; do echo $i; done one two three one two three $
(Writing this entry has been useful in forcing me to confront some
of my own fuzzy thinking around the whole area of "$@"
, as you
can tell from the story of my first reaction to this.)
Some thoughts on ways of choosing what TLS ciphers to support
As you might expect, the TLS DROWN attack has me looking at our TLS configurations with an eye towards making them more secure. In light of DROWN I'm especially looking at our non-HTTPS services, the most prominent of these being IMAP. As part of this I've been thinking about various approaches to deciding what TLS ciphers to support or disallow.
(I'm going to use 'cipher' somewhat broadly here; I really mean what often gets called 'cipher suites'.)
There's a number of different principles for picking what cipher suites to support that one could follow here:
- Don't change anything and leave it to the software defaults. This
seems like a bad option in today's Internet world unless you make
sure to run the latest TLS software written by people who
aggressively disable ciphers (at least by default). TLS risks and
attacks just move too fast and TLS library defaults are often set
conservatively (or simply not changed from historical practice,
even when the threats change and some cipher suites become terrible
ideas).
The good news is that modern TLS libraries generally have disabled at least some terrible ideas, like SSLv2 and export grade ciphers. So some progress is being made here.
- Disable only known to be broken cipher suite options. Today I
believe that this is purely RC4 or MD5 based cipher suites (plus
terrible things like all export grade ciphers, SSLv2, etc).
These are sufficiently dangerous that any client with nothing
better is probably better off failing entirely.
(Certainly we don't want user passwords traveling to us over TLS encryption that's this weak, never mind any other protocol vulnerabilities that they may expose.)
- Disable obscure, rarely used cipher suites as well as known
broken ones. Today I believe that would add at least SEED and CAMELLIA based cipher
suites. I've certainly seen various sites that advise doing this.
(In some environments I believe that DES/3DES cipher suits would also be disabled here.)
- Set your cipher suites to the recommended best settings
from eg Mozilla or other
well regarded sources. These people
have hopefully already worked out both what the good state of
the art is as well as what tradeoffs you need to be broadly
compatible with existing clients. You may need to supplement
this with additional cipher suites if you have unusual clients.
(Mozilla is great for HTTPS services but I'm not sure they've looked at, say, the TLS support levels in various IMAP clients. And current versions of web browsers are probably more up to date than clients for other TLS services.)
- Track your actual client TLS usage and then set your cipher suites to what your users actually need, plus the latest high security ciphers so that new clients or upgraded ones can get the best security possible. The drawback here is making sure you really know all of the cipher suites that your users are using; you may find that people keep turning up with uncommon clients that need new cipher suites added.
Any time you explicitly set the list of TLS cipher suites to use (as opposed to disabling some from the default list), you become responsible for updating this list as new versions of TLS libraries add support for new and hopefully better cipher suites. Sometimes you can be a bit generic in your explicit settings; sometimes sites have you set an explicit list of specific cipher suites. Just disabling things is probably more future proof, although the ice may be thin here.
I don't currently have any opinions on what approach is the best one. Really, I don't think there is a single 'best one'; it depends on your circumstances.