#1064437 filename on command line gets mangled

Package:
guile-3.0
Source:
guile-3.0
Description:
GNU extension language and Scheme interpreter
Submitter:
Zefram
Date:
2024-02-23 10:51:06 UTC
Severity:
normal
#1064437#5
Date:
2024-02-22 08:01:15 UTC
From:
To:
The guile-3.0(1) command-line interface is documented to take the filename
of a script to execute.  Here's how well it understands filenames:

$ echo '(display "sadness") (newline)' > 'L?on.scm'
$ echo '(display "joy") (newline)' > $'L\xe9on.scm'
$ LC_ALL=C guile-3.0 --no-auto-compile $'L\xe9on.scm'
sadness
$ LC_ALL=de_DE.utf8 guile-3.0 --no-auto-compile $'L\xe9on.scm'
sadness
$ LC_ALL=de_DE.iso88591 guile-3.0 --no-auto-compile $'L\xe9on.scm'
joy

In this example I've created two different script files, with different
but related names, I've told guile-3.0(1) three times to run one
of them, and it's run the wrong one on two of the three attempts.
(The --no-auto-compile option doesn't affect the substantive result,
I'm just using it to avoid the noise that the caching system would
otherwise make.)  In the invocations that ran the wrong file, one can see
via strace(1) that guile-3.0(1) doesn't use the correct filename for any
file operations at all; it completely substitutes the erroneous filename.
The use of the wrong filename doesn't depend on the file of that wrong
name existing: if there is no file of that name then guile-3.0(1) will
fail to find any script to execute, and will generate an error message
that shows the erroneous filename.

How guile-3.0(1) mangles the script filename on each invocation depends
on the locale implied by the environment, and more specifically on the
character encoding nominated by the LC_CTYPE component of the locale.
Nominating a locale that's not installed behaves the same as nominating
the C locale.  Part of my example above depends on having the de_DE.utf8
and de_DE.iso88591 locales installed.  If you don't have the specific
locales that I used then you can get the same results as me by
substituting an installed locale that nominates the same encoding.

This bug occurs in most cases where the supplied filename doesn't have
the syntax of locale-nominated encoding of text.  (A different bug occurs
in some other cases of the supplied filename not having such syntax,
report to come.)  The nature of the manglement is that each octet that
doesn't look like valid encoded text gets replaced with "?".

It appears that the supplied filename is being decoded, according
to the locale-nominated encoding, with decoding errors muffled and
"?" silently substituted in, and then the lossily-decoded filename is
re-encoded according to the locale-nominated encoding, and the result
of that process is the filename that gets actually used.  As far as I
can see the manglement comes only from character decoding: there isn't
also any Unicode normalisation.

This could cause a security problem in some circumstances that are only
slightly strange.  Suppose a privileged program is using guile-3.0(1)
to run scripts that partly derive from untrusted user input.  Suppose the
program has created an innocuous script to run, has permitted an untrusted
user to determine part of the filename for that script, and has ensured
that the supplied filename is innocuous from a Unix point of view but
isn't preventing the use of filenames with high-half octets.  Suppose
further that an untrusted user can cause the same program to create
another file, of content that the program doesn't intend to execute,
under the mangled name, which is almost as innocuous from a Unix point
of view.  Then it could execute code determined by a malicious user,
due entirely to guile-3.0(1) misinterpreting a filename.  I'm not aware
of any specific program that can be exploited in this way, and I haven't
based the declared severity of this bug report on this security issue.

Preferably, guile-3.0(1) should use the script file of the name that
was supplied on the command line.  It must pass to the file syscalls
the same octet string that was supplied as a command line argument,
without assuming anything about its syntax.

If it cannot be made to handle arbitrary filenames correctly, then
guile-3.0(1) must at least detect that it can't handle the specified
filename.  It must signal an error on any filename it can't handle, and
not use any mangled form of the filename for any purpose.  Furthermore,
this limitation must be documented.

#1064437#10
Date:
2024-02-23 04:11:09 UTC
From:
To:
Zefram <zefram@fysh.org> writes:

Hmm, if I don't misunderstand, this doesn't sound like a Debian-specific
issue.  So if you're comfortable with it, I'd recommend pursuing issues
like this upstream at either bug-guile@gnu.org or guile-devel@gnu.org,
since that's where the changes would need to be made.

Thanks

#1064437#15
Date:
2024-02-23 10:30:52 UTC
From:
To:
Rob Browning wrote:

This certainly is an upstream issue, but the Guile maintainers
have a history of not doing anything about character encoding
issues of this nature.  In fact, a version of this bug is
already mentioned in an upstream bug report (from me) that is
primarily about filenames getting mangled by file I/O functions.
I made that bug report in 2016 and it's had no reply so far.
See <http://debbugs.gnu.org/cgi/bugreport.cgi?bug=22913>.

I think, rather than merely punt to unresponsive maintainers, it would
be useful here to take some ameliorative action on the Debian side and
*then* prod upstream.  Seeing that a significant downstream user has
taken their own action to address a bug might provide the necessary
impetus for the upstream maintainers to tackle the issue.

Fully fixing the issue is beyond the scope of reasonable Debian-specific
customisation, because it has language design implications.  It would
also be unreasonably involved to patch the code in a way that only
affects the filename arguments: the manglement is actually applied
to the entirety of argv, and is done before parsing the arguments.
(See upstream bug report about manglement of arguments beyond the filename
<http://debbugs.gnu.org/cgi/bugreport.cgi?bug=20823>.  This got a bit
of discussion, but no fix and no agreement on how to fix it.)

What could reasonably be done on the Debian side is to add, to the code
that locale-decodes argv, some logic that checks whether the decoding has
been lossy, and signals an error if it is.  I imagine re-encoding the
decoded strings, in the same way as is done by file I/O functions, and
checking whether the resulting octet string matches the original octet
string.  We would also, of course, put a notice in the documentation,
cautioning about the locale-dependent acceptability of filenames and
other arguments.  Some variations are possible, such as erroring on
arguments that contain high-half octets regardless of locale, but I
think accepting the locale-dependent results is the least bad option
at this stage.  I can put together such a patch quite quickly, if you
agree that this customisation would be worthwhile.

The documentation part of the patch that I propose would also serve to
address Bug#1064440, regarding filenames that already produce encoding
errors.  As with the manglement issue, this kind of patch isn't a
proper fix, but ameliorates the issue pending a proper upstream fix.
Because both bugs arise from the same design issue, it's likely that a
single upstream fix would resolve both bugs.

A near-identical customisation can also be applied to the guile-2.2
package, to ameliorate the same problems there, which I reported as
Bug#1064444 and Bug#1064445.