[Top][All Lists]

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

Re: grub2 not using linux cmdline as verbatim

From: Jiri Jaburek
Subject: Re: grub2 not using linux cmdline as verbatim
Date: Mon, 08 Jun 2015 17:31:16 +0200

On 06/06/2015 09:02 AM, Andrei Borzenkov wrote:
> В Fri, 05 Jun 2015 12:48:41 +0200
> Jiri Jaburek <address@hidden> пишет:
>> Seeing that grub2's shell language applies to the kernel cmdline as
>> well, not anymore.
> You misunderstand. grub2 shell language rules apply to grub2 shell
> script. When grub2 parses its input it has no idea whether result will
> be used as kernel command line.
> If you want to fix a problem you need to correctly identify this
> problem. Giving a problem completely off mark description will just
> cause it to be ignored.

Which is what I'm trying to do - I didn't know grub2 does shell
processing before recognizing keywords. It may be obvious to you,
but it wasn't for me and I'm thankful for your help so far.

>> The problem happens when an external pre-parser is already in place,
>> sanitizing possible user input for multiple bootloaders like syslinux,
>> zipl (system-z), grub1, lilo, u-boot, various EFI loaders, ..., or when
>> the cmdline is specified by the user in a bootloader-agnostic way.
>> In my specific example, a user wanted to pass `&' as a kernel module
>> parameter value, which works just about everywhere except grub2, which
>> does additional parsing on the cmdline.
> Any generic tool will still need to write bootloader-specific entry, so
> it needs to have bootloader-specific knowledge. It is trivial to quote
> line so it will not be further interpreted by GRUB shell:
> sed -e "s@'@'\\\\''@g" -e "s/\\(.*\\)/'\\1'/"
> This will enclose line in single quotes and replace all existing single
> quotes with '\''. Like in
> address@hidden:~/src/grub> echo "xx'bb'cc" | sed -e "s@'@'\\\\''@g" -e 
> "s/\\(.*\\)/'\\1'/"
> 'x x'\''b b'\''c c'
> This works for any input.

It, unfortunately, doesn't work for any printable ASCII input, I have
tried something similar prior to sending my first email here.

For example (in bash):

$ sed -e "s@'@'\\\\''@g" -e "s/\\(.*\\)/'\\1'/" <<'EOF'
a'b"c d{](address@hidden
'a'\''b"c d{](address@hidden'

When passed to grub as the kernel cmdline, it gets transformed to:

  "a\'b\"c d{](address@hidden"

(instead of the original)

  a'b"c d{](address@hidden

Doing a side step with variables works around the double quotes, but
not around the backslashes:

  set testvar='a'\''b"c d{](address@hidden'
  linux16 /some/image $testvar

results in:

  a\'b\"c d{](address@hidden

Just pointing out that it's not an easy problem to solve with a simple

>> The point is that even if I wrote an anti-parser to grub2's parser,
>> escaping quotes and sequences to make it pass the cmdline 1:1 as the
>> user specified (this might include intentionally broken syntax for
>> kernel testing), I can't catch everything - for example I was unable
>> to make grub2 send a single `\' (backslash) character - specifying it
>> twice `\\' left two characters in place (instead of one), specifying
>> it once just made grub2 replace it with quotes.
>> Using variables didn't help much either.
> Yes, that is the problem. GRUB overquotes its input. E.g. it will change
> parm="foo bar"
> into
> "parm=\"foo bar\""
> which will then be interpreted by kernel as two arguments
> name  = parm
> value = \"foo
> name  = bar\""
> value = NULL
> That needs fixing. Could you provide real life use-case where this
> behavior causes an issue? Searching archives suggests similar problem
> that is stated to be fixed.

My use case is a system for managing a pool of machines (hardware) and
installing OSes on them based on user requests.
( )

Here, the user can select a kernel+initrd combination and optionally
specify additional kernel cmdline arguments via some UI and the system
allocates a machine from the pool and starts the kernel+initrd via PXE.
This is done transparently for any HW architecture / loader from the
POV of the user.

The kernel cmdline may include anything from module-specific options
to initrd-specific or init(1)-specific options such as IP addresses
or hostnames for root= on NFS, URL of an auto-installation script
("kickstart" for fedora/rhel/centos, "preseed" for debian, ...), etc.

In general, the system needs to be robust to whatever the user passes
on the cmdline, preferably with just a simple character-based filter
(printable ascii chars). The system doesn't care what happens beyond
the bootloader - if the kernel crashes as a result of the user passing
malicious arguments, that's fine.
The problem here is that it happens in the loader and thus automatically
marks the machine (HW) as "broken".

>> Considering this, would you see a feature request for parser-less
>> handling of the kernel cmdline sane?
> If you mean that GRUB shell should somehow foresee that input is
> intended as kernel command line - that is simply not possible. If you
> mean fixing overquoting of kernel arguments before they are passed to
> kernel - sure, it is not feature request, it is bug fix.

My use case is simply passing anything from ASCII 0x20 to 0x7e
(inclusive), possibly also 0x09 ('\t'), to the kernel command line,
as-is. I don't particularly care how that is done, I was just trying to
come up with something that would be "clean" and useful to others.

The documentation, section 5.2, Quoting, seems to suggest that all that
is needed for any such input to be passed unchanged, is to simply wrap
it up in single quotes and escape any existing single quotes, just like
the sed line you provided.

Therefore maybe all this is just a single bug in multiple forms.

> BTW GRUB2 can read and interpret GRUB legacy menu.lst. You may give it
> a try.

Thanks, will explore that possibility if all else fails.

>> Maybe it could be implemented as assignment of "raw" content into
>> a variable and then using the variable as-is, to be more versatile.
> That's already possible. Except variable assignment goes through the
> same GRUB shell parsing so you just shifted your issue to another place.
>> Maybe an external file with kernel cmdline (like system-z), able to
>> contain even newlines or any other non-ascii bytes.
> You need to give compelling arguments why you want to do it, including
> real life use case examples. Although we may need to implement
> arbitrary binary arguments at some point to support e.g. EFI programs.

Maybe a generic implementation would be reading files into variables,
though I'm not sure how well grub stores ie. '\0' in variables and/or
how the variable expansion would deal with such case.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]