On Tue, Jan 31, 2017 at 09:35:55PM +0000, Laurent Bercot wrote:
> It won't do it in every case: parsing /proc/cmdline is hazardous and
> much more difficult than it appears. (There could be quotes, and quoted
> spaces, in the elements.) We had a discussion about this on the Alpine
> development IRC channel, and it appeared that you can't do it safely
> with less than 50 lines of shell.
Perhaps more than 50 lines if you insist on use sh(1) because of the
usage of `eval' to set up dynamically-named variables, eg.:
> eval "${opt%%=*}='${opt#*=}'"
which, for opt="a=b' dont-rm -rf /'", becomes
> a='b' dont-rm -rf /''
However, the code can be very simple if you use a shell that does not
forbid "$key=val", and restrict the kernel command line as a
space-separated list of strings in the `key[=val1,val2,...]' form,
where `key's are valid shell variable names, and `val's are strings of
non-whitespace non-comma printable characters. Here's an example
written in rc(1) (the Byron Rakitzis implementation):
> for (opt in `{cat /proc/cmdline}) {
> if (~ $opt *'='*) {
> key=`{echo $opt | sed 's/=.*$//'}
> KOPT_$key=`{echo $opt | sed 's/^[^=]*=//; s/,/ /g'}
> } else if (~ $opt no*) {
> KOPT_`{echo $opt | sed 's/^no//'}=no
> } else KOPT_$opt=yes
> }
> The simplest solution, if you control the kernel command line, is to
> duplicate the root= argument with something the kernel will let through:
> The kernel keeps the "root" argument, but puts "rootfs" in the
> environment, which you can easily read from.
>From those distros I have used, it seems that the kernel does not eat
anything from its command line, so I think it is unnecessary to
duplicate the `rootfs' parameter.
> Once it has all the information it needs and has found its rootfs, the
> initramfs script doesn't need environment variables anymore, so it
> cleans up its environment. You should do the same: be as transparent as
> possible, do not leak into /sbin/init anything it doesn't strictly need.
> /sbin/init may have the environment variables set by the kernel, but it
> definitely shouldn't have any variables set by your initramfs script.
In addition, the cause for `KOPT_*' not showing up in Alpine init is
that sh(1) does not leak manually set variables except when told to
`export'. In contrast, rc(1) does not have the `export' builtin, and
simply exports all variables. Anyway, you can use the following
chainloading command to clean up the environment just before switching
root:
> /bin/busybox env -i [key1=val1 key2=val2 ...] \
> /bin/busybox switch_root $root $init
--
My current OpenPGP key:
RSA4096/0x227E8CAAB7AA186C (expires: 2020.10.19)
7077 7781 B859 5166 AE07 0286 227E 8CAA B7AA 186C
Received on Wed Feb 01 2017 - 07:42:19 UTC