[Libguestfs] [PATCH] Replace shell_quote function with %Q and %R printf specifiers.
Richard W.M. Jones
rjones at redhat.com
Mon Jul 27 21:42:17 UTC 2009
At the moment the daemon code contains an incredibly hairy function
called shell_quote for safely quoting strings passed to the shell.
The patch replaces that with a glibc custom printf format (actually
two, but very closely related), %Q and %R.
%Q is like %s but it safely shell quotes the string.
%R is like %Q but it prefixes the path with /sysroot.
Example usage (w/o error checks):
asprintf (&cmd, "zcat %R | tar xvf -", path);
==> "zcat /sysroot/path\ with\ spaces | tar xvf -"
Rich.
[One of the nice things about OCaml is this sort of safe shell quoting
is built in to the stdlib functions].
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
Read my programming blog: http://rwmj.wordpress.com
Fedora now supports 75 OCaml packages (the OPEN alternative to F#)
http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
-------------- next part --------------
>From fcc190a856a537bb1ca429714e54468ca3514f33 Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at trick.home.annexia.org>
Date: Mon, 27 Jul 2009 22:27:45 +0100
Subject: [PATCH 1/2] Replace shell_quote function with %Q and %R printf specifiers.
%Q => simple shell quoted string
%R => path will be prefixed by /sysroot
eg. snprintf (cmd, sizeof cmd, "cat %R", path); system (cmd);
---
daemon/daemon.h | 17 ++++++++++++-
daemon/file.c | 24 ++++++++-----------
daemon/find.c | 11 +-------
daemon/grub.c | 9 ++-----
daemon/guestfsd.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++
daemon/initrd.c | 16 ++++---------
daemon/tar.c | 60 +++++++++++++++++++-----------------------------
7 files changed, 124 insertions(+), 78 deletions(-)
diff --git a/daemon/daemon.h b/daemon/daemon.h
index c2bbf3e..2ab1574 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -54,12 +54,25 @@ extern int commandrv (char **stdoutput, char **stderror,
extern char **split_lines (char *str);
-extern int shell_quote (char *out, int len, const char *in);
-
extern int device_name_translation (char *device, const char *func);
extern void udev_settle (void);
+/* This just stops gcc from giving a warning about our custom
+ * printf formatters %Q and %R.
+ */
+static inline int
+asprintf_nowarn (char **strp, const char *fmt, ...)
+{
+ int r;
+ va_list args;
+
+ va_start (args, fmt);
+ r = vasprintf (strp, fmt, args);
+ va_end (args);
+ return r;
+}
+
/*-- in names.c (auto-generated) --*/
extern const char *function_names[];
diff --git a/daemon/file.c b/daemon/file.c
index 7c46722..6062c50 100644
--- a/daemon/file.c
+++ b/daemon/file.c
@@ -440,6 +440,7 @@ char *
do_zfile (char *method, char *path)
{
int len;
+ const char *zcat;
char *cmd;
FILE *fp;
char line[256];
@@ -447,27 +448,22 @@ do_zfile (char *method, char *path)
NEED_ROOT (NULL);
ABS_PATH (path, NULL);
- len = 2 * strlen (path) + sysroot_len + 64;
- cmd = malloc (len);
- if (!cmd) {
- reply_with_perror ("malloc");
- return NULL;
- }
-
if (strcmp (method, "gzip") == 0 || strcmp (method, "compress") == 0)
- strcpy (cmd, "zcat");
+ zcat = "zcat";
else if (strcmp (method, "bzip2") == 0)
- strcpy (cmd, "bzcat");
+ zcat = "bzcat";
else {
- free (cmd);
reply_with_error ("zfile: unknown method");
return NULL;
}
- strcat (cmd, " ");
- strcat (cmd, sysroot);
- shell_quote (cmd + strlen (cmd), len - strlen (cmd), path);
- strcat (cmd, " | file -bsL -");
+ if (asprintf_nowarn (&cmd, "%s %R | file -bsL -", zcat, path) == -1) {
+ reply_with_perror ("asprintf");
+ return NULL;
+ }
+
+ if (verbose)
+ fprintf (stderr, "%s\n", cmd);
fp = popen (cmd, "r");
if (fp == NULL) {
diff --git a/daemon/find.c b/daemon/find.c
index d882953..40f1b3b 100644
--- a/daemon/find.c
+++ b/daemon/find.c
@@ -83,21 +83,14 @@ do_find (char *dir)
sysrootdirlen = strlen (sysrootdir);
/* Assemble the external find command. */
- len = 2 * sysrootdirlen + 32;
- cmd = malloc (len);
- if (!cmd) {
+ if (asprintf_nowarn (&cmd, "find %Q -print0", sysrootdir) == -1) {
reply_with_perror ("malloc");
free (sysrootdir);
return NULL;
}
- strcpy (cmd, "find ");
- shell_quote (cmd+5, len-5, sysrootdir);
- free (sysrootdir);
- strcat (cmd, " -print0");
-
if (verbose)
- printf ("%s\n", cmd);
+ fprintf (stderr, "%s\n", cmd);
fp = popen (cmd, "r");
if (fp == NULL) {
diff --git a/daemon/grub.c b/daemon/grub.c
index 3b1768f..86e812e 100644
--- a/daemon/grub.c
+++ b/daemon/grub.c
@@ -28,7 +28,7 @@
int
do_grub_install (char *root, char *device)
{
- int r, len;
+ int r;
char *err;
char *buf;
@@ -36,13 +36,10 @@ do_grub_install (char *root, char *device)
ABS_PATH (root, -1);
IS_DEVICE (device, -1);
- len = strlen (root) + sysroot_len + 64;
- buf = malloc (len);
- if (!buf) {
- reply_with_perror ("malloc");
+ if (asprintf_nowarn (&buf, "--root-directory=%R", root) == -1) {
+ reply_with_perror ("asprintf");
return -1;
}
- snprintf (buf, len, "--root-directory=%s%s", sysroot, root);
r = command (NULL, &err, "/sbin/grub-install", buf, device, NULL);
free (buf);
diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c
index 5c250f0..6c044b6 100644
--- a/daemon/guestfsd.c
+++ b/daemon/guestfsd.c
@@ -36,6 +36,7 @@
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
+#include <printf.h>
#include "daemon.h"
@@ -47,6 +48,10 @@ static void usage (void);
int verbose = 0;
+static int print_shell_quote (FILE *stream, const struct printf_info *info, const void *const *args);
+static int print_sysroot_shell_quote (FILE *stream, const struct printf_info *info, const void *const *args);
+static int print_arginfo (const struct printf_info *info, size_t n, int *argtypes, int *size);
+
/* Location to mount root device. */
const char *sysroot = "/sysroot"; /* No trailing slash. */
int sysroot_len = 8;
@@ -76,6 +81,10 @@ main (int argc, char *argv[])
uint32_t len;
struct sigaction sa;
+ /* http://udrepper.livejournal.com/20948.html */
+ register_printf_specifier ('Q', print_shell_quote, print_arginfo);
+ register_printf_specifier ('R', print_sysroot_shell_quote, print_arginfo);
+
for (;;) {
c = getopt_long (argc, argv, options, long_options, NULL);
if (c == -1) break;
@@ -229,6 +238,8 @@ main (int argc, char *argv[])
*
* Caller must check for NULL and call reply_with_perror ("malloc")
* if it is. Caller must also free the string.
+ *
+ * See also the custom %R printf formatter which does shell quoting too.
*/
char *
sysroot_path (const char *path)
@@ -685,6 +696,59 @@ split_lines (char *str)
return lines;
}
+/* printf helper function so we can use %Q ("quoted") and %R to print
+ * shell-quoted strings.
+ *
+ * %Q => simple shell quoted string
+ * %R => path will be prefixed by /sysroot
+ *
+ * eg. snprintf (cmd, sizeof cmd, "cat %R", path); system (cmd);
+ */
+static int
+print_shell_quote (FILE *stream,
+ const struct printf_info *info,
+ const void *const *args)
+{
+#define SAFE(c) (isalnum((c)) || \
+ (c) == '/' || (c) == '-' || (c) == '_' || (c) == '.')
+ int i, len;
+ const char *str = *((const char **) (args[0]));
+
+ for (i = len = 0; str[i]; ++i) {
+ if (!SAFE(str[i])) {
+ putc ('\\', stream);
+ len ++;
+ }
+ putc (str[i], stream);
+ len ++;
+ }
+
+ return len;
+}
+
+static int
+print_sysroot_shell_quote (FILE *stream,
+ const struct printf_info *info,
+ const void *const *args)
+{
+#define SAFE(c) (isalnum((c)) || \
+ (c) == '/' || (c) == '-' || (c) == '_' || (c) == '.')
+ fputs (sysroot, stream);
+ return sysroot_len + print_shell_quote (stream, info, args);
+}
+
+static int
+print_arginfo (const struct printf_info *info,
+ size_t n, int *argtypes, int *size)
+{
+ if (n > 0) {
+ argtypes[0] = PA_STRING;
+ size[0] = sizeof (const char *);
+ }
+ return 1;
+}
+
+#if 0
/* Quote 'in' for the shell, and write max len-1 bytes to out. The
* result will be NUL-terminated, even if it is truncated.
*
@@ -721,6 +785,7 @@ shell_quote (char *out, int len, const char *in)
return outlen;
}
+#endif
/* Perform device name translation. Don't call this directly -
* use the IS_DEVICE macro.
diff --git a/daemon/initrd.c b/daemon/initrd.c
index 392b811..59749bb 100644
--- a/daemon/initrd.c
+++ b/daemon/initrd.c
@@ -31,29 +31,23 @@ char **
do_initrd_list (char *path)
{
FILE *fp;
- int len;
char *cmd;
char filename[PATH_MAX];
char **filenames = NULL;
int size = 0, alloc = 0;
+ size_t len;
NEED_ROOT (NULL);
ABS_PATH (path, NULL);
/* "zcat /sysroot/<path> | cpio --quiet -it", but path must be quoted. */
- len = 64 + sysroot_len + 2 * strlen (path);
- cmd = malloc (len);
- if (!cmd) {
- reply_with_perror ("malloc");
+ if (asprintf_nowarn (&cmd, "zcat %R | cpio --quiet -it", path) == -1) {
+ reply_with_perror ("asprintf");
return NULL;
}
- strcpy (cmd, "zcat ");
- strcat (cmd, sysroot);
- shell_quote (cmd+13, len-13, path);
- strcat (cmd, " | cpio --quiet -it");
-
- fprintf (stderr, "%s\n", cmd);
+ if (verbose)
+ fprintf (stderr, "%s\n", cmd);
fp = popen (cmd, "r");
if (fp == NULL) {
diff --git a/daemon/tar.c b/daemon/tar.c
index 3008574..39b983c 100644
--- a/daemon/tar.c
+++ b/daemon/tar.c
@@ -38,7 +38,7 @@ fwrite_cb (void *fp_ptr, const void *buf, int len)
int
do_tar_in (char *dir)
{
- int err, r, len;
+ int err, r;
FILE *fp;
char *cmd;
@@ -49,19 +49,16 @@ do_tar_in (char *dir)
}
/* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
- len = 2 * strlen (dir) + sysroot_len + 32;
- cmd = malloc (len);
- if (!cmd) {
+ if (asprintf_nowarn (&cmd, "tar -C %R -xf -", dir) == -1) {
err = errno;
cancel_receive ();
errno = err;
- reply_with_perror ("malloc");
+ reply_with_perror ("asprintf");
return -1;
}
- strcpy (cmd, "tar -C ");
- strcat (cmd, sysroot);
- shell_quote (cmd+15, len-15, dir);
- strcat (cmd, " -xf -");
+
+ if (verbose)
+ fprintf (stderr, "%s\n", cmd);
fp = popen (cmd, "w");
if (fp == NULL) {
@@ -104,7 +101,7 @@ do_tar_in (char *dir)
int
do_tar_out (char *dir)
{
- int r, len;
+ int r;
FILE *fp;
char *cmd;
char buf[GUESTFS_MAX_CHUNK_SIZE];
@@ -113,16 +110,13 @@ do_tar_out (char *dir)
ABS_PATH (dir, -1);
/* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
- len = 2 * strlen (dir) + sysroot_len + 32;
- cmd = malloc (len);
- if (!cmd) {
- reply_with_perror ("malloc");
+ if (asprintf_nowarn (&cmd, "tar -C %R -cf - .", dir) == -1) {
+ reply_with_perror ("asprintf");
return -1;
}
- strcpy (cmd, "tar -C ");
- strcat (cmd, sysroot);
- shell_quote (cmd+15, len-15, dir);
- strcat (cmd, " -cf - .");
+
+ if (verbose)
+ fprintf (stderr, "%s\n", cmd);
fp = popen (cmd, "r");
if (fp == NULL) {
@@ -166,7 +160,7 @@ do_tar_out (char *dir)
int
do_tgz_in (char *dir)
{
- int err, r, len;
+ int err, r;
FILE *fp;
char *cmd;
@@ -177,19 +171,16 @@ do_tgz_in (char *dir)
}
/* "tar -C /sysroot%s -zxf -" but we have to quote the dir. */
- len = 2 * strlen (dir) + sysroot_len + 32;
- cmd = malloc (len);
- if (!cmd) {
+ if (asprintf_nowarn (&cmd, "tar -C %R -zxf -", dir) == -1) {
err = errno;
cancel_receive ();
errno = err;
- reply_with_perror ("malloc");
+ reply_with_perror ("asprintf");
return -1;
}
- strcpy (cmd, "tar -C ");
- strcat (cmd, sysroot);
- shell_quote (cmd+15, len-15, dir);
- strcat (cmd, " -zxf -");
+
+ if (verbose)
+ fprintf (stderr, "%s\n", cmd);
fp = popen (cmd, "w");
if (fp == NULL) {
@@ -232,7 +223,7 @@ do_tgz_in (char *dir)
int
do_tgz_out (char *dir)
{
- int r, len;
+ int r;
FILE *fp;
char *cmd;
char buf[GUESTFS_MAX_CHUNK_SIZE];
@@ -241,16 +232,13 @@ do_tgz_out (char *dir)
ABS_PATH (dir, -1);
/* "tar -C /sysroot%s -zcf - ." but we have to quote the dir. */
- len = 2 * strlen (dir) + sysroot_len + 32;
- cmd = malloc (len);
- if (!cmd) {
- reply_with_perror ("malloc");
+ if (asprintf_nowarn (&cmd, "tar -C %R -zcf - .", dir) == -1) {
+ reply_with_perror ("asprintf");
return -1;
}
- strcpy (cmd, "tar -C ");
- strcat (cmd, sysroot);
- shell_quote (cmd+15, len-15, dir);
- strcat (cmd, " -zcf - .");
+
+ if (verbose)
+ fprintf (stderr, "%s\n", cmd);
fp = popen (cmd, "r");
if (fp == NULL) {
--
1.6.2.5
More information about the Libguestfs
mailing list