Richard W.M. Jones
2016-Dec-18 20:09 UTC
[Libguestfs] [PATCH 1/2] launch: Rationalize how we construct the Linux kernel command line.
This is just code refactoring.
---
src/launch.c | 172 +++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 109 insertions(+), 63 deletions(-)
diff --git a/src/launch.c b/src/launch.c
index 46d7ab9..84d5e82 100644
--- a/src/launch.c
+++ b/src/launch.c
@@ -293,9 +293,7 @@ guestfs_impl_config (guestfs_h *g,
#endif
#if defined(__aarch64__)
-#define EARLYPRINTK " earlyprintk=pl011,0x9000000"
-#else
-#define EARLYPRINTK ""
+#define EARLYPRINTK "earlyprintk=pl011,0x9000000"
#endif
/**
@@ -327,75 +325,123 @@ char *
guestfs_int_appliance_command_line (guestfs_h *g, const char *appliance_dev,
int flags)
{
- char root[64] = "";
+ CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (argv);
char *term = getenv ("TERM");
- char *ret;
bool tcg = flags & APPLIANCE_COMMAND_LINE_IS_TCG;
- char lpj_s[64] = "";
- if (appliance_dev)
- snprintf (root, sizeof root, " root=%s", appliance_dev);
+ /* We assemble the kernel command line by simply joining the final
+ * list of strings with spaces. This means (a) the strings are not
+ * quoted (it's not clear if the kernel can handle quoting in any
+ * case), and (b) we can append multiple parameters in a single
+ * argument, as we must do for the g->append parameter.
+ */
+
+ /* Force kernel to panic if daemon exits. */
+ guestfs_int_add_string (g, &argv, "panic=1");
+
+#ifdef __arm__
+ guestfs_int_add_sprintf (g, &argv, " mem=%dM", g->memsize);
+#endif
+
+#ifdef __i386__
+ /* Workaround for RHBZ#857026. */
+ guestfs_int_add_string (g, &argv, "noapic");
+#endif
+
+ /* Serial console. */
+ guestfs_int_add_string (g, &argv, SERIAL_CONSOLE);
+
+#ifdef EARLYPRINTK
+ /* Get messages from early boot. */
+ guestfs_int_add_string (g, &argv, EARLYPRINTK);
+#endif
+
+#ifdef __aarch64__
+ guestfs_int_add_string (g, &argv, "ignore_loglevel");
+
+ /* This option turns off the EFI RTC device. QEMU VMs don't
+ * currently provide EFI, and if the device is compiled in it
+ * will try to call the EFI function GetTime unconditionally
+ * (causing a call to NULL). However this option requires a
+ * non-upstream patch.
+ */
+ guestfs_int_add_string (g, &argv, "efi-rtc=noprobe");
+#endif
+
+ /* RHBZ#1404287 */
+ guestfs_int_add_string (g, &argv, "edd=off");
+
+ /* For slow systems (RHBZ#480319, RHBZ#1096579). */
+ guestfs_int_add_string (g, &argv, "udevtimeout=6000");
+
+ /* Same as above, for newer udevd. */
+ guestfs_int_add_string (g, &argv, "udev.event-timeout=6000");
+
+ /* Fix for RHBZ#502058. */
+ guestfs_int_add_string (g, &argv, "no_timer_check");
if (tcg) {
const int lpj = guestfs_int_get_lpj (g);
if (lpj > 0)
- snprintf (lpj_s, sizeof lpj_s, " lpj=%d", lpj);
+ guestfs_int_add_sprintf (g, &argv, "lpj=%d", lpj);
}
- ret = safe_asprintf
- (g,
- "panic=1" /* force kernel to panic if daemon exits
*/
-#ifdef __arm__
- " mem=%dM"
-#endif
-#ifdef __i386__
- " noapic" /* workaround for RHBZ#857026 */
-#endif
- " " SERIAL_CONSOLE /* serial console */
- EARLYPRINTK /* get messages from early boot */
-#ifdef __aarch64__
- " ignore_loglevel"
- /* This option turns off the EFI RTC device. QEMU VMs don't
- * currently provide EFI, and if the device is compiled in it
- * will try to call the EFI function GetTime unconditionally
- * (causing a call to NULL). However this option requires a
- * non-upstream patch.
- */
- " efi-rtc=noprobe"
-#endif
- " edd=off" /* RHBZ#1404287 */
- " udevtimeout=6000"/* for slow systems (RHBZ#480319,
RHBZ#1096579) */
- " udev.event-timeout=6000" /* for newer udevd */
- " no_timer_check" /* fix for RHBZ#502058 */
- "%s" /* lpj */
- " printk.time=1" /* display timestamp before kernel messages
*/
- " cgroup_disable=memory" /* saves us about 5 MB of RAM */
- " usbcore.nousb" /* disable USB, only saves about 1ms
*/
- " cryptomgr.notests" /* disable crypto tests, saves 28ms
*/
- " tsc=reliable" /* don't synch TSCs when using
SMP,
- saves 21ms for each secondary vCPU */
- " 8250.nr_uarts=1" /* don't scan all 8250 UARTS */
- "%s" /* root=appliance_dev */
- " %s" /* selinux */
- " %s" /* quiet/verbose */
- "%s" /* network */
- " TERM=%s" /* TERM environment variable */
- "%s%s" /* handle identifier */
- "%s%s", /* append */
-#ifdef __arm__
- g->memsize,
-#endif
- lpj_s,
- root,
- g->selinux ? "selinux=1 enforcing=0" : "selinux=0",
- g->verbose ? "guestfs_verbose=1" : "quiet",
- g->enable_network ? " guestfs_network=1" : "",
- term ? term : "linux",
- STRNEQ (g->identifier, "") ? " guestfs_identifier="
: "",
- g->identifier,
- g->append ? " " : "", g->append ? g->append :
"");
-
- return ret;
+ /* Display timestamp before kernel messages. */
+ guestfs_int_add_string (g, &argv, "printk.time=1");
+
+ /* Saves us about 5 MB of RAM. */
+ guestfs_int_add_string (g, &argv, "cgroup_disable=memory");
+
+ /* Disable USB, only saves about 1ms. */
+ guestfs_int_add_string (g, &argv, "usbcore.nousb");
+
+ /* Disable crypto tests, saves 28ms. */
+ guestfs_int_add_string (g, &argv, "cryptomgr.notests");
+
+ /* Don't synch TSCs when using SMP. Saves 21ms for each secondary vCPU.
*/
+ guestfs_int_add_string (g, &argv, "tsc=reliable");
+
+ /* Don't scan all 8250 UARTS. */
+ guestfs_int_add_string (g, &argv, "8250.nr_uarts=1");
+
+ /* Tell supermin about the appliance device. */
+ if (appliance_dev)
+ guestfs_int_add_sprintf (g, &argv, "root=%s", appliance_dev);
+
+ /* SELinux - deprecated setting, never worked and should not be enabled. */
+ if (g->selinux)
+ guestfs_int_add_string (g, &argv, "selinux=1 enforcing=0");
+ else
+ guestfs_int_add_string (g, &argv, "selinux=0");
+
+ /* Quiet/verbose. */
+ if (g->verbose)
+ guestfs_int_add_string (g, &argv, "guestfs_verbose=1");
+ else
+ guestfs_int_add_string (g, &argv, "quiet");
+
+ /* Network. */
+ if (g->enable_network)
+ guestfs_int_add_string (g, &argv, "guestfs_network=1");
+
+ /* TERM environment variable. */
+ if (term)
+ guestfs_int_add_sprintf (g, &argv, "TERM=%s", term);
+ else
+ guestfs_int_add_string (g, &argv, "TERM=linux");
+
+ /* Handle identifier. */
+ if (STRNEQ (g->identifier, ""))
+ guestfs_int_add_sprintf (g, &argv, "guestfs_identifier=%s",
g->identifier);
+
+ /* Append extra arguments. */
+ if (g->append)
+ guestfs_int_add_string (g, &argv, g->append);
+
+ guestfs_int_end_stringsbuf (g, &argv);
+
+ /* Caller frees. */
+ return guestfs_int_join_strings (" ", argv.argv);
}
/**
--
2.10.2
Richard W.M. Jones
2016-Dec-18 20:09 UTC
[Libguestfs] [PATCH 2/2] launch: Validate $TERM before passing it through to the kernel command line.
Make sure it is reasonable before we pass it through to the kernel
command line. I don't believe this is exploitable, but it might cause
obscure bugs.
---
src/launch.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/src/launch.c b/src/launch.c
index 84d5e82..ee2a23d 100644
--- a/src/launch.c
+++ b/src/launch.c
@@ -39,6 +39,8 @@
#include <assert.h>
#include <libintl.h>
+#include "c-ctype.h"
+
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
@@ -284,6 +286,28 @@ guestfs_impl_config (guestfs_h *g,
return 0;
}
+/**
+ * Check that the $TERM environment variable is reasonable before
+ * we pass it through to the appliance.
+ */
+static int
+valid_term (const char *term)
+{
+ size_t len = strlen (term);
+
+ if (len == 0 || len > 16)
+ return 0;
+
+ while (len > 0) {
+ char c = *term++;
+ len--;
+ if (!c_isalnum (c) && c != '-' && c != '_')
+ return 0;
+ }
+
+ return 1;
+}
+
#if defined(__powerpc64__)
#define SERIAL_CONSOLE "console=hvc0 console=ttyS0"
#elif defined(__arm__) || defined(__aarch64__)
@@ -425,7 +449,7 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char
*appliance_dev,
guestfs_int_add_string (g, &argv, "guestfs_network=1");
/* TERM environment variable. */
- if (term)
+ if (term && valid_term (term))
guestfs_int_add_sprintf (g, &argv, "TERM=%s", term);
else
guestfs_int_add_string (g, &argv, "TERM=linux");
--
2.10.2
Pino Toscano
2016-Dec-22 16:29 UTC
Re: [Libguestfs] [PATCH 1/2] launch: Rationalize how we construct the Linux kernel command line.
On Sunday, 18 December 2016 20:09:28 CET Richard W.M. Jones wrote:> This is just code refactoring. > ---Mostly LGTM, just one note.> + return guestfs_int_join_strings (" ", argv.argv);Currently, safe_asprintf aborts on ENOMEM errors, while guestfs_int_join_strings just returns NULL on that situation -- most probably the abort callback needs to be invoked manually: char *ret; ... ret = guestfs_int_join_strings (" ", argv.argv); if (ret == NULL) g->abort_cb (); return ret; Thanks, -- Pino Toscano
Pino Toscano
2016-Dec-22 16:50 UTC
Re: [Libguestfs] [PATCH 2/2] launch: Validate $TERM before passing it through to the kernel command line.
On Sunday, 18 December 2016 20:09:29 CET Richard W.M. Jones wrote:> Make sure it is reasonable before we pass it through to the kernel > command line. I don't believe this is exploitable, but it might cause > obscure bugs. > --- > src/launch.c | 26 +++++++++++++++++++++++++- > 1 file changed, 25 insertions(+), 1 deletion(-) > > diff --git a/src/launch.c b/src/launch.c > index 84d5e82..ee2a23d 100644 > --- a/src/launch.c > +++ b/src/launch.c > @@ -39,6 +39,8 @@ > #include <assert.h> > #include <libintl.h> > > +#include "c-ctype.h" > + > #include "guestfs.h" > #include "guestfs-internal.h" > #include "guestfs-internal-actions.h" > @@ -284,6 +286,28 @@ guestfs_impl_config (guestfs_h *g, > return 0; > } > > +/** > + * Check that the $TERM environment variable is reasonable before > + * we pass it through to the appliance. > + */ > +static int > +valid_term (const char *term)I guess the return value can be bool.> +{ > + size_t len = strlen (term); > + > + if (len == 0 || len > 16) > + return 0; > + > + while (len > 0) { > + char c = *term++; > + len--; > + if (!c_isalnum (c) && c != '-' && c != '_') > + return 0; > + }The loop is fine already, maybe the need to use len can be dropped: for (; *term; ++term) { char c = *term; if (!c_isalnum (c) && c != '-' && c != '_') return 0; } Thanks, -- Pino Toscano
Possibly Parallel Threads
- [PATCH 2/2] launch: Validate $TERM before passing it through to the kernel command line.
- [PATCH 1/2] launch: Rationalize how we construct the Linux kernel command line.
- [PATCH] lib: Use a common function to validate strings.
- [PATCH] lib: Use a common function to validate strings.
- Get term from document by position