All of lore.kernel.org
 help / color / mirror / Atom feed
From: P J P <ppandit@redhat.com>
To: QEMU Developers <qemu-devel@nongnu.org>
Cc: "Daniel P . Berrange" <berrange@redhat.com>,
	Michael Roth <mdroth@linux.vnet.ibm.com>,
	Niu Guoxiang <niuguoxiang@huawei.com>,
	Prasad J Pandit <pjp@fedoraproject.org>
Subject: [Qemu-devel] [PATCH v2] qga: check length of command-line & environment variables
Date: Sun, 19 May 2019 14:18:15 +0530	[thread overview]
Message-ID: <20190519084815.7410-1-ppandit@redhat.com> (raw)

From: Prasad J Pandit <pjp@fedoraproject.org>

Qemu guest agent while executing user commands does not seem to
check length of argument list and/or environment variables passed.
It may lead to integer overflow or infinite loop issues. Add check
to avoid it.

Reported-by: Niu Guoxiang <niuguoxiang@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
 qga/commands-posix.c   | 18 ++++++++++++++++++
 qga/commands-win32.c   | 13 +++++++++++++
 qga/commands.c         |  8 ++++++--
 qga/guest-agent-core.h |  2 ++
 4 files changed, 39 insertions(+), 2 deletions(-)

Update v2: add helper function ga_get_arg_max()
  -> https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg06360.html

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 7ee6a33cce..e0455722e0 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -60,6 +60,24 @@ extern char **environ;
 #endif
 #endif
 
+size_t ga_get_arg_max(void)
+{
+    /* Since kernel 2.6.23, most architectures support argument size limit
+     * derived from the soft RLIMIT_STACK resource limit (see getrlimit(2)).
+     * For these architectures, the total size is limited to 1/4 of the
+     * allowed stack size. (see execve(2))
+     *
+     * struct rlimit r;
+     *
+     * getrlimit(RLIMIT_STACK, &r);
+     * ARG_MAX = r.rlim_cur / 4;
+     *
+     * ARG_MAX is _NOT_ the maximum number of arguments. It is size of the
+     * memory used to hold command line arguments and environment variables.
+     */
+    return sysconf(_SC_ARG_MAX);
+}
+
 static void ga_wait_child(pid_t pid, int *status, Error **errp)
 {
     pid_t rpid;
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 6b67f16faf..47bbddd74a 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -92,6 +92,19 @@ static OpenFlags guest_file_open_modes[] = {
     g_free(suffix); \
 } while (0)
 
+size_t ga_get_arg_max(void)
+{
+    /* Win32 environment has different values for the ARG_MAX constant.
+     * We'll go with the maximum here.
+     *
+     * https://devblogs.microsoft.com/oldnewthing/?p=41553
+     *
+     * ARG_MAX is _NOT_ the maximum number of arguments. It is size of the
+     * memory used to hold command line arguments and environment variables.
+     */
+    return 32767;
+}
+
 static OpenFlags *find_open_flag(const char *mode_str)
 {
     int mode;
diff --git a/qga/commands.c b/qga/commands.c
index 0c7d1385c2..425a4c405f 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -231,17 +231,21 @@ static char **guest_exec_get_args(const strList *entry, bool log)
     int count = 1, i = 0;  /* reserve for NULL terminator */
     char **args;
     char *str; /* for logging array of arguments */
-    size_t str_size = 1;
+    size_t str_size = 1, arg_max;
 
+    arg_max = ga_get_arg_max();
     for (it = entry; it != NULL; it = it->next) {
         count++;
         str_size += 1 + strlen(it->value);
+        if (str_size >= arg_max || count >= arg_max / 2) {
+            break;
+        }
     }
 
     str = g_malloc(str_size);
     *str = 0;
     args = g_malloc(count * sizeof(char *));
-    for (it = entry; it != NULL; it = it->next) {
+    for (it = entry; it != NULL && i < count; it = it->next) {
         args[i++] = it->value;
         pstrcat(str, str_size, it->value);
         if (it->next) {
diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
index 60eae16f27..300ff7e482 100644
--- a/qga/guest-agent-core.h
+++ b/qga/guest-agent-core.h
@@ -46,6 +46,8 @@ const char *ga_fsfreeze_hook(GAState *s);
 int64_t ga_get_fd_handle(GAState *s, Error **errp);
 int ga_parse_whence(GuestFileWhence *whence, Error **errp);
 
+size_t ga_get_arg_max(void);
+
 #ifndef _WIN32
 void reopen_fd_to_null(int fd);
 #endif
-- 
2.20.1



             reply	other threads:[~2019-05-19  8:56 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-19  8:48 P J P [this message]
2019-05-20 18:22 ` [Qemu-devel] [PATCH v2] qga: check length of command-line & environment variables Daniel Henrique Barboza
2019-05-22 13:34 ` Marc-André Lureau
2019-05-23  7:53   ` P J P
2019-05-23 12:05     ` Marc-André Lureau
2019-05-29  9:38       ` P J P
2019-05-29 11:47         ` Marc-André Lureau
2019-05-29 14:35           ` P J P
2019-05-29 14:44             ` Marc-André Lureau
2019-05-29 17:40               ` P J P

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190519084815.7410-1-ppandit@redhat.com \
    --to=ppandit@redhat.com \
    --cc=berrange@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=niuguoxiang@huawei.com \
    --cc=pjp@fedoraproject.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.