[Qemu-devel] [PULL v3 1/3] replay: add record/replay for audio passthrough

Gerd Hoffmann posted 3 patches 8 years, 11 months ago
[Qemu-devel] [PULL v3 1/3] replay: add record/replay for audio passthrough
Posted by Gerd Hoffmann 8 years, 11 months ago
From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>

This patch adds recording and replaying audio data. Is saves synchronization
information for audio out and inputs from the microphone.

v2: removed unneeded whitespace change

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-id: 20170202055054.4848.94901.stgit@PASHA-ISP.lan02.inno

[ kraxel: add qemu/error-report.h include to fix osx build failure ]

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 audio/audio.c            |  9 ++++--
 audio/audio.h            |  5 +++
 audio/mixeng.c           | 32 ++++++++++++++++++++
 docs/replay.txt          |  7 +++++
 include/sysemu/replay.h  |  7 +++++
 replay/Makefile.objs     |  1 +
 replay/replay-audio.c    | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
 replay/replay-internal.h |  4 +++
 8 files changed, 142 insertions(+), 2 deletions(-)
 create mode 100644 replay/replay-audio.c

diff --git a/audio/audio.c b/audio/audio.c
index c845a44..21f7b0b 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -28,6 +28,7 @@
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
 #include "qemu/cutils.h"
+#include "sysemu/replay.h"
 
 #define AUDIO_CAP "audio"
 #include "audio_int.h"
@@ -1387,6 +1388,7 @@ static void audio_run_out (AudioState *s)
 
         prev_rpos = hw->rpos;
         played = hw->pcm_ops->run_out (hw, live);
+        replay_audio_out(&played);
         if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
             dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
                    hw->rpos, hw->samples, played);
@@ -1450,9 +1452,12 @@ static void audio_run_in (AudioState *s)
 
     while ((hw = audio_pcm_hw_find_any_enabled_in (hw))) {
         SWVoiceIn *sw;
-        int captured, min;
+        int captured = 0, min;
 
-        captured = hw->pcm_ops->run_in (hw);
+        if (replay_mode != REPLAY_MODE_PLAY) {
+            captured = hw->pcm_ops->run_in(hw);
+        }
+        replay_audio_in(&captured, hw->conv_buf, &hw->wpos, hw->samples);
 
         min = audio_pcm_hw_find_min_in (hw);
         hw->total_samples_captured += captured - min;
diff --git a/audio/audio.h b/audio/audio.h
index c3c5198..f4339a1 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -166,4 +166,9 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
 bool audio_is_cleaning_up(void);
 void audio_cleanup(void);
 
+void audio_sample_to_uint64(void *samples, int pos,
+                            uint64_t *left, uint64_t *right);
+void audio_sample_from_uint64(void *samples, int pos,
+                            uint64_t left, uint64_t right);
+
 #endif /* QEMU_AUDIO_H */
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 66c0328..0bf9b53 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -25,6 +25,7 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "qemu/bswap.h"
+#include "qemu/error-report.h"
 #include "audio.h"
 
 #define AUDIO_CAP "mixeng"
@@ -267,6 +268,37 @@ f_sample *mixeng_clip[2][2][2][3] = {
     }
 };
 
+
+void audio_sample_to_uint64(void *samples, int pos,
+                            uint64_t *left, uint64_t *right)
+{
+    struct st_sample *sample = samples;
+    sample += pos;
+#ifdef FLOAT_MIXENG
+    error_report(
+        "Coreaudio and floating point samples are not supported by replay yet");
+    abort();
+#else
+    *left = sample->l;
+    *right = sample->r;
+#endif
+}
+
+void audio_sample_from_uint64(void *samples, int pos,
+                            uint64_t left, uint64_t right)
+{
+    struct st_sample *sample = samples;
+    sample += pos;
+#ifdef FLOAT_MIXENG
+    error_report(
+        "Coreaudio and floating point samples are not supported by replay yet");
+    abort();
+#else
+    sample->l = left;
+    sample->r = right;
+#endif
+}
+
 /*
  * August 21, 1998
  * Copyright 1998 Fabrice Bellard.
diff --git a/docs/replay.txt b/docs/replay.txt
index 03e1931..486c1e0 100644
--- a/docs/replay.txt
+++ b/docs/replay.txt
@@ -225,3 +225,10 @@ recording the virtual machine this filter puts all packets coming from
 the outer world into the log. In replay mode packets from the log are
 injected into the network device. All interactions with network backend
 in replay mode are disabled.
+
+Audio devices
+-------------
+
+Audio data is recorded and replay automatically. The command line for recording
+and replaying must contain identical specifications of audio hardware, e.g.:
+ -soundhw ac97
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 7aad20b..f1c0712 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -152,6 +152,13 @@ void replay_unregister_net(ReplayNetState *rns);
 void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
                              const struct iovec *iov, int iovcnt);
 
+/* Audio */
+
+/*! Saves/restores number of played samples of audio out operation. */
+void replay_audio_out(int *played);
+/*! Saves/restores recorded samples of audio in operation. */
+void replay_audio_in(int *recorded, void *samples, int *wpos, int size);
+
 /* VM state operations */
 
 /*! Called at the start of execution.
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index b2afd40..cee6539 100644
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -6,3 +6,4 @@ common-obj-y += replay-input.o
 common-obj-y += replay-char.o
 common-obj-y += replay-snapshot.o
 common-obj-y += replay-net.o
+common-obj-y += replay-audio.o
\ No newline at end of file
diff --git a/replay/replay-audio.c b/replay/replay-audio.c
new file mode 100644
index 0000000..3d83743
--- /dev/null
+++ b/replay/replay-audio.c
@@ -0,0 +1,79 @@
+/*
+ * replay-audio.c
+ *
+ * Copyright (c) 2010-2017 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "sysemu/sysemu.h"
+#include "audio/audio.h"
+
+void replay_audio_out(int *played)
+{
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_save_instructions();
+        replay_mutex_lock();
+        replay_put_event(EVENT_AUDIO_OUT);
+        replay_put_dword(*played);
+        replay_mutex_unlock();
+    } else if (replay_mode == REPLAY_MODE_PLAY) {
+        replay_account_executed_instructions();
+        replay_mutex_lock();
+        if (replay_next_event_is(EVENT_AUDIO_OUT)) {
+            *played = replay_get_dword();
+            replay_finish_event();
+            replay_mutex_unlock();
+        } else {
+            replay_mutex_unlock();
+            error_report("Missing audio out event in the replay log");
+            abort();
+        }
+    }
+}
+
+void replay_audio_in(int *recorded, void *samples, int *wpos, int size)
+{
+    int pos;
+    uint64_t left, right;
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_save_instructions();
+        replay_mutex_lock();
+        replay_put_event(EVENT_AUDIO_IN);
+        replay_put_dword(*recorded);
+        replay_put_dword(*wpos);
+        for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
+             ; pos = (pos + 1) % size) {
+            audio_sample_to_uint64(samples, pos, &left, &right);
+            replay_put_qword(left);
+            replay_put_qword(right);
+        }
+        replay_mutex_unlock();
+    } else if (replay_mode == REPLAY_MODE_PLAY) {
+        replay_account_executed_instructions();
+        replay_mutex_lock();
+        if (replay_next_event_is(EVENT_AUDIO_IN)) {
+            *recorded = replay_get_dword();
+            *wpos = replay_get_dword();
+            for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
+                 ; pos = (pos + 1) % size) {
+                left = replay_get_qword();
+                right = replay_get_qword();
+                audio_sample_from_uint64(samples, pos, left, right);
+            }
+            replay_finish_event();
+            replay_mutex_unlock();
+        } else {
+            replay_mutex_unlock();
+            error_report("Missing audio in event in the replay log");
+            abort();
+        }
+    }
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index c26d079..ed66ed8 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -29,6 +29,10 @@ enum ReplayEvents {
     /* for character device read all event */
     EVENT_CHAR_READ_ALL,
     EVENT_CHAR_READ_ALL_ERROR,
+    /* for audio out event */
+    EVENT_AUDIO_OUT,
+    /* for audio in event */
+    EVENT_AUDIO_IN,
     /* for clock read/writes */
     /* some of greater codes are reserved for clocks */
     EVENT_CLOCK,
-- 
1.8.3.1


Re: [Qemu-devel] [PULL v3 1/3] replay: add record/replay for audio passthrough
Posted by Peter Maydell 7 years, 9 months ago
On 1 March 2017 at 15:40, Gerd Hoffmann <kraxel@redhat.com> wrote:
> From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
>
> This patch adds recording and replaying audio data. Is saves synchronization
> information for audio out and inputs from the microphone.
>
> v2: removed unneeded whitespace change
>
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> Message-id: 20170202055054.4848.94901.stgit@PASHA-ISP.lan02.inno
>
> [ kraxel: add qemu/error-report.h include to fix osx build failure ]
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  audio/audio.c            |  9 ++++--
>  audio/audio.h            |  5 +++
>  audio/mixeng.c           | 32 ++++++++++++++++++++
>  docs/replay.txt          |  7 +++++
>  include/sysemu/replay.h  |  7 +++++
>  replay/Makefile.objs     |  1 +
>  replay/replay-audio.c    | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
>  replay/replay-internal.h |  4 +++
>  8 files changed, 142 insertions(+), 2 deletions(-)
>  create mode 100644 replay/replay-audio.c
>
> diff --git a/audio/audio.c b/audio/audio.c
> index c845a44..21f7b0b 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -28,6 +28,7 @@
>  #include "qemu/timer.h"
>  #include "sysemu/sysemu.h"
>  #include "qemu/cutils.h"
> +#include "sysemu/replay.h"
>
>  #define AUDIO_CAP "audio"
>  #include "audio_int.h"
> @@ -1387,6 +1388,7 @@ static void audio_run_out (AudioState *s)
>
>          prev_rpos = hw->rpos;
>          played = hw->pcm_ops->run_out (hw, live);
> +        replay_audio_out(&played);
>          if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
>              dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
>                     hw->rpos, hw->samples, played);

Hi. Coverity produces a new warning because of this change (CID1390632),
because it treats the replay file as "tainted data", and complains
that we trust a value from the file to become a sample count
passed to audio_capture_mix_and_clear() and eventually used as
a byte count for a memset.

Do we trust the replay file to be non-malicious (making this
a false-positive), or not (in which case we need to sanitize
or check its contents somehow) ?

thanks
-- PMM

Re: [Qemu-devel] [PULL v3 1/3] replay: add record/replay for audio passthrough
Posted by Pavel Dovgalyuk 7 years, 9 months ago
> From: Peter Maydell [mailto:peter.maydell@linaro.org]
> On 1 March 2017 at 15:40, Gerd Hoffmann <kraxel@redhat.com> wrote:
> > From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> >
> > This patch adds recording and replaying audio data. Is saves synchronization
> > information for audio out and inputs from the microphone.
> >
> > v2: removed unneeded whitespace change
> >
> > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> > Message-id: 20170202055054.4848.94901.stgit@PASHA-ISP.lan02.inno
> >
> > [ kraxel: add qemu/error-report.h include to fix osx build failure ]
> >
> > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> > ---
> >  audio/audio.c            |  9 ++++--
> >  audio/audio.h            |  5 +++
> >  audio/mixeng.c           | 32 ++++++++++++++++++++
> >  docs/replay.txt          |  7 +++++
> >  include/sysemu/replay.h  |  7 +++++
> >  replay/Makefile.objs     |  1 +
> >  replay/replay-audio.c    | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  replay/replay-internal.h |  4 +++
> >  8 files changed, 142 insertions(+), 2 deletions(-)
> >  create mode 100644 replay/replay-audio.c
> >
> > diff --git a/audio/audio.c b/audio/audio.c
> > index c845a44..21f7b0b 100644
> > --- a/audio/audio.c
> > +++ b/audio/audio.c
> > @@ -28,6 +28,7 @@
> >  #include "qemu/timer.h"
> >  #include "sysemu/sysemu.h"
> >  #include "qemu/cutils.h"
> > +#include "sysemu/replay.h"
> >
> >  #define AUDIO_CAP "audio"
> >  #include "audio_int.h"
> > @@ -1387,6 +1388,7 @@ static void audio_run_out (AudioState *s)
> >
> >          prev_rpos = hw->rpos;
> >          played = hw->pcm_ops->run_out (hw, live);
> > +        replay_audio_out(&played);
> >          if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
> >              dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
> >                     hw->rpos, hw->samples, played);
> 
> Hi. Coverity produces a new warning because of this change (CID1390632),
> because it treats the replay file as "tainted data", and complains
> that we trust a value from the file to become a sample count
> passed to audio_capture_mix_and_clear() and eventually used as
> a byte count for a memset.
> 
> Do we trust the replay file to be non-malicious (making this
> a false-positive), or not (in which case we need to sanitize
> or check its contents somehow) ?

Replay file is generated by QEMU and does not affected by the guest system directly.
This file is used by the developer himself (e.g., recording and replaying execution
on the same machine for the analysis or debugging).
Replay file can also be used by testers for bug reporting (e.g., to send bug
reproduction scenario to the developer).

In the case of transferring the file it can be used as an exploit.
But I cannot judge is it a real threat or just inessential one.

Pavel Dovgalyuk


Re: [Qemu-devel] [PULL v3 1/3] replay: add record/replay for audio passthrough
Posted by Peter Maydell 7 years, 9 months ago
On 27 April 2018 at 13:28, Pavel Dovgalyuk <dovgaluk@ispras.ru> wrote:
>> From: Peter Maydell [mailto:peter.maydell@linaro.org]
>> Hi. Coverity produces a new warning because of this change (CID1390632),
>> because it treats the replay file as "tainted data", and complains
>> that we trust a value from the file to become a sample count
>> passed to audio_capture_mix_and_clear() and eventually used as
>> a byte count for a memset.
>>
>> Do we trust the replay file to be non-malicious (making this
>> a false-positive), or not (in which case we need to sanitize
>> or check its contents somehow) ?
>
> Replay file is generated by QEMU and does not affected by the guest system directly.
> This file is used by the developer himself (e.g., recording and replaying execution
> on the same machine for the analysis or debugging).
> Replay file can also be used by testers for bug reporting (e.g., to send bug
> reproduction scenario to the developer).
>
> In the case of transferring the file it can be used as an exploit.
> But I cannot judge is it a real threat or just inessential one.

Thanks for the explanation. I think we should consider the
replay file to be trusted -- it's a developer convenience, it's
only relevant to TCG, and it's not something that's going to
typically be passed around. I'll mark the relevant Coverity
complaints as false-positives.

-- PMM

Re: [Qemu-devel] [PULL v3 1/3] replay: add record/replay for audio passthrough
Posted by Alex Bennée 8 years, 10 months ago
Gerd Hoffmann <kraxel@redhat.com> writes:

> From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
>
> This patch adds recording and replaying audio data. Is saves synchronization
> information for audio out and inputs from the microphone.
>
> v2: removed unneeded whitespace change
>
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> Message-id: 20170202055054.4848.94901.stgit@PASHA-ISP.lan02.inno
>
> [ kraxel: add qemu/error-report.h include to fix osx build failure ]
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  audio/audio.c            |  9 ++++--
>  audio/audio.h            |  5 +++
>  audio/mixeng.c           | 32 ++++++++++++++++++++
>  docs/replay.txt          |  7 +++++
>  include/sysemu/replay.h  |  7 +++++
>  replay/Makefile.objs     |  1 +
>  replay/replay-audio.c    | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
>  replay/replay-internal.h |  4 +++
>  8 files changed, 142 insertions(+), 2 deletions(-)
>  create mode 100644 replay/replay-audio.c
>
<snip>
> diff --git a/replay/replay-internal.h b/replay/replay-internal.h
> index c26d079..ed66ed8 100644
> --- a/replay/replay-internal.h
> +++ b/replay/replay-internal.h
> @@ -29,6 +29,10 @@ enum ReplayEvents {
>      /* for character device read all event */
>      EVENT_CHAR_READ_ALL,
>      EVENT_CHAR_READ_ALL_ERROR,
> +    /* for audio out event */
> +    EVENT_AUDIO_OUT,
> +    /* for audio in event */
> +    EVENT_AUDIO_IN,
>      /* for clock read/writes */
>      /* some of greater codes are reserved for clocks */
>      EVENT_CLOCK,

Well one thing I noticed while I was trying to work out the difference
between pre/post mttcg replay problems is the log format ABI has
changed. REPLAY_VERSION needs to be bumped to prevent confusion.

--
Alex Bennée

Re: [Qemu-devel] [PULL v3 1/3] replay: add record/replay for audio passthrough
Posted by Pavel Dovgalyuk 8 years, 10 months ago
> From: Alex Bennée [mailto:alex.bennee@linaro.org]
> > From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> >
> > This patch adds recording and replaying audio data. Is saves synchronization
> > information for audio out and inputs from the microphone.
> >
> > v2: removed unneeded whitespace change
> >
> > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> > Message-id: 20170202055054.4848.94901.stgit@PASHA-ISP.lan02.inno
> >
> > [ kraxel: add qemu/error-report.h include to fix osx build failure ]
> >
> > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> > ---
> >  audio/audio.c            |  9 ++++--
> >  audio/audio.h            |  5 +++
> >  audio/mixeng.c           | 32 ++++++++++++++++++++
> >  docs/replay.txt          |  7 +++++
> >  include/sysemu/replay.h  |  7 +++++
> >  replay/Makefile.objs     |  1 +
> >  replay/replay-audio.c    | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
> >  replay/replay-internal.h |  4 +++
> >  8 files changed, 142 insertions(+), 2 deletions(-)
> >  create mode 100644 replay/replay-audio.c
> >
> <snip>
> > diff --git a/replay/replay-internal.h b/replay/replay-internal.h
> > index c26d079..ed66ed8 100644
> > --- a/replay/replay-internal.h
> > +++ b/replay/replay-internal.h
> > @@ -29,6 +29,10 @@ enum ReplayEvents {
> >      /* for character device read all event */
> >      EVENT_CHAR_READ_ALL,
> >      EVENT_CHAR_READ_ALL_ERROR,
> > +    /* for audio out event */
> > +    EVENT_AUDIO_OUT,
> > +    /* for audio in event */
> > +    EVENT_AUDIO_IN,
> >      /* for clock read/writes */
> >      /* some of greater codes are reserved for clocks */
> >      EVENT_CLOCK,
> 
> Well one thing I noticed while I was trying to work out the difference
> between pre/post mttcg replay problems is the log format ABI has
> changed. REPLAY_VERSION needs to be bumped to prevent confusion.

Right, I missed that while sending the patches.

Pavel Dovgalyuk