Compare commits

...

72 Commits

Author SHA1 Message Date
85e0a3f630 fix comment 2022-09-07 21:29:56 +02:00
ab54074925 TESTING: add some code for instrumentation tests 2022-07-10 16:21:02 +02:00
f5b92c8907 new example in main 2022-07-10 16:18:46 +02:00
f438967783 extend libafl_exec_jmp_hook 2022-05-26 23:57:34 +02:00
3493dfa219 start interrupt timer on start 2022-05-04 22:58:30 +02:00
a5a49c3292 add hard-coded libafl_exec_systick_hook 2022-04-26 00:29:18 +02:00
8a379ba198 add libafl_send_irq 2022-04-19 23:44:36 +02:00
6ffc2bbe4f bugfix 2022-04-18 13:46:21 +02:00
0cf10fb0ff add jmp instrumentation 2022-04-11 22:56:11 +02:00
404cb91655 use libafl_gen_jmp 2022-04-08 00:54:21 +02:00
ff823f26ff save edges after interrupts 2022-04-06 21:16:15 +02:00
80af255c2e add native remove breakpoint 2022-02-06 20:50:16 +01:00
e62b0072ea switch to icount_get_raw 2022-02-01 15:00:06 +01:00
6ec50ee9c3 add libafl_get_clock 2022-01-31 19:42:07 +01:00
88a0358a4e ignore binaries 2022-01-28 12:22:43 +01:00
78dac2f524 add starters 2022-01-28 10:34:05 +01:00
9caef2e60f Fix tb->icount > TCG_MAX_INSNS for edges
Aparently tcg_tb_alloc does not return a 0ed field,
which can cause icount to appear to have a value above the
maximum allowed number of instructions per tb.
2022-01-15 23:33:33 +01:00
b781a3ebce EXPERIMENT: don't flush tbs on loadvm
This should speed up fuzzing somewhat, but could also create
use-after-free bugs.
2022-01-09 22:44:41 +01:00
5a1cf4d873 Add softmmu instumentation
Break up the control flow from softmmu/main.c:main to be called as a
library.
For now use gdb style breakpoints and native snapshots.
This keeps compatability with user-mode code.
2022-01-09 22:30:34 +01:00
c1dba1b39d backport libafl to v6.1.1
libafl state: fa2b9c4a25f548f15b3d1b1afcfdb75cc7165f9a
2022-01-09 13:20:46 +01:00
Michael Roth
54e1f5be86 Update version for v6.1.1 release
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-23 09:52:09 -06:00
Cole Robinson
fddd169de5 tests: tcg: Fix PVH test with binutils 2.36+
binutils started adding a .note.gnu.property ELF section which
makes the PVH test fail:

  TEST    hello on x86_64
qemu-system-x86_64: Error loading uncompressed kernel without PVH ELF Note

Discard .note.gnu* while keeping the PVH .note bits intact.

This also strips the build-id note, so drop the related comment.

Signed-off-by: Cole Robinson <crobinso@redhat.com>
Message-Id: <5ab2a54c262c61f64c22dbb49ade3e2db8a740bb.1633708346.git.crobinso@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 8e751e9c38e324737fd3d3aa0562f886313bba3c)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-15 07:13:37 -06:00
Richard Henderson
711bd602cc tcg/arm: Reduce vector alignment requirement for NEON
With arm32, the ABI gives us 8-byte alignment for the stack.
While it's possible to realign the stack to provide 16-byte alignment,
it's far easier to simply not encode 16-byte alignment in the
VLD1 and VST1 instructions that we emit.

Remove the assertion in temp_allocate_frame, limit natural alignment
to the provided stack alignment, and add a comment.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1999878
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20210912174925.200132-1-richard.henderson@linaro.org>
Message-Id: <20211206191335.230683-2-richard.henderson@linaro.org>
(cherry picked from commit b9537d5904f6e3df896264a6144883ab07db9608)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-15 07:13:27 -06:00
Daniel P. Berrangé
e88636b4d4 target/i386: add missing bits to CR4_RESERVED_MASK
Booting Fedora kernels with -cpu max hangs very early in boot. Disabling
the la57 CPUID bit fixes the problem. git bisect traced the regression to

  commit 213ff024a2f92020290296cb9dc29c2af3d4a221 (HEAD, refs/bisect/bad)
  Author: Lara Lazier <laramglazier@gmail.com>
  Date:   Wed Jul 21 17:26:50 2021 +0200

    target/i386: Added consistency checks for CR4

    All MBZ bits in CR4 must be zero. (APM2 15.5)
    Added reserved bitmask and added checks in both
    helper_vmrun and helper_write_crN.

    Signed-off-by: Lara Lazier <laramglazier@gmail.com>
    Message-Id: <20210721152651.14683-2-laramglazier@gmail.com>
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

In this commit CR4_RESERVED_MASK is missing CR4_LA57_MASK and
two others. Adding this lets Fedora kernels boot once again.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Message-Id: <20210831175033.175584-1-berrange@redhat.com>
[Removed VMXE/SMXE, matching the commit message. - Paolo]
Fixes: 213ff024a2 ("target/i386: Added consistency checks for CR4", 2021-07-22)
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 69e3895f9d37ca39536775b13ce63e8c291427ba)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-15 07:13:18 -06:00
Gerd Hoffmann
34833f361b qxl: fix pre-save logic
Oops.  Logic is backwards.

Fixes: 39b8a183e2f3 ("qxl: remove assert in qxl_pre_save.")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/610
Resolves: https://bugzilla.redhat.com//show_bug.cgi?id=2002907
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20210910094203.3582378-1-kraxel@redhat.com>
(cherry picked from commit eb94846280df3f1e2a91b6179fc05f9890b7e384)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-15 07:13:12 -06:00
Jon Maloy
43583f0c07 e1000: fix tx re-entrancy problem
The fact that the MMIO handler is not re-entrant causes an infinite
loop under certain conditions:

Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX

We now eliminate the effect of this problem locally in e1000, by adding
a boolean in struct E1000State indicating when the TX side is busy. This
will cause any entering new call to return early instead of interfering
with the ongoing work, and eliminates any risk of looping.

This is intended to address CVE-2021-20257.

Signed-off-by: Jon Maloy <jmaloy@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit 25ddb946e6301f42cff3094ea1c25fb78813e7e9)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 17:40:06 -06:00
Prasad J Pandit
1ce084af08 net: vmxnet3: validate configuration values during activate (CVE-2021-20203)
While activating device in vmxnet3_acticate_device(), it does not
validate guest supplied configuration values against predefined
minimum - maximum limits. This may lead to integer overflow or
OOB access issues. Add checks to avoid it.

Fixes: CVE-2021-20203
Buglink: https://bugs.launchpad.net/qemu/+bug/1913873
Reported-by: Gaoning Pan <pgn@zju.edu.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit d05dcd94aee88728facafb993c7280547eb4d645)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 17:39:20 -06:00
Mark Mielke
fec12fc888 virtio-blk: Fix clean up of host notifiers for single MR transaction.
The code that introduced "virtio-blk: Configure all host notifiers in
a single MR transaction" introduced a second loop variable to perform
cleanup in second loop, but mistakenly still refers to the first
loop variable within the second loop body.

Fixes: d0267da61489 ("virtio-blk: Configure all host notifiers in a single MR transaction")
Signed-off-by: Mark Mielke <mark.mielke@gmail.com>
Message-id: CALm7yL08qarOu0dnQkTN+pa=BSRC92g31YpQQNDeAiT4yLZWQQ@mail.gmail.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 5b807181c27a940a3a7ad1f221a2e76a132cbdc0)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 15:10:56 -06:00
Philippe Mathieu-Daudé
ef0cf1887e tests/qtest/fdc-test: Add a regression test for CVE-2021-20196
Without the previous commit, when running 'make check-qtest-i386'
with QEMU configured with '--enable-sanitizers' we get:

  AddressSanitizer:DEADLYSIGNAL
  =================================================================
  ==287878==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000344
  ==287878==The signal is caused by a WRITE memory access.
  ==287878==Hint: address points to the zero page.
      #0 0x564b2e5bac27 in blk_inc_in_flight block/block-backend.c:1346:5
      #1 0x564b2e5bb228 in blk_pwritev_part block/block-backend.c:1317:5
      #2 0x564b2e5bcd57 in blk_pwrite block/block-backend.c:1498:11
      #3 0x564b2ca1cdd3 in fdctrl_write_data hw/block/fdc.c:2221:17
      #4 0x564b2ca1b2f7 in fdctrl_write hw/block/fdc.c:829:9
      #5 0x564b2dc49503 in portio_write softmmu/ioport.c:201:9

Add the reproducer for CVE-2021-20196.

Suggested-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20211124161536.631563-4-philmd@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
(cherry picked from commit cc20926e9b8077bff6813efc8dcdeae90d1a3b10)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 15:05:11 -06:00
Philippe Mathieu-Daudé
71ba2adfeb hw/block/fdc: Kludge missing floppy drive to fix CVE-2021-20196
Guest might select another drive on the bus by setting the
DRIVE_SEL bit of the DIGITAL OUTPUT REGISTER (DOR).
The current controller model doesn't expect a BlockBackend
to be NULL. A simple way to fix CVE-2021-20196 is to create
an empty BlockBackend when it is missing. All further
accesses will be safely handled, and the controller state
machines keep behaving correctly.

Cc: qemu-stable@nongnu.org
Fixes: CVE-2021-20196
Reported-by: Gaoning Pan (Ant Security Light-Year Lab) <pgn@zju.edu.cn>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20211124161536.631563-3-philmd@redhat.com
BugLink: https://bugs.launchpad.net/qemu/+bug/1912780
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/338
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
(cherry picked from commit 1ab95af033a419e7a64e2d58e67dd96b20af5233)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 15:05:05 -06:00
Philippe Mathieu-Daudé
7629818574 hw/block/fdc: Extract blk_create_empty_drive()
We are going to re-use this code in the next commit,
so extract it as a new blk_create_empty_drive() function.

Inspired-by: Hanna Reitz <hreitz@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20211124161536.631563-2-philmd@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
(cherry picked from commit b154791e7b6d4ca5cdcd54443484d97360bd7ad2)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 15:04:59 -06:00
Daniil Tatianin
4658dfcbc0 chardev/wctable: don't free the instance in wctablet_chr_finalize
Object is supposed to be freed by invoking obj->free, and not
obj->instance_finalize. This would lead to use-after-free followed by
double free in object_unref/object_finalize.

Signed-off-by: Daniil Tatianin <d-tatianin@yandex-team.ru>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20211117142349.836279-1-d-tatianin@yandex-team.ru>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit fdc6e168181d06391711171b7c409b34f2981ced)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:54:14 -06:00
Klaus Jensen
2b2eb343a0 hw/nvme: fix buffer overrun in nvme_changed_nslist (CVE-2021-3947)
Fix missing offset verification.

Cc: qemu-stable@nongnu.org
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Reported-by: Qiuhao Li <Qiuhao.Li@outlook.com>
Fixes: f432fdfa121 ("support changed namespace asynchronous event")
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
(cherry picked from commit e2c57529c9306e4c9aac75d9879f6e7699584a22)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:52:50 -06:00
Eric Blake
932333c5f0 nbd/server: Don't complain on certain client disconnects
When a client disconnects abruptly, but did not have any pending
requests (for example, when using nbdsh without calling h.shutdown),
we used to output the following message:

$ qemu-nbd -f raw file
$ nbdsh -u 'nbd://localhost:10809' -c 'h.trim(1,0)'
qemu-nbd: Disconnect client, due to: Failed to read request: Unexpected end-of-file before all bytes were read

Then in commit f148ae7, we refactored nbd_receive_request() to use
nbd_read_eof(); when this returns 0, we regressed into tracing
uninitialized memory (if tracing is enabled) and reporting a
less-specific:

qemu-nbd: Disconnect client, due to: Request handling failed in intermediate state

Note that with Unix sockets, we have yet another error message,
unchanged by the 6.0 regression:

$ qemu-nbd -k /tmp/sock -f raw file
$ nbdsh -u 'nbd+unix:///?socket=/tmp/sock' -c 'h.trim(1,0)'
qemu-nbd: Disconnect client, due to: Failed to send reply: Unable to write to socket: Broken pipe

But in all cases, the error message goes away if the client performs a
soft shutdown by using NBD_CMD_DISC, rather than a hard shutdown by
abrupt disconnect:

$ nbdsh -u 'nbd://localhost:10809' -c 'h.trim(1,0)' -c 'h.shutdown()'

This patch fixes things to avoid uninitialized memory, and in general
avoids warning about a client that does a hard shutdown when not in
the middle of a packet.  A client that aborts mid-request, or which
does not read the full server's reply, can still result in warnings,
but those are indeed much more unusual situations.

CC: qemu-stable@nongnu.org
Fixes: f148ae7d36 ("nbd/server: Quiesce coroutines on context switch", v6.0.0)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
[eblake: defer unrelated typo fixes to later patch]
Message-Id: <20211117170230.1128262-2-eblake@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 1644cccea5c71b02b9cf8f78b780e7069a29b189)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:51:17 -06:00
Peng Liang
8c2d5911de vfio: Fix memory leak of hostwin
hostwin is allocated and added to hostwin_list in vfio_host_win_add, but
it is only deleted from hostwin_list in vfio_host_win_del, which causes
a memory leak.  Also, freeing all elements in hostwin_list is missing in
vfio_disconnect_container.

Fix: 2e4109de8e58 ("vfio/spapr: Create DMA window dynamically (SPAPR IOMMU v2)")
CC: qemu-stable@nongnu.org
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
Link: https://lore.kernel.org/r/20211117014739.1839263-1-liangpeng10@huawei.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
(cherry picked from commit f3bc3a73c908df15966e66f88d5a633bd42fd029)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:49:55 -06:00
Jason Wang
08e46e6d92 virtio: use virtio accessor to access packed event
We used to access packed descriptor event and off_wrap via
address_space_{write|read}_cached(). When we hit the cache, memcpy()
is used which is not atomic which may lead a wrong value to be read or
wrote.

This patch fixes this by switching to use
virito_{stw|lduw}_phys_cached() to make sure the access is atomic.

Fixes: 683f7665679c1 ("virtio: event suppression support for packed ring")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20211111063854.29060-2-jasowang@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit d152cdd6f6fad381e804c8185f0ba938030ccac9)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:43:25 -06:00
Jason Wang
df1c9c3039 virtio: use virtio accessor to access packed descriptor flags
We used to access packed descriptor flags via
address_space_{write|read}_cached(). When we hit the cache, memcpy()
is used which is not an atomic operation which may lead a wrong value
is read or wrote.

So this patch switches to use virito_{stw|lduw}_phys_cached() to make
sure the aceess is atomic.

Fixes: 86044b24e865f ("virtio: basic packed virtqueue support")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20211111063854.29060-1-jasowang@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit f463e761a41ee71e59892121e1c74d9c25c985d2)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:43:18 -06:00
Igor Mammedov
7204b8f3c6 pcie: rename 'native-hotplug' to 'x-native-hotplug'
Mark property as experimental/internal adding 'x-' prefix.

Property was introduced in 6.1 and it should have provided
ability to turn on native PCIE hotplug on port even when
ACPI PCI hotplug is in use is user explicitly sets property
on CLI. However that never worked since slot is wired to
ACPI hotplug controller.
Another non-intended usecase: disable native hotplug on slot
when APCI based hotplug is disabled, which works but slot has
'hotplug' property for this taks.

It should be relatively safe to rename it to experimental
as no users should exist for it and given that the property
is broken we don't really want to leave it around for much
longer lest users start using it.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <20211112110857.3116853-2-imammedo@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 2aa1842d6d79dcd1b84c58eeb44591a99a9e56df)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:38:08 -06:00
Greg Kurz
36c651c226 accel/tcg: Register a force_rcu notifier
A TCG vCPU doing a busy loop systematicaly hangs the QEMU monitor
if the user passes 'device_add' without argument. This is because
drain_cpu_all() which is called from qmp_device_add() cannot return
if readers don't exit read-side critical sections. That is typically
what busy-looping TCG vCPUs do:

int cpu_exec(CPUState *cpu)
{
[...]
    rcu_read_lock();
[...]
    while (!cpu_handle_exception(cpu, &ret)) {
        // Busy loop keeps vCPU here
    }
[...]
    rcu_read_unlock();

    return ret;
}

For MTTCG, have all vCPU threads register a force_rcu notifier that will
kick them out of the loop using async_run_on_cpu(). The notifier is called
with the rcu_registry_lock mutex held, using async_run_on_cpu() ensures
there are no deadlocks.

For RR, a single thread runs all vCPUs. Just register a single notifier
that kicks the current vCPU to the next one.

For MTTCG:
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>

For RR:
Suggested-by: Richard Henderson <richard.henderson@linaro.org>

Fixes: 7bed89958bfb ("device_core: use drain_call_rcu in in qmp_device_add")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/650
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20211109183523.47726-3-groug@kaod.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit dd47a8f654d84f666b235ce8891e17ee76f9be8b)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:26:01 -06:00
Greg Kurz
fceaefb43f rcu: Introduce force_rcu notifier
The drain_rcu_call() function can be blocked as long as an RCU reader
stays in a read-side critical section. This is typically what happens
when a TCG vCPU is executing a busy loop. It can deadlock the QEMU
monitor as reported in https://gitlab.com/qemu-project/qemu/-/issues/650 .

This can be avoided by allowing drain_rcu_call() to enforce an RCU grace
period. Since each reader might need to do specific actions to end a
read-side critical section, do it with notifiers.

Prepare ground for this by adding a notifier list to the RCU reader
struct and use it in wait_for_readers() if drain_rcu_call() is in
progress. An API is added for readers to register their notifiers.

This is largely based on a draft from Paolo Bonzini.

Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20211109183523.47726-2-groug@kaod.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit ef149763a8fcce70b85dfda27cc1222ecf765750)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:25:55 -06:00
Laurent Vivier
7d71e6bfb0 hw: m68k: virt: Add compat machine for 6.1
Add the missing machine type for m68k/virt

Cc: qemu-stable@nongnu.org
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20211106194158.4068596-2-laurent@vivier.eu>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
(cherry picked from commit 6837f299762679429924242a63f16490862578e3)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:23:21 -06:00
Mauro Matteo Cascella
c2c7f108b8 hw/scsi/scsi-disk: MODE_PAGE_ALLS not allowed in MODE SELECT commands
This avoids an off-by-one read of 'mode_sense_valid' buffer in
hw/scsi/scsi-disk.c:mode_sense_page().

Fixes: CVE-2021-3930
Cc: qemu-stable@nongnu.org
Reported-by: Alexander Bulekov <alxndr@bu.edu>
Fixes: a8f4bbe2900 ("scsi-disk: store valid mode pages in a table")
Fixes: #546
Reported-by: Qiuhao Li <Qiuhao.Li@outlook.com>
Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit b3af7fdf9cc537f8f0dd3e2423d83f5c99a457e8)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:22:44 -06:00
Paolo Bonzini
3488bb205d target-i386: mmu: fix handling of noncanonical virtual addresses
mmu_translate is supposed to return an error code for page faults; it is
not able to handle other exceptions.  The #GP case for noncanonical
virtual addresses is not handled correctly, and incorrectly raised as
a page fault with error code 1.  Since it cannot happen for nested
page tables, move it directly to handle_mmu_fault, even before the
invocation of mmu_translate.

Fixes: #676
Fixes: 661ff4879e ("target/i386: extract mmu_translate", 2021-05-11)
Cc: qemu-stable@nongnu.org
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit b04dc92e013d55c9ac8082caefff45dcfb1310e7)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:19:00 -06:00
Paolo Bonzini
cddfaf96ab target-i386: mmu: use pg_mode instead of HF_LMA_MASK
Correctly look up the paging mode of the hypervisor when it is using 64-bit
mode but the guest is not.

Fixes: 68746930ae ("target/i386: use mmu_translate for NPT walk", 2021-05-11)
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 93eae3583256896dd91a4c2ca38dcbb8d4051cff)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:18:25 -06:00
Jessica Clarke
43a457841f Partially revert "build: -no-pie is no functional linker flag"
This partially reverts commit bbd2d5a8120771ec59b86a80a1f51884e0a26e53.

This commit was misguided and broke using --disable-pie on any distro
that enables PIE by default in their compiler driver, including Debian
and its derivatives. Whilst -no-pie is not a linker flag, it is a
compiler driver flag that ensures -pie is not automatically passed by it
to the linker. Without it, all compile_prog checks will fail as any code
built with the explicit -fno-pie will fail to link with the implicit
default -pie due to trying to use position-dependent relocations. The
only bug that needed fixing was LDFLAGS_NOPIE being used as a flag for
the linker itself in pc-bios/optionrom/Makefile.

Note this does not reinstate exporting LDFLAGS_NOPIE, as it is unused,
since the only previous use was the one that should not have existed. I
have also updated the comment for the -fno-pie and -no-pie checks to
reflect what they're actually needed for.

Fixes: bbd2d5a8120771ec59b86a80a1f51884e0a26e53
Cc: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Message-Id: <20210805192545.38279-1-jrtc27@jrtc27.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit ffd205ef2901bd65fcfbd09a98c0ff7cfcec5e4d)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:13:38 -06:00
Ari Sundholm
ebf660beb1 block/file-posix: Fix return value translation for AIO discards
AIO discards regressed as a result of the following commit:
	0dfc7af2 block/file-posix: Optimize for macOS

When trying to run blkdiscard within a Linux guest, the request would
fail, with some errors in dmesg:

---- [ snip ] ----
[    4.010070] sd 2:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_OK
driverbyte=DRIVER_SENSE
[    4.011061] sd 2:0:0:0: [sda] tag#0 Sense Key : Aborted Command
[current]
[    4.011061] sd 2:0:0:0: [sda] tag#0 Add. Sense: I/O process
terminated
[    4.011061] sd 2:0:0:0: [sda] tag#0 CDB: Unmap/Read sub-channel 42
00 00 00 00 00 00 00 18 00
[    4.011061] blk_update_request: I/O error, dev sda, sector 0
---- [ snip ] ----

This turns out to be a result of a flaw in changes to the error value
translation logic in handle_aiocb_discard(). The default return value
may be left untranslated in some configurations, and the wrong variable
is used in one translation.

Fix both issues.

Fixes: 0dfc7af2b28 ("block/file-posix: Optimize for macOS")
Cc: qemu-stable@nongnu.org
Signed-off-by: Ari Sundholm <ari@tuxera.com>
Signed-off-by: Emil Karlson <jkarlson@tuxera.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20211019110954.4170931-1-ari@tuxera.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 13a028336f2c05e7ff47dfdaf30dfac7f4883e80)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:12:50 -06:00
Ani Sinha
bbbdedb386 tests/acpi/bios-tables-test: update DSDT blob for multifunction bridge test
We added a new unit test for testing acpi hotplug on multifunction bridges in
q35 machines. Here, we update the DSDT table gloden master blob for this unit
test.

The test adds the following devices to qemu and then checks the changes
introduced in the DSDT table due to the addition of the following devices:

(a) a multifunction bridge device
(b) a bridge device with function 1
(c) a non-bridge device with function 2

In the DSDT table, we should see AML hotplug descriptions for (a) and (b).
For (a) we should find a hotplug AML description for function 0.

Following is the ASL diff between the original DSDT table and the modified DSDT
table due to the unit test. We see that multifunction bridge on bus 2 and single
function bridge on bus 3 function 1 are described, not the non-bridge balloon
device on bus 4, function 2.

@@ -1,30 +1,30 @@
 /*
  * Intel ACPI Component Architecture
  * AML/ASL+ Disassembler version 20190509 (64-bit version)
  * Copyright (c) 2000 - 2019 Intel Corporation
  *
  * Disassembling to symbolic ASL+ operators
  *
- * Disassembly of tests/data/acpi/q35/DSDT, Thu Oct  7 18:29:19 2021
+ * Disassembly of /tmp/aml-C7JCA1, Thu Oct  7 18:29:19 2021
  *
  * Original Table Header:
  *     Signature        "DSDT"
- *     Length           0x00002061 (8289)
+ *     Length           0x00002187 (8583)
  *     Revision         0x01 **** 32-bit table (V1), no 64-bit math support
- *     Checksum         0xF9
+ *     Checksum         0x8D
  *     OEM ID           "BOCHS "
  *     OEM Table ID     "BXPC    "
  *     OEM Revision     0x00000001 (1)
  *     Compiler ID      "BXPC"
  *     Compiler Version 0x00000001 (1)
  */
 DefinitionBlock ("", "DSDT", 1, "BOCHS ", "BXPC    ", 0x00000001)
 {
     Scope (\)
     {
         OperationRegion (DBG, SystemIO, 0x0402, One)
         Field (DBG, ByteAcc, NoLock, Preserve)
         {
             DBGB,   8
         }

@@ -3265,23 +3265,95 @@
                 Method (_S1D, 0, NotSerialized)  // _S1D: S1 Device State
                 {
                     Return (Zero)
                 }

                 Method (_S2D, 0, NotSerialized)  // _S2D: S2 Device State
                 {
                     Return (Zero)
                 }

                 Method (_S3D, 0, NotSerialized)  // _S3D: S3 Device State
                 {
                     Return (Zero)
                 }
             }

+            Device (S10)
+            {
+                Name (_ADR, 0x00020000)  // _ADR: Address
+                Name (BSEL, One)
+                Device (S00)
+                {
+                    Name (_SUN, Zero)  // _SUN: Slot User Number
+                    Name (_ADR, Zero)  // _ADR: Address
+                    Method (_EJ0, 1, NotSerialized)  // _EJx: Eject Device, x=0-9
+                    {
+                        PCEJ (BSEL, _SUN)
+                    }
+
+                    Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
+                    {
+                        Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, _SUN))
+                    }
+                }
+
+                Method (DVNT, 2, NotSerialized)
+                {
+                    If ((Arg0 & One))
+                    {
+                        Notify (S00, Arg1)
+                    }
+                }
+
+                Method (PCNT, 0, NotSerialized)
+                {
+                    BNUM = One
+                    DVNT (PCIU, One)
+                    DVNT (PCID, 0x03)
+                }
+            }
+
+            Device (S19)
+            {
+                Name (_ADR, 0x00030001)  // _ADR: Address
+                Name (BSEL, Zero)
+                Device (S00)
+                {
+                    Name (_SUN, Zero)  // _SUN: Slot User Number
+                    Name (_ADR, Zero)  // _ADR: Address
+                    Method (_EJ0, 1, NotSerialized)  // _EJx: Eject Device, x=0-9
+                    {
+                        PCEJ (BSEL, _SUN)
+                    }
+
+                    Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
+                    {
+                        Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, _SUN))
+                    }
+                }
+
+                Method (DVNT, 2, NotSerialized)
+                {
+                    If ((Arg0 & One))
+                    {
+                        Notify (S00, Arg1)
+                    }
+                }
+
+                Method (PCNT, 0, NotSerialized)
+                {
+                    BNUM = Zero
+                    DVNT (PCIU, One)
+                    DVNT (PCID, 0x03)
+                }
+            }
+
             Method (PCNT, 0, NotSerialized)
             {
+                ^S19.PCNT ()
+                ^S10.PCNT ()
             }
         }
     }
 }

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <20211007135750.1277213-4-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
(cherry picked from commit a8339e07f94a47f99560baef59d65a9e039aaf45)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:05:24 -06:00
Ani Sinha
8319de607f tests/acpi/pcihp: add unit tests for hotplug on multifunction bridges for q35
commit d7346e614f4ec ("acpi: x86: pcihp: add support hotplug on multifunction bridges")
added ACPI hotplug descriptions for cold plugged bridges for functions other
than 0. For all other devices, the ACPI hotplug descriptions are limited to
function 0 only. This change adds unit tests for this feature.

This test adds the following devices to qemu and then checks the changes
introduced in the DSDT table due to the addition of the following devices:

(a) a multifunction bridge device
(b) a bridge device with function 1
(c) a non-bridge device with function 2

In the DSDT table, we should see AML hotplug descriptions for (a) and (b).
For (a) we should find a hotplug AML description for function 0.

The following diff compares the DSDT table AML with the new unit test before
and after the change d7346e614f4ec is introduced. In other words,
this diff reflects the changes that occurs in the DSDT table due to the change
d7346e614f4ec .

@@ -1,60 +1,38 @@
 /*
  * Intel ACPI Component Architecture
  * AML/ASL+ Disassembler version 20190509 (64-bit version)
  * Copyright (c) 2000 - 2019 Intel Corporation
  *
  * Disassembling to symbolic ASL+ operators
  *
- * Disassembly of tests/data/acpi/q35/DSDT.multi-bridge, Thu Oct  7 18:56:05 2021
+ * Disassembly of /tmp/aml-AN0DA1, Thu Oct  7 18:56:05 2021
  *
  * Original Table Header:
  *     Signature        "DSDT"
- *     Length           0x000020FE (8446)
+ *     Length           0x00002187 (8583)
  *     Revision         0x01 **** 32-bit table (V1), no 64-bit math support
- *     Checksum         0xDE
+ *     Checksum         0x8D
  *     OEM ID           "BOCHS "
  *     OEM Table ID     "BXPC    "
  *     OEM Revision     0x00000001 (1)
  *     Compiler ID      "BXPC"
  *     Compiler Version 0x00000001 (1)
  */
 DefinitionBlock ("", "DSDT", 1, "BOCHS ", "BXPC    ", 0x00000001)
 {
-    /*
-     * iASL Warning: There was 1 external control method found during
-     * disassembly, but only 0 were resolved (1 unresolved). Additional
-     * ACPI tables may be required to properly disassemble the code. This
-     * resulting disassembler output file may not compile because the
-     * disassembler did not know how many arguments to assign to the
-     * unresolved methods. Note: SSDTs can be dynamically loaded at
-     * runtime and may or may not be available via the host OS.
-     *
-     * In addition, the -fe option can be used to specify a file containing
-     * control method external declarations with the associated method
-     * argument counts. Each line of the file must be of the form:
-     *     External (<method pathname>, MethodObj, <argument count>)
-     * Invocation:
-     *     iasl -fe refs.txt -d dsdt.aml
-     *
-     * The following methods were unresolved and many not compile properly
-     * because the disassembler had to guess at the number of arguments
-     * required for each:
-     */
-    External (_SB_.PCI0.S19_.PCNT, MethodObj)    // Warning: Unknown method, guessing 1 arguments
-
     Scope (\)
     {
         OperationRegion (DBG, SystemIO, 0x0402, One)
         Field (DBG, ByteAcc, NoLock, Preserve)
         {
             DBGB,   8
         }

         Method (DBUG, 1, NotSerialized)
         {
             ToHexString (Arg0, Local0)
             ToBuffer (Local0, Local0)
             Local1 = (SizeOf (Local0) - One)
             Local2 = Zero
             While ((Local2 < Local1))
             {
@@ -3322,24 +3300,60 @@
                 Method (DVNT, 2, NotSerialized)
                 {
                     If ((Arg0 & One))
                     {
                         Notify (S00, Arg1)
                     }
                 }

                 Method (PCNT, 0, NotSerialized)
                 {
                     BNUM = One
                     DVNT (PCIU, One)
                     DVNT (PCID, 0x03)
                 }
             }

+            Device (S19)
+            {
+                Name (_ADR, 0x00030001)  // _ADR: Address
+                Name (BSEL, Zero)
+                Device (S00)
+                {
+                    Name (_SUN, Zero)  // _SUN: Slot User Number
+                    Name (_ADR, Zero)  // _ADR: Address
+                    Method (_EJ0, 1, NotSerialized)  // _EJx: Eject Device, x=0-9
+                    {
+                        PCEJ (BSEL, _SUN)
+                    }
+
+                    Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
+                    {
+                        Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, _SUN))
+                    }
+                }
+
+                Method (DVNT, 2, NotSerialized)
+                {
+                    If ((Arg0 & One))
+                    {
+                        Notify (S00, Arg1)
+                    }
+                }
+
+                Method (PCNT, 0, NotSerialized)
+                {
+                    BNUM = Zero
+                    DVNT (PCIU, One)
+                    DVNT (PCID, 0x03)
+                }
+            }
+
             Method (PCNT, 0, NotSerialized)
             {
-                ^S19.PCNT (^S10.PCNT ())
+                ^S19.PCNT ()
+                ^S10.PCNT ()
             }
         }
     }
 }

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <20211007135750.1277213-3-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
(cherry picked from commit 04dd78b9e85720226a148eef54b45cb02b463034)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:05:20 -06:00
Ani Sinha
a759dc19ec tests/acpi/bios-tables-test: add and allow changes to a new q35 DSDT table blob
We are adding a new unit test to cover the acpi hotplug support in q35 for
multi-function bridges. This test uses a new table DSDT.multi-bridge.
We need to allow changes in DSDT acpi table for addition of this new
unit test.

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <20211007135750.1277213-2-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
(cherry picked from commit 6dcb1cc9512c6b4cd8f85abc537abaf6f6c0738b)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:05:15 -06:00
Michael S. Tsirkin
24101e36f1 pci: fix PCI resource reserve capability on BE
PCI resource reserve capability should use LE format as all other PCI
things. If we don't then seabios won't boot:

=== PCI new allocation pass #1 ===
PCI: check devices
PCI: QEMU resource reserve cap: size 10000000000000 type io
PCI: secondary bus 1 size 10000000000000 type io
PCI: secondary bus 1 size 00200000 type mem
PCI: secondary bus 1 size 00200000 type prefmem
=== PCI new allocation pass #2 ===
PCI: out of I/O address space

This became more important since we started reserving IO by default,
previously no one noticed.

Fixes: e2a6290aab ("hw/pcie-root-port: Fix hotplug for PCI devices requiring IO")
Cc: marcel.apfelbaum@gmail.com
Fixes: 226263fb5c ("hw/pci: add QEMU-specific PCI capability to the Generic PCI Express Root Port")
Cc: zuban32s@gmail.com
Fixes: 6755e618d0 ("hw/pci: add PCI resource reserve capability to legacy PCI bridge")
Cc: jing2.liu@linux.intel.com
Tested-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
(cherry picked from commit 0e464f7d993113119f0fd17b890831440734ce15)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:01:41 -06:00
Paolo Bonzini
a43e057bd6 block: introduce max_hw_iov for use in scsi-generic
Linux limits the size of iovecs to 1024 (UIO_MAXIOV in the kernel
sources, IOV_MAX in POSIX).  Because of this, on some host adapters
requests with many iovecs are rejected with -EINVAL by the
io_submit() or readv()/writev() system calls.

In fact, the same limit applies to SG_IO as well.  To fix both the
EINVAL and the possible performance issues from using fewer iovecs
than allowed by Linux (some HBAs have max_segments as low as 128),
introduce a separate entry in BlockLimits to hold the max_segments
value from sysfs.  This new limit is used only for SG_IO and clamped
to bs->bl.max_iov anyway, just like max_hw_transfer is clamped to
bs->bl.max_transfer.

Reported-by: Halil Pasic <pasic@linux.ibm.com>
Cc: Hanna Reitz <hreitz@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: qemu-block@nongnu.org
Cc: qemu-stable@nongnu.org
Fixes: 18473467d5 ("file-posix: try BLKSECTGET on block devices too, do not round to power of 2", 2021-06-25)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20210923130436.1187591-1-pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit cc071629539dc1f303175a7e2d4ab854c0a8b20f)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:53:15 -06:00
Ani Sinha
3aa2c2cd67 bios-tables-test: Update ACPI DSDT table golden blobs for q35
We have modified the IO address range for ACPI pci hotplug in q35. See change:

5adcc9e39e6a5 ("hw/i386/acpi: fix conflicting IO address range for acpi pci hotplug in q35")

The ACPI DSDT table golden blobs must be regenrated in order to make the unit tests
pass. This change updates the golden ACPI DSDT table blobs.

Following is the ASL diff between the blobs:

@@ -1,30 +1,30 @@
 /*
  * Intel ACPI Component Architecture
  * AML/ASL+ Disassembler version 20190509 (64-bit version)
  * Copyright (c) 2000 - 2019 Intel Corporation
  *
  * Disassembling to symbolic ASL+ operators
  *
- * Disassembly of tests/data/acpi/q35/DSDT, Tue Sep 14 09:04:06 2021
+ * Disassembly of /tmp/aml-52DP90, Tue Sep 14 09:04:06 2021
  *
  * Original Table Header:
  *     Signature        "DSDT"
  *     Length           0x00002061 (8289)
  *     Revision         0x01 **** 32-bit table (V1), no 64-bit math support
- *     Checksum         0xE5
+ *     Checksum         0xF9
  *     OEM ID           "BOCHS "
  *     OEM Table ID     "BXPC    "
  *     OEM Revision     0x00000001 (1)
  *     Compiler ID      "BXPC"
  *     Compiler Version 0x00000001 (1)
  */
 DefinitionBlock ("", "DSDT", 1, "BOCHS ", "BXPC    ", 0x00000001)
 {
     Scope (\)
     {
         OperationRegion (DBG, SystemIO, 0x0402, One)
         Field (DBG, ByteAcc, NoLock, Preserve)
         {
             DBGB,   8
         }

@@ -226,46 +226,46 @@
             Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
             {
                 IO (Decode16,
                     0x0070,             // Range Minimum
                     0x0070,             // Range Maximum
                     0x01,               // Alignment
                     0x08,               // Length
                     )
                 IRQNoFlags ()
                     {8}
             })
         }
     }

     Scope (_SB.PCI0)
     {
-        OperationRegion (PCST, SystemIO, 0x0CC4, 0x08)
+        OperationRegion (PCST, SystemIO, 0x0CC0, 0x08)
         Field (PCST, DWordAcc, NoLock, WriteAsZeros)
         {
             PCIU,   32,
             PCID,   32
         }

-        OperationRegion (SEJ, SystemIO, 0x0CCC, 0x04)
+        OperationRegion (SEJ, SystemIO, 0x0CC8, 0x04)
         Field (SEJ, DWordAcc, NoLock, WriteAsZeros)
         {
             B0EJ,   32
         }

-        OperationRegion (BNMR, SystemIO, 0x0CD4, 0x08)
+        OperationRegion (BNMR, SystemIO, 0x0CD0, 0x08)
         Field (BNMR, DWordAcc, NoLock, WriteAsZeros)
         {
             BNUM,   32,
             PIDX,   32
         }

         Mutex (BLCK, 0x00)
         Method (PCEJ, 2, NotSerialized)
         {
             Acquire (BLCK, 0xFFFF)
             BNUM = Arg0
             B0EJ = (One << Arg1)
             Release (BLCK)
             Return (Zero)
         }

@@ -3185,34 +3185,34 @@
                     0x0620,             // Range Minimum
                     0x0620,             // Range Maximum
                     0x01,               // Alignment
                     0x10,               // Length
                     )
             })
         }

         Device (PHPR)
         {
             Name (_HID, "PNP0A06" /* Generic Container Device */)  // _HID: Hardware ID
             Name (_UID, "PCI Hotplug resources")  // _UID: Unique ID
             Name (_STA, 0x0B)  // _STA: Status
             Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
             {
                 IO (Decode16,
-                    0x0CC4,             // Range Minimum
-                    0x0CC4,             // Range Maximum
+                    0x0CC0,             // Range Minimum
+                    0x0CC0,             // Range Maximum
                     0x01,               // Alignment
                     0x18,               // Length
                     )
             })
         }
     }

     Scope (\)
     {
         Name (_S3, Package (0x04)  // _S3_: S3 System State
         {
             One,
             One,
             Zero,
             Zero
         })

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20210916132838.3469580-4-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 500eb21cff08dfb0478db9b34f2fdba69eb31496)
*drop dependency on 75539b886a ("tests: acpi: tpm1.2: Add expected TPM 1.2 ACPI blobs")
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:27:44 -06:00
Ani Sinha
9e80a430ed hw/i386/acpi: fix conflicting IO address range for acpi pci hotplug in q35
Change caf108bc58790 ("hw/i386/acpi-build: Add ACPI PCI hot-plug methods to Q35")
selects an IO address range for acpi based PCI hotplug for q35 arbitrarily. It
starts at address 0x0cc4 and ends at 0x0cdb. At the time when the patch was
written but the final version of the patch was not yet pushed upstream, this
address range was free and did not conflict with any other IO address ranges.
However, with the following change, this address range was no
longer conflict free as in this change, the IO address range
(value of ACPI_PCIHP_SIZE) was incremented by four bytes:

b32bd763a1ca92 ("pci: introduce acpi-index property for PCI device")

This can be seen from the output of QMP command 'info mtree' :

0000000000000600-0000000000000603 (prio 0, i/o): acpi-evt
0000000000000604-0000000000000605 (prio 0, i/o): acpi-cnt
0000000000000608-000000000000060b (prio 0, i/o): acpi-tmr
0000000000000620-000000000000062f (prio 0, i/o): acpi-gpe0
0000000000000630-0000000000000637 (prio 0, i/o): acpi-smi
0000000000000cc4-0000000000000cdb (prio 0, i/o): acpi-pci-hotplug
0000000000000cd8-0000000000000ce3 (prio 0, i/o): acpi-cpu-hotplug

It shows that there is a region of conflict between IO regions of acpi
pci hotplug and acpi cpu hotplug.

Unfortunately, the change caf108bc58790 did not update the IO address range
appropriately before it was pushed upstream to accommodate the increased
length of the IO address space introduced in change b32bd763a1ca92.

Due to this bug, windows guests complain 'This device cannot find
enough free resources it can use' in the device manager panel for extended
IO buses. This issue also breaks the correct functioning of pci hotplug as the
following shows that the IO space for pci hotplug has been truncated:

(qemu) info mtree -f
FlatView #0
 AS "I/O", root: io
 Root memory region: io
  0000000000000cc4-0000000000000cd7 (prio 0, i/o): acpi-pci-hotplug
  0000000000000cd8-0000000000000cf7 (prio 0, i/o): acpi-cpu-hotplug

Therefore, in this fix, we adjust the IO address range for the acpi pci
hotplug so that it does not conflict with cpu hotplug and there is no
truncation of IO spaces. The starting IO address of PCI hotplug region
has been decremented by four bytes in order to accommodate four byte
increment in the IO address space introduced by change
b32bd763a1ca92 ("pci: introduce acpi-index property for PCI device")

After fixing, the following are the corrected IO ranges:

0000000000000600-0000000000000603 (prio 0, i/o): acpi-evt
0000000000000604-0000000000000605 (prio 0, i/o): acpi-cnt
0000000000000608-000000000000060b (prio 0, i/o): acpi-tmr
0000000000000620-000000000000062f (prio 0, i/o): acpi-gpe0
0000000000000630-0000000000000637 (prio 0, i/o): acpi-smi
0000000000000cc0-0000000000000cd7 (prio 0, i/o): acpi-pci-hotplug
0000000000000cd8-0000000000000ce3 (prio 0, i/o): acpi-cpu-hotplug

This change has been tested using a Windows Server 2019 guest VM. Windows
no longer complains after this change.

Fixes: caf108bc58790 ("hw/i386/acpi-build: Add ACPI PCI hot-plug methods to Q35")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/561

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Julia Suvorova <jusual@redhat.com>
Message-Id: <20210916132838.3469580-3-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 0e780da76a6fe283a20283856718bca3986c104f)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:12:38 -06:00
Ani Sinha
c66f5dfc12 bios-tables-test: allow changes in DSDT ACPI tables for q35
We are going to commit a change to fix IO address range allocated for acpi pci
hotplug in q35. This affects DSDT tables. This change allows DSDT table
modification so that unit tests are not broken.

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20210916132838.3469580-2-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 9f29e872d5b3973003701401cf659cfb71c95013)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:12:31 -06:00
Jean-Philippe Brucker
5cf977a2a1 hw/i386: Rename default_bus_bypass_iommu
Since commit d8fb7d0969d5 ("vl: switch -M parsing to keyval"), machine
parameter definitions cannot use underscores, because keyval_dashify()
transforms them to dashes and the parser doesn't find the parameter.

This affects option default_bus_bypass_iommu which was introduced in the
same release:

$ qemu-system-x86_64 -M q35,default_bus_bypass_iommu=on
qemu-system-x86_64: Property 'pc-q35-6.1-machine.default-bus-bypass-iommu' not found

Rename the parameter to "default-bus-bypass-iommu". Passing
"default_bus_bypass_iommu" is still valid since the underscore are
transformed automatically.

Fixes: c9e96b04fc19 ("hw/i386: Add a default_bus_bypass_iommu pc machine option")
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Message-Id: <20211025104737.1560274-1-jean-philippe@linaro.org>
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 739b38630c45585cd9d372d44537f69c0b2b4346)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:07:48 -06:00
Jean-Philippe Brucker
36cfd11a86 hw/arm/virt: Rename default_bus_bypass_iommu
Since commit d8fb7d0969d5 ("vl: switch -M parsing to keyval"), machine
parameter definitions cannot use underscores, because keyval_dashify()
transforms them to dashes and the parser doesn't find the parameter.

This affects option default_bus_bypass_iommu which was introduced in the
same release:

$ qemu-system-aarch64 -M virt,default_bus_bypass_iommu=on
qemu-system-aarch64: Property 'virt-6.1-machine.default-bus-bypass-iommu' not found

Rename the parameter to "default-bus-bypass-iommu". Passing
"default_bus_bypass_iommu" is still valid since the underscore are
transformed automatically.

Fixes: 6d7a85483a06 ("hw/arm/virt: Add default_bus_bypass_iommu machine option")
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Tested-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20211026093733.2144161-1-jean-philippe@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
(cherry picked from commit 9dad363a223df8269175d218413aa8cd265e078e)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:07:27 -06:00
Stefano Garzarella
246ccfbf44 vhost-vsock: fix migration issue when seqpacket is supported
Commit 1e08fd0a46 ("vhost-vsock: SOCK_SEQPACKET feature bit support")
enabled the SEQPACKET feature bit.
This commit is released with QEMU 6.1, so if we try to migrate a VM where
the host kernel supports SEQPACKET but machine type version is less than
6.1, we get the following errors:

    Features 0x130000002 unsupported. Allowed features: 0x179000000
    Failed to load virtio-vhost_vsock:virtio
    error while loading state for instance 0x0 of device '0000:00:05.0/virtio-vhost_vsock'
    load of migration failed: Operation not permitted

Let's disable the feature bit for machine types < 6.1.
We add a new OnOffAuto property for this, called `seqpacket`.
When it is `auto` (default), QEMU behaves as before, trying to enable the
feature, when it is `on` QEMU will fail if the backend (vhost-vsock
kernel module) doesn't support it.

Fixes: 1e08fd0a46 ("vhost-vsock: SOCK_SEQPACKET feature bit support")
Cc: qemu-stable@nongnu.org
Reported-by: Jiang Wang <jiang.wang@bytedance.com>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Message-Id: <20210921161642.206461-2-sgarzare@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit d6a9378f47515c6d70dbff4912c5740c98709880)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:04:13 -06:00
Michael Tokarev
3ee93e456d qemu-sockets: fix unix socket path copy (again)
Commit 4cfd970ec188558daa6214f26203fe553fb1e01f added an
assert which ensures the path within an address of a unix
socket returned from the kernel is at least one byte and
does not exceed sun_path buffer. Both of this constraints
are wrong:

A unix socket can be unnamed, in this case the path is
completely empty (not even \0)

And some implementations (notable linux) can add extra
trailing byte (\0) _after_ the sun_path buffer if we
passed buffer larger than it (and we do).

So remove the assertion (since it causes real-life breakage)
but at the same time fix the usage of sun_path. Namely,
we should not access sun_path[0] if kernel did not return
it at all (this is the case for unnamed sockets),
and use the returned salen when copyig actual path as an
upper constraint for the amount of bytes to copy - this
will ensure we wont exceed the information provided by
the kernel, regardless whenever there is a trailing \0
or not. This also helps with unnamed sockets.

Note the case of abstract socket, the sun_path is actually
a blob and can contain \0 characters, - it should not be
passed to g_strndup and the like, it should be accessed by
memcpy-like functions.

Fixes: 4cfd970ec188558daa6214f26203fe553fb1e01f
Fixes: http://bugs.debian.org/993145
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
CC: qemu-stable@nongnu.org
(cherry picked from commit 118d527f2e4baec5fe8060b22a6212468b8e4d3f)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:55:36 -06:00
Paolo Bonzini
ec08035102 plugins: do not limit exported symbols if modules are active
On Mac --enable-modules and --enable-plugins are currently incompatible, because the
Apple -Wl,-exported_symbols_list command line options prevents the export of any
symbols needed by the modules.  On x86 -Wl,--dynamic-list does not have this effect,
but only because the -Wl,--export-dynamic option provided by gmodule-2.0.pc overrides
it.  On Apple there is no -Wl,--export-dynamic, because it is the default, and thus
no override.

Either way, when modules are active there is no reason to include the plugin_ldflags.
While at it, avoid the useless -Wl,--export-dynamic when --enable-plugins is
specified but --enable-modules is not; this way, the GNU and Apple configurations
are more similar.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/516
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
[AJB: fix noexport to no-export]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20210811100550.54714-1-pbonzini@redhat.com>
Cc: qemu-stable@nongnu.org
(cherry picked from commit b906acace2d4f68b6ff8de73739a773cc4851436)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:49:09 -06:00
Mahmoud Mandour
f97853c8cb plugins/execlog: removed unintended "s" at the end of log lines.
Signed-off-by: Mahmoud Mandour <ma.mandourr@gmail.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20210803151428.125323-1-ma.mandourr@gmail.com>
Message-Id: <20210806141015.2487502-2-alex.bennee@linaro.org>
Cc: qemu-stable@nongnu.org
(cherry picked from commit b40310616d2bd550279dd22b05483c3c613a00ff)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:48:25 -06:00
Christian Schoenebeck
abeee2a470 9pfs: fix crash in v9fs_walk()
v9fs_walk() utilizes the v9fs_co_run_in_worker({...}) macro to run the
supplied fs driver code block on a background worker thread.

When either the 'Twalk' client request was interrupted or if the client
requested fid for that 'Twalk' request caused a stat error then that
fs driver code block was left by 'break' keyword, with the intention to
return from worker thread back to main thread as well:

    v9fs_co_run_in_worker({
        if (v9fs_request_cancelled(pdu)) {
            err = -EINTR;
            break;
        }
        err = s->ops->lstat(&s->ctx, &dpath, &fidst);
        if (err < 0) {
            err = -errno;
            break;
        }
        ...
    });

However that 'break;' statement also skipped the v9fs_co_run_in_worker()
macro's final and mandatory

    /* re-enter back to qemu thread */
    qemu_coroutine_yield();

call and thus caused the rest of v9fs_walk() to be continued being
executed on the worker thread instead of main thread, eventually
leading to a crash in the transport virtio transport driver.

To fix this issue and to prevent the same error from happening again by
other users of v9fs_co_run_in_worker() in future, auto wrap the supplied
code block into its own

    do { } while (0);

loop inside the 'v9fs_co_run_in_worker' macro definition.

Full discussion and backtrace:
https://lists.gnu.org/archive/html/qemu-devel/2021-08/msg05209.html
https://lists.gnu.org/archive/html/qemu-devel/2021-09/msg00174.html

Fixes: 8d6cb100731c4d28535adbf2a3c2d1f29be3fef4
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Cc: qemu-stable@nongnu.org
Reviewed-by: Greg Kurz <groug@kaod.org>
Message-Id: <E1mLTBg-0002Bh-2D@lizzy.crudebyte.com>
(cherry picked from commit f83df00900816476cca41bb536e4d532b297d76e)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:46:48 -06:00
Yang Zhong
ff6d391e10 i386/cpu: Remove AVX_VNNI feature from Cooperlake cpu model
The AVX_VNNI feature is not in Cooperlake platform, remove it
from cpu model.

Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <20210820054611.84303-1-yang.zhong@intel.com>
Fixes: c1826ea6a052 ("i386/cpu: Expose AVX_VNNI instruction to guest")
Cc: qemu-stable@nongnu.org
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
(cherry picked from commit f429dbf8fc526a9cacf531176b28d0c65701475a)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:43:09 -06:00
Helge Deller
b19de1137b hw/display/artist: Fix bug in coordinate extraction in artist_vram_read() and artist_vram_write()
The CDE desktop on HP-UX 10 shows wrongly rendered pixels when the local screen
menu is closed. This bug was introduced by commit c7050f3f167b
("hw/display/artist: Refactor x/y coordination extraction") which converted the
coordinate extraction in artist_vram_read() and artist_vram_write() to use the
ADDR_TO_X and ADDR_TO_Y macros, but forgot to right-shift the address by 2 as
it was done before.

Signed-off-by: Helge Deller <deller@gmx.de>
Fixes: c7050f3f167b ("hw/display/artist: Refactor x/y coordination extraction")
Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>
Cc: Richard Henderson <richard.henderson@linaro.org>
Cc: Sven Schnelle <svens@stackframe.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <YK1aPb8keur9W7h2@ls3530>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 01f750f5fef1afd8f6abc0548910f87d473e26d5)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:57:12 -06:00
David Hildenbrand
3c6e5df1f6 libvhost-user: fix VHOST_USER_REM_MEM_REG skipping mmap_addr
We end up not copying the mmap_addr of all existing regions, resulting
in a SEGFAULT once we actually try to map/access anything within our
memory regions.

Fixes: 875b9fd97b34 ("Support individual region unmap in libvhost-user")
Cc: qemu-stable@nongnu.org
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Raphael Norwitz <raphael.norwitz@nutanix.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Coiby Xu <coiby.xu@gmail.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20211011201047.62587-1-david@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 6889eb2d431ae962e3e083b57bff47cd573cb1c4)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:57:07 -06:00
Xueming Li
695c25e167 vhost-user: fix duplicated notifier MR init
In case of device resume after suspend, VQ notifier MR still valid.
Duplicated registrations explode memory block list and slow down device
resume.

Fixes: 44866521bd6e ("vhost-user: support registering external host notifiers")
Cc: tiwei.bie@intel.com
Cc: qemu-stable@nongnu.org
Cc: Yuwei Zhang <zhangyuwei.9149@bytedance.com>

Signed-off-by: Xueming Li <xuemingl@nvidia.com>
Message-Id: <20211008080215.590292-1-xuemingl@nvidia.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit a1ed9ef1de87c3e86ff68589604298ec90875a14)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:57:02 -06:00
Gerd Hoffmann
23ba9f170f uas: add stream number sanity checks.
The device uses the guest-supplied stream number unchecked, which can
lead to guest-triggered out-of-band access to the UASDevice->data3 and
UASDevice->status3 fields.  Add the missing checks.

Fixes: CVE-2021-3713
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reported-by: Chen Zhe <chenzhe@huawei.com>
Reported-by: Tan Jingguo <tanjingguo@huawei.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20210818120505.1258262-2-kraxel@redhat.com>
(cherry picked from commit 13b250b12ad3c59114a6a17d59caf073ce45b33a)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:53 -06:00
David Hildenbrand
f0dee5a40d virtio-mem-pci: Fix memory leak when creating MEMORY_DEVICE_SIZE_CHANGE event
Apparently, we don't have to duplicate the string.

Fixes: 722a3c783ef4 ("virtio-pci: Send qapi events when the virtio-mem size changes")
Cc: qemu-stable@nongnu.org
Signed-off-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20210929162445.64060-2-david@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 75b98cb9f6456ccf194211beffcbf93b0a995fa4)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:49 -06:00
Markus Armbruster
7637373b23 hmp: Unbreak "change vnc"
HMP command "change vnc" can take the password as argument, or prompt
for it:

    (qemu) change vnc password 123
    (qemu) change vnc password
    Password: ***
    (qemu)

This regressed in commit cfb5387a1d "hmp: remove "change vnc TARGET"
command", v6.0.0.

    (qemu) change vnc passwd 123
    Password: ***
    (qemu) change vnc passwd
    (qemu)

The latter passes NULL to qmp_change_vnc_password(), which is a no-no.
Looks like it puts the display into "password required, but none set"
state.

The logic error is easy to miss in review, but testing should've
caught it.

Fix the obvious way.

Fixes: cfb5387a1de2acda23fb5c97d2378b9e7ddf8025
Cc: qemu-stable@nongnu.org
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Message-Id: <20210909081219.308065-2-armbru@redhat.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
(cherry picked from commit 6193344f9337f8b76cd44ce94a32c9900d907d35)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:41 -06:00
Nir Soffer
4c34ef3d34 qemu-nbd: Change default cache mode to writeback
Both qemu and qemu-img use writeback cache mode by default, which is
already documented in qemu(1). qemu-nbd uses writethrough cache mode by
default, and the default cache mode is not documented.

According to the qemu-nbd(8):

   --cache=CACHE
          The  cache  mode  to be used with the file.  See the
          documentation of the emulator's -drive cache=... option for
          allowed values.

qemu(1) says:

    The default mode is cache=writeback.

So users have no reason to assume that qemu-nbd is using writethough
cache mode. The only hint is the painfully slow writing when using the
defaults.

Looking in git history, it seems that qemu used writethrough in the past
to support broken guests that did not flush data properly, or could not
flush due to limitations in qemu. But qemu-nbd clients can use
NBD_CMD_FLUSH to flush data, so using writethrough does not help anyone.

Change the default cache mode to writback, and document the default and
available values properly in the online help and manual.

With this change converting image via qemu-nbd is 3.5 times faster.

    $ qemu-img create dst.img 50g
    $ qemu-nbd -t -f raw -k /tmp/nbd.sock dst.img

Before this change:

    $ hyperfine -r3 "./qemu-img convert -p -f raw -O raw -T none -W fedora34.img nbd+unix:///?socket=/tmp/nbd.sock"
    Benchmark #1: ./qemu-img convert -p -f raw -O raw -T none -W fedora34.img nbd+unix:///?socket=/tmp/nbd.sock
      Time (mean ± σ):     83.639 s ±  5.970 s    [User: 2.733 s, System: 6.112 s]
      Range (min … max):   76.749 s … 87.245 s    3 runs

After this change:

    $ hyperfine -r3 "./qemu-img convert -p -f raw -O raw -T none -W fedora34.img nbd+unix:///?socket=/tmp/nbd.sock"
    Benchmark #1: ./qemu-img convert -p -f raw -O raw -T none -W fedora34.img nbd+unix:///?socket=/tmp/nbd.sock
      Time (mean ± σ):     23.522 s ±  0.433 s    [User: 2.083 s, System: 5.475 s]
      Range (min … max):   23.234 s … 24.019 s    3 runs

Users can avoid the issue by using --cache=writeback[1] but the defaults
should give good performance for the common use case.

[1] https://bugzilla.redhat.com/1990656

Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Message-Id: <20210813205519.50518-1-nsoffer@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
CC: qemu-stable@nongnu.org
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 09615257058a0ae87b837bb041f56f7312d9ead8)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:36 -06:00
Jason Wang
9e41f16fca virtio-net: fix use after unmap/free for sg
When mergeable buffer is enabled, we try to set the num_buffers after
the virtqueue elem has been unmapped. This will lead several issues,
E.g a use after free when the descriptor has an address which belongs
to the non direct access region. In this case we use bounce buffer
that is allocated during address_space_map() and freed during
address_space_unmap().

Fixing this by storing the elems temporarily in an array and delay the
unmap after we set the the num_buffers.

This addresses CVE-2021-3748.

Reported-by: Alexander Bulekov <alxndr@bu.edu>
Fixes: fbe78f4f55c6 ("virtio-net support")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit bedd7e93d01961fcb16a97ae45d93acf357e11f6)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:31 -06:00
Peter Maydell
3054f772de target/arm: Don't skip M-profile reset entirely in user mode
Currently all of the M-profile specific code in arm_cpu_reset() is
inside a !defined(CONFIG_USER_ONLY) ifdef block.  This is
unintentional: it happened because originally the only
M-profile-specific handling was the setup of the initial SP and PC
from the vector table, which is system-emulation only.  But then we
added a lot of other M-profile setup to the same "if (ARM_FEATURE_M)"
code block without noticing that it was all inside a not-user-mode
ifdef.  This has generally been harmless, but with the addition of
v8.1M low-overhead-loop support we ran into a problem: the reset of
FPSCR.LTPSIZE to 4 was only being done for system emulation mode, so
if a user-mode guest tried to execute the LE instruction it would
incorrectly take a UsageFault.

Adjust the ifdefs so only the really system-emulation specific parts
are covered.  Because this means we now run some reset code that sets
up initial values in the FPCCR and similar FPU related registers,
explicitly set up the registers controlling FPU context handling in
user-emulation mode so that the FPU works by design and not by
chance.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/613
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20210914120725.24992-2-peter.maydell@linaro.org
(cherry picked from commit b62ceeaf8096fdbbbfdc6087da0028bc4a4dd77e)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:25 -06:00
David Hildenbrand
aa77e375a5 virtio-balloon: don't start free page hinting if postcopy is possible
Postcopy never worked properly with 'free-page-hint=on', as there are
at least two issues:

1) With postcopy, the guest will never receive a VIRTIO_BALLOON_CMD_ID_DONE
   and consequently won't release free pages back to the OS once
   migration finishes.

   The issue is that for postcopy, we won't do a final bitmap sync while
   the guest is stopped on the source and
   virtio_balloon_free_page_hint_notify() will only call
   virtio_balloon_free_page_done() on the source during
   PRECOPY_NOTIFY_CLEANUP, after the VM state was already migrated to
   the destination.

2) Once the VM touches a page on the destination that has been excluded
   from migration on the source via qemu_guest_free_page_hint() while
   postcopy is active, that thread will stall until postcopy finishes
   and all threads are woken up. (with older Linux kernels that won't
   retry faults when woken up via userfaultfd, we might actually get a
   SEGFAULT)

   The issue is that the source will refuse to migrate any pages that
   are not marked as dirty in the dirty bmap -- for example, because the
   page might just have been sent. Consequently, the faulting thread will
   stall, waiting for the page to be migrated -- which could take quite
   a while and result in guest OS issues.

While we could fix 1) comparatively easily, 2) is harder to get right and
might require more involved RAM migration changes on source and destination
[1].

As it never worked properly, let's not start free page hinting in the
precopy notifier if the postcopy migration capability was enabled to fix
it easily. Capabilities cannot be enabled once migration is already
running.

Note 1: in the future we might either adjust migration code on the source
        to track pages that have actually been sent or adjust
        migration code on source and destination  to eventually send
        pages multiple times from the source and and deal with pages
        that are sent multiple times on the destination.

Note 2: virtio-mem has similar issues, however, access to "unplugged"
        memory by the guest is very rare and we would have to be very
        lucky for it to happen during migration. The spec states
        "The driver SHOULD NOT read from unplugged memory blocks ..."
        and "The driver MUST NOT write to unplugged memory blocks".
        virtio-mem will move away from virtio_balloon_free_page_done()
        soon and handle this case explicitly on the destination.

[1] https://lkml.kernel.org/r/e79fd18c-aa62-c1d8-c7f3-ba3fc2c25fc8@redhat.com

Fixes: c13c4153f76d ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT")
Cc: qemu-stable@nongnu.org
Cc: Wei Wang <wei.w.wang@intel.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Alexander Duyck <alexander.duyck@gmail.com>
Cc: Juan Quintela <quintela@redhat.com>
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Cc: Peter Xu <peterx@redhat.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20210708095339.20274-2-david@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
(cherry picked from commit fd51e54fa10221e5a8add894c38cc1cf199f4bc4)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:18 -06:00
97 changed files with 2179 additions and 139 deletions

3
.gitignore vendored
View File

@ -15,3 +15,6 @@ GTAGS
*.depend_raw *.depend_raw
*.swp *.swp
*.patch *.patch
.cache
*.axf
*.qcow2

72
3k.c Normal file
View File

@ -0,0 +1,72 @@
#include <stdio.h>
#include <stdint.h>
void libafl_qemu_main_loop( void );
void libafl_qemu_sys_init(int argc, char **argv, char **envp);
void libafl_qemu_cleanup( void );
void libafl_qemu_set_breakpoint( unsigned long int );
void libafl_qemu_remove_native_breakpoint( unsigned long int );
void libafl_qemu_set_native_breakpoint( unsigned long int );
void libafl_snapshot_save( const char* );
void libafl_snapshot_load( const char* );
void libafl_phys_read(uint32_t, uint8_t*, int);
void libafl_phys_write(uint32_t, uint8_t*, int);
int64_t icount_to_ns(int64_t icount);
int64_t libafl_get_clock( void );
int main(int argc, char **argv, char **envp)
{
unsigned char buf[32] = "_`abcdefghijklmnopqrstuvwxyz{|}~";
unsigned char buf2[32] = "0";
unsigned char buf3[32] = "z";
unsigned char buf4[32] = "a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
unsigned char buf5[32] = "b!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
libafl_qemu_sys_init(argc, argv, envp);
int pheader = 0x00006a4c;
// libafl_phys_read(0x20000110-0x20000100+pheader, buf,32);
// printf("FUZZ_INPUT[0]: %c\n", buf[0]);
// Start pre-run
libafl_qemu_set_native_breakpoint(0x4ce2);//send 217028
libafl_qemu_main_loop();
libafl_qemu_remove_native_breakpoint(0x4ce2);
// End pre-run
libafl_snapshot_save("Start");
libafl_qemu_set_native_breakpoint(0x4be0);
int64_t tmp = libafl_get_clock();
printf("snapshot icount: %ld, %ldns\n",tmp,icount_to_ns(tmp));
libafl_snapshot_load("Start");
tmp = libafl_get_clock();
printf("snapshot icount after load: %ld, %ldns\n",tmp,icount_to_ns(tmp));
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
libafl_qemu_main_loop();
printf("%ld für %s\n",libafl_get_clock(),buf);
libafl_snapshot_load("Start");
libafl_phys_write(0x20000110-0x20000100+pheader, buf2,32);
libafl_qemu_main_loop();
printf("%ld für %s\n",libafl_get_clock(),buf2);
libafl_snapshot_load("Start");
libafl_phys_write(0x20000110-0x20000100+pheader, buf3,32);
libafl_qemu_main_loop();
printf("%ld für %s\n",libafl_get_clock(),buf3);
libafl_snapshot_load("Start");
/*int counter = 3000;
do {
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
libafl_qemu_main_loop();
int64_t tmp = libafl_get_clock();
printf("%ld, %ldns\n",tmp,icount_to_ns(tmp));
libafl_snapshot_load("Start");
// puts("Reload has occured");
counter--;
} while (counter);*/
libafl_qemu_cleanup();
return 0;
}

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# QEMU LibAFL Bridge
This is a patched QEMU that exposes an interface for LibAFL-based fuzzers.
This raw interface is used in `libafl_qemu` that expose a more Rusty API.
#### License
<sup>
This project extends the QEMU emulator, and our contributions to previously existing files adopt those files' respective licenses; the files that we have added are made available under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
</sup>
<br>

View File

@ -1 +1 @@
6.1.0 6.1.1

View File

@ -626,6 +626,18 @@ static inline void cpu_handle_debug_exception(CPUState *cpu)
static inline bool cpu_handle_exception(CPUState *cpu, int *ret) static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
{ {
//// --- Begin LibAFL code ---
#define EXCP_LIBAFL_BP 0xf4775747
if (cpu->exception_index == EXCP_LIBAFL_BP) {
*ret = cpu->exception_index;
cpu->exception_index = -1;
return true;
}
//// --- End LibAFL code ---
if (cpu->exception_index < 0) { if (cpu->exception_index < 0) {
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (replay_has_exception() if (replay_has_exception()
@ -851,6 +863,15 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
#endif #endif
} }
//// --- Begin LibAFL code ---
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong dst_block, target_ulong cs_base,
uint32_t flags, int cflags);
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block);
//// --- End LibAFL code ---
/* main execution loop */ /* main execution loop */
int cpu_exec(CPUState *cpu) int cpu_exec(CPUState *cpu)
@ -950,6 +971,12 @@ int cpu_exec(CPUState *cpu)
*/ */
qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb); qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
} }
//// --- Begin LibAFL code ---
// This will save an edge (0,pc) after interrupts
// if (!last_tb) {
// libafl_exec_edge_one_off(0, tb->pc);
// }
//// --- End LibAFL code ---
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
/* /*
@ -964,8 +991,28 @@ int cpu_exec(CPUState *cpu)
#endif #endif
/* See if we can patch the calling TB. */ /* See if we can patch the calling TB. */
if (last_tb) { if (last_tb) {
// tb_add_jump(last_tb, tb_exit, tb);
//// --- Begin LibAFL code ---
if (last_tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
mmap_lock();
TranslationBlock *edge = libafl_gen_edge(cpu, last_tb->pc, tb->pc,
cs_base, flags, cflags);
mmap_unlock();
if (edge) {
tb_add_jump(last_tb, tb_exit, edge);
tb_add_jump(edge, 0, tb);
} else {
tb_add_jump(last_tb, tb_exit, tb); tb_add_jump(last_tb, tb_exit, tb);
} }
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
//// --- End LibAFL code ---
}
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit); cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit);

View File

@ -28,6 +28,7 @@
#include "sysemu/tcg.h" #include "sysemu/tcg.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/notify.h"
#include "qemu/guest-random.h" #include "qemu/guest-random.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "hw/boards.h" #include "hw/boards.h"
@ -35,6 +36,26 @@
#include "tcg-accel-ops.h" #include "tcg-accel-ops.h"
#include "tcg-accel-ops-mttcg.h" #include "tcg-accel-ops-mttcg.h"
typedef struct MttcgForceRcuNotifier {
Notifier notifier;
CPUState *cpu;
} MttcgForceRcuNotifier;
static void do_nothing(CPUState *cpu, run_on_cpu_data d)
{
}
static void mttcg_force_rcu(Notifier *notify, void *data)
{
CPUState *cpu = container_of(notify, MttcgForceRcuNotifier, notifier)->cpu;
/*
* Called with rcu_registry_lock held, using async_run_on_cpu() ensures
* that there are no deadlocks.
*/
async_run_on_cpu(cpu, do_nothing, RUN_ON_CPU_NULL);
}
/* /*
* In the multi-threaded case each vCPU has its own thread. The TLS * In the multi-threaded case each vCPU has its own thread. The TLS
* variable current_cpu can be used deep in the code to find the * variable current_cpu can be used deep in the code to find the
@ -43,12 +64,16 @@
static void *mttcg_cpu_thread_fn(void *arg) static void *mttcg_cpu_thread_fn(void *arg)
{ {
MttcgForceRcuNotifier force_rcu;
CPUState *cpu = arg; CPUState *cpu = arg;
assert(tcg_enabled()); assert(tcg_enabled());
g_assert(!icount_enabled()); g_assert(!icount_enabled());
rcu_register_thread(); rcu_register_thread();
force_rcu.notifier.notify = mttcg_force_rcu;
force_rcu.cpu = cpu;
rcu_add_force_rcu_notifier(&force_rcu.notifier);
tcg_register_thread(); tcg_register_thread();
qemu_mutex_lock_iothread(); qemu_mutex_lock_iothread();
@ -100,6 +125,7 @@ static void *mttcg_cpu_thread_fn(void *arg)
tcg_cpus_destroy(cpu); tcg_cpus_destroy(cpu);
qemu_mutex_unlock_iothread(); qemu_mutex_unlock_iothread();
rcu_remove_force_rcu_notifier(&force_rcu.notifier);
rcu_unregister_thread(); rcu_unregister_thread();
return NULL; return NULL;
} }

View File

@ -28,6 +28,7 @@
#include "sysemu/tcg.h" #include "sysemu/tcg.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/notify.h"
#include "qemu/guest-random.h" #include "qemu/guest-random.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
@ -135,6 +136,11 @@ static void rr_deal_with_unplugged_cpus(void)
} }
} }
static void rr_force_rcu(Notifier *notify, void *data)
{
rr_kick_next_cpu();
}
/* /*
* In the single-threaded case each vCPU is simulated in turn. If * In the single-threaded case each vCPU is simulated in turn. If
* there is more than a single vCPU we create a simple timer to kick * there is more than a single vCPU we create a simple timer to kick
@ -145,10 +151,13 @@ static void rr_deal_with_unplugged_cpus(void)
static void *rr_cpu_thread_fn(void *arg) static void *rr_cpu_thread_fn(void *arg)
{ {
Notifier force_rcu;
CPUState *cpu = arg; CPUState *cpu = arg;
assert(tcg_enabled()); assert(tcg_enabled());
rcu_register_thread(); rcu_register_thread();
force_rcu.notify = rr_force_rcu;
rcu_add_force_rcu_notifier(&force_rcu);
tcg_register_thread(); tcg_register_thread();
qemu_mutex_lock_iothread(); qemu_mutex_lock_iothread();
@ -257,6 +266,7 @@ static void *rr_cpu_thread_fn(void *arg)
rr_deal_with_unplugged_cpus(); rr_deal_with_unplugged_cpus();
} }
rcu_remove_force_rcu_notifier(&force_rcu);
rcu_unregister_thread(); rcu_unregister_thread();
return NULL; return NULL;
} }

View File

@ -31,6 +31,19 @@
#include "exec/log.h" #include "exec/log.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
//// --- Begin LibAFL code ---
#define EXCP_LIBAFL_BP 0xf4775747
void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env)
{
CPUState* cpu = env_cpu(env);
cpu->exception_index = EXCP_LIBAFL_BP;
cpu_loop_exit(cpu);
}
//// --- End LibAFL code ---
/* 32-bit helpers */ /* 32-bit helpers */
int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2) int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2)

View File

@ -285,3 +285,9 @@ DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
//// --- Begin LibAFL code ---
DEF_HELPER_FLAGS_1(libafl_qemu_handle_breakpoint, TCG_CALL_NO_RWG, void, env)
//// --- End LibAFL code ---

View File

@ -61,6 +61,386 @@
#include "tb-context.h" #include "tb-context.h"
#include "internal.h" #include "internal.h"
//// --- Begin LibAFL code ---
#include "tcg/tcg-op.h"
#include "tcg/tcg-internal.h"
#include "exec/helper-head.h"
void libafl_helper_table_add(TCGHelperInfo* info);
void libafl_gen_jmp(target_ulong src, target_ulong dst);
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block);
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong dst_block, target_ulong cs_base,
uint32_t flags, int cflags);
void libafl_gen_read(TCGv addr, MemOp ot);
void libafl_gen_read_N(TCGv addr, uint32_t size);
void libafl_gen_write(TCGv addr, MemOp ot);
void libafl_gen_write_N(TCGv addr, uint32_t size);
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot);
void (*libafl_exec_edge_hook)(uint64_t id);
uint64_t (*libafl_gen_edge_hook)(uint64_t src, uint64_t dst);
void (*libafl_exec_jmp_hook)(uint64_t src, uint64_t dst, uint64_t id);
uint64_t (*libafl_gen_jmp_hook)(uint64_t src, uint64_t dst);
static TCGHelperInfo libafl_exec_edge_hook_info = {
.func = NULL, .name = "libafl_exec_edge_hook", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
};
static int exec_edge_hook_added = 0;
static TCGHelperInfo libafl_exec_jmp_hook_info = {
.func = NULL, .name = "libafl_exec_jmp_hook", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 3)
};
static int exec_jmp_hook_added = 0;
void (*libafl_exec_block_hook)(uint64_t id);
uint64_t (*libafl_gen_block_hook)(uint64_t pc);
static TCGHelperInfo libafl_exec_block_hook_info = {
.func = NULL, .name = "libafl_exec_block_hook", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
};
static int exec_block_hook_added = 0;
void (*libafl_exec_read_hook1)(uint64_t id, uint64_t addr);
void (*libafl_exec_read_hook2)(uint64_t id, uint64_t addr);
void (*libafl_exec_read_hook4)(uint64_t id, uint64_t addr);
void (*libafl_exec_read_hook8)(uint64_t id, uint64_t addr);
void (*libafl_exec_read_hookN)(uint64_t id, uint64_t addr, uint32_t size);
uint64_t (*libafl_gen_read_hook)(uint32_t size);
static TCGHelperInfo libafl_exec_read_hook1_info = {
.func = NULL, .name = "libafl_exec_read_hook1", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_read_hook2_info = {
.func = NULL, .name = "libafl_exec_read_hook2", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_read_hook4_info = {
.func = NULL, .name = "libafl_exec_read_hook4", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_read_hook8_info = {
.func = NULL, .name = "libafl_exec_read_hook8", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_read_hookN_info = {
.func = NULL, .name = "libafl_exec_read_hookN", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) | dh_typemask(i32, 2)
};
static int exec_read_hook_added = 0;
void libafl_gen_read(TCGv addr, MemOp ot)
{
uint32_t size = 0;
void* func = NULL;
switch (ot & MO_SIZE) {
case MO_64:
size = 8;
func = libafl_exec_read_hook8;
break;
case MO_32:
size = 4;
func = libafl_exec_read_hook4;
break;
case MO_16:
size = 2;
func = libafl_exec_read_hook2;
break;
case MO_8:
size = 1;
func = libafl_exec_read_hook1;
break;
default:
return;
}
uint32_t libafl_id = 0;
if (libafl_gen_read_hook)
libafl_id = libafl_gen_read_hook(size);
if (func && libafl_id != (uint32_t)-1) {
if (!exec_read_hook_added) {
exec_read_hook_added = 1;
libafl_exec_read_hook1_info.func = libafl_exec_read_hook1;
libafl_helper_table_add(&libafl_exec_read_hook1_info);
libafl_exec_read_hook2_info.func = libafl_exec_read_hook2;
libafl_helper_table_add(&libafl_exec_read_hook2_info);
libafl_exec_read_hook4_info.func = libafl_exec_read_hook4;
libafl_helper_table_add(&libafl_exec_read_hook4_info);
libafl_exec_read_hook8_info.func = libafl_exec_read_hook8;
libafl_helper_table_add(&libafl_exec_read_hook8_info);
libafl_exec_read_hookN_info.func = libafl_exec_read_hookN;
libafl_helper_table_add(&libafl_exec_read_hookN_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGTemp *tmp1[2] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(addr) };
#else
tcgv_i64_temp(addr) };
#endif
tcg_gen_callN(func, NULL, 2, tmp1);
tcg_temp_free_i64(tmp0);
}
}
void libafl_gen_read_N(TCGv addr, uint32_t size)
{
uint32_t libafl_id = 0;
if (libafl_gen_read_hook)
libafl_id = libafl_gen_read_hook(size);
if (libafl_id != (uint32_t)-1) {
if (!exec_read_hook_added) {
exec_read_hook_added = 1;
libafl_exec_read_hook1_info.func = libafl_exec_read_hook1;
libafl_helper_table_add(&libafl_exec_read_hook1_info);
libafl_exec_read_hook2_info.func = libafl_exec_read_hook2;
libafl_helper_table_add(&libafl_exec_read_hook2_info);
libafl_exec_read_hook4_info.func = libafl_exec_read_hook4;
libafl_helper_table_add(&libafl_exec_read_hook4_info);
libafl_exec_read_hook8_info.func = libafl_exec_read_hook8;
libafl_helper_table_add(&libafl_exec_read_hook8_info);
libafl_exec_read_hookN_info.func = libafl_exec_read_hookN;
libafl_helper_table_add(&libafl_exec_read_hookN_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGv_i32 tmp1 = tcg_const_i32(size);
TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(addr),
#else
tcgv_i64_temp(addr),
#endif
tcgv_i32_temp(tmp1)
};
tcg_gen_callN(libafl_exec_read_hookN, NULL, 3, tmp2);
tcg_temp_free_i32(tmp1);
tcg_temp_free_i64(tmp0);
}
}
void (*libafl_exec_write_hook1)(uint64_t id, uint64_t addr);
void (*libafl_exec_write_hook2)(uint64_t id, uint64_t addr);
void (*libafl_exec_write_hook4)(uint64_t id, uint64_t addr);
void (*libafl_exec_write_hook8)(uint64_t id, uint64_t addr);
void (*libafl_exec_write_hookN)(uint64_t id, uint64_t addr, uint32_t size);
uint64_t (*libafl_gen_write_hook)(uint32_t size);
static TCGHelperInfo libafl_exec_write_hook1_info = {
.func = NULL, .name = "libafl_exec_write_hook1", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_write_hook2_info = {
.func = NULL, .name = "libafl_exec_write_hook2", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_write_hook4_info = {
.func = NULL, .name = "libafl_exec_write_hook4", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_write_hook8_info = {
.func = NULL, .name = "libafl_exec_write_hook8", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_write_hookN_info = {
.func = NULL, .name = "libafl_exec_write_hookN", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) | dh_typemask(i32, 2)
};
static int exec_write_hook_added = 0;
void libafl_gen_write(TCGv addr, MemOp ot)
{
uint32_t size = 0;
void* func = NULL;
switch (ot & MO_SIZE) {
case MO_64:
size = 8;
func = libafl_exec_write_hook8;
break;
case MO_32:
size = 4;
func = libafl_exec_write_hook4;
break;
case MO_16:
size = 2;
func = libafl_exec_write_hook2;
break;
case MO_8:
size = 1;
func = libafl_exec_write_hook1;
break;
default:
return;
}
uint32_t libafl_id = 0;
if (libafl_gen_write_hook)
libafl_id = libafl_gen_write_hook(size);
if (func && libafl_id != (uint32_t)-1) {
if (!exec_write_hook_added) {
exec_write_hook_added = 1;
libafl_exec_write_hook1_info.func = libafl_exec_write_hook1;
libafl_helper_table_add(&libafl_exec_write_hook1_info);
libafl_exec_write_hook2_info.func = libafl_exec_write_hook2;
libafl_helper_table_add(&libafl_exec_write_hook2_info);
libafl_exec_write_hook4_info.func = libafl_exec_write_hook4;
libafl_helper_table_add(&libafl_exec_write_hook4_info);
libafl_exec_write_hook8_info.func = libafl_exec_write_hook8;
libafl_helper_table_add(&libafl_exec_write_hook8_info);
libafl_exec_write_hookN_info.func = libafl_exec_write_hookN;
libafl_helper_table_add(&libafl_exec_write_hookN_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGTemp *tmp1[2] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(addr) };
#else
tcgv_i64_temp(addr) };
#endif
tcg_gen_callN(func, NULL, 2, tmp1);
tcg_temp_free_i64(tmp0);
}
}
void libafl_gen_write_N(TCGv addr, uint32_t size)
{
uint32_t libafl_id = 0;
if (libafl_gen_write_hook)
libafl_id = libafl_gen_write_hook(size);
if (libafl_id != (uint32_t)-1) {
if (!exec_write_hook_added) {
exec_write_hook_added = 1;
libafl_exec_write_hook1_info.func = libafl_exec_write_hook1;
libafl_helper_table_add(&libafl_exec_write_hook1_info);
libafl_exec_write_hook2_info.func = libafl_exec_write_hook2;
libafl_helper_table_add(&libafl_exec_write_hook2_info);
libafl_exec_write_hook4_info.func = libafl_exec_write_hook4;
libafl_helper_table_add(&libafl_exec_write_hook4_info);
libafl_exec_write_hook8_info.func = libafl_exec_write_hook8;
libafl_helper_table_add(&libafl_exec_write_hook8_info);
libafl_exec_write_hookN_info.func = libafl_exec_write_hookN;
libafl_helper_table_add(&libafl_exec_write_hookN_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGv_i32 tmp1 = tcg_const_i32(size);
TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(addr),
#else
tcgv_i64_temp(addr),
#endif
tcgv_i32_temp(tmp1)
};
tcg_gen_callN(libafl_exec_write_hookN, NULL, 3, tmp2);
tcg_temp_free_i32(tmp1);
tcg_temp_free_i64(tmp0);
}
}
void (*libafl_exec_cmp_hook1)(uint64_t id, uint8_t v0, uint8_t v1);
void (*libafl_exec_cmp_hook2)(uint64_t id, uint16_t v0, uint16_t v1);
void (*libafl_exec_cmp_hook4)(uint64_t id, uint32_t v0, uint32_t v1);
void (*libafl_exec_cmp_hook8)(uint64_t id, uint64_t v0, uint64_t v1);
uint64_t (*libafl_gen_cmp_hook)(uint64_t pc, uint32_t size);
static TCGHelperInfo libafl_exec_cmp_hook1_info = {
.func = NULL, .name = "libafl_exec_cmp_hook1", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
};
static TCGHelperInfo libafl_exec_cmp_hook2_info = {
.func = NULL, .name = "libafl_exec_cmp_hook2", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
};
static TCGHelperInfo libafl_exec_cmp_hook4_info = {
.func = NULL, .name = "libafl_exec_cmp_hook4", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
};
static TCGHelperInfo libafl_exec_cmp_hook8_info = {
.func = NULL, .name = "libafl_exec_cmp_hook8", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
};
static int exec_cmp_hook_added = 0;
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot)
{
uint32_t size = 0;
void* func = NULL;
switch (ot & MO_SIZE) {
case MO_64:
size = 8;
func = libafl_exec_cmp_hook8;
break;
case MO_32:
size = 4;
func = libafl_exec_cmp_hook4;
break;
case MO_16:
size = 2;
func = libafl_exec_cmp_hook2;
break;
case MO_8:
size = 1;
func = libafl_exec_cmp_hook1;
break;
default:
return;
}
uint32_t libafl_id = 0;
if (libafl_gen_cmp_hook)
libafl_id = libafl_gen_cmp_hook((uint64_t)pc, size);
if (func && libafl_id != (uint32_t)-1) {
if (!exec_cmp_hook_added) {
exec_cmp_hook_added = 1;
libafl_exec_cmp_hook1_info.func = libafl_exec_cmp_hook1;
libafl_helper_table_add(&libafl_exec_cmp_hook1_info);
libafl_exec_cmp_hook2_info.func = libafl_exec_cmp_hook2;
libafl_helper_table_add(&libafl_exec_cmp_hook2_info);
libafl_exec_cmp_hook4_info.func = libafl_exec_cmp_hook4;
libafl_helper_table_add(&libafl_exec_cmp_hook4_info);
libafl_exec_cmp_hook8_info.func = libafl_exec_cmp_hook8;
libafl_helper_table_add(&libafl_exec_cmp_hook8_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGTemp *tmp1[3] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(op0), tcgv_i32_temp(op1) };
#else
tcgv_i64_temp(op0), tcgv_i64_temp(op1) };
#endif
tcg_gen_callN(func, NULL, 3, tmp1);
tcg_temp_free_i64(tmp0);
}
}
//// --- End LibAFL code ---
/* #define DEBUG_TB_INVALIDATE */ /* #define DEBUG_TB_INVALIDATE */
/* #define DEBUG_TB_FLUSH */ /* #define DEBUG_TB_FLUSH */
/* make various TB consistency checks */ /* make various TB consistency checks */
@ -1400,6 +1780,157 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
return tb; return tb;
} }
//// --- Begin LibAFL code ---
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block)
{
uint32_t libafl_id = 0;
if (libafl_gen_edge_hook)
libafl_id = libafl_gen_edge_hook((uint64_t)src_block, (uint64_t)dst_block);
if (!libafl_exec_edge_hook || libafl_id == (uint32_t)-1)
return;
if (!exec_edge_hook_added) {
exec_edge_hook_added = 1;
libafl_exec_edge_hook_info.func = libafl_exec_edge_hook;
libafl_helper_table_add(&libafl_exec_edge_hook_info);
}
libafl_exec_edge_hook(libafl_id);
}
void libafl_gen_jmp(target_ulong src, target_ulong dst)
{
uint32_t libafl_id = 0;
if (libafl_gen_jmp_hook)
libafl_id = libafl_gen_jmp_hook((uint64_t)src, (uint64_t)dst);
if (!libafl_exec_jmp_hook || libafl_id == (uint32_t)-1)
return;
if (!exec_jmp_hook_added) {
exec_jmp_hook_added = 1;
libafl_exec_jmp_hook_info.func = libafl_exec_jmp_hook;
libafl_helper_table_add(&libafl_exec_jmp_hook_info);
}
TCGv_i64 tmp0 = tcg_const_i64(src);
TCGv_i64 tmp1 = tcg_const_i64(dst);
TCGv_i64 tmp2 = tcg_const_i64(libafl_id);
TCGTemp *tmp3[3] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1), tcgv_i64_temp(tmp2) };
tcg_gen_callN(libafl_exec_jmp_hook, NULL, 3, tmp3);
tcg_temp_free_i64(tmp0);
}
/* Called with mmap_lock held for user mode emulation. */
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong dst_block, target_ulong cs_base,
uint32_t flags, int cflags)
{
CPUArchState *env = cpu->env_ptr;
TranslationBlock *tb;
tcg_insn_unit *gen_code_buf;
int gen_code_size, search_size;
assert_memory_lock();
uint32_t libafl_id = 0;
if (libafl_gen_edge_hook)
libafl_id = libafl_gen_edge_hook((uint64_t)src_block, (uint64_t)dst_block);
if (!libafl_exec_edge_hook || libafl_id == (uint32_t)-1)
return NULL;
if (!exec_edge_hook_added) {
exec_edge_hook_added = 1;
libafl_exec_edge_hook_info.func = libafl_exec_edge_hook;
libafl_helper_table_add(&libafl_exec_edge_hook_info);
}
buffer_overflow1:
tb = tcg_tb_alloc(tcg_ctx);
if (unlikely(!tb)) {
/* flush must be done */
tb_flush(cpu);
mmap_unlock();
/* Make the execution loop process the flush as soon as possible. */
cpu->exception_index = EXCP_INTERRUPT;
cpu_loop_exit(cpu);
}
libafl_exec_edge_hook(libafl_id);
gen_code_buf = tcg_ctx->code_gen_ptr;
tb->tc.ptr = gen_code_buf;
tb->pc = 0;
tb->cs_base = cs_base;
tb->flags = flags;
tb->cflags = cflags;
tb->trace_vcpu_dstate = *cpu->trace_dstate;
tb->icount = 0;
tcg_ctx->tb_cflags = 0;
tcg_func_start(tcg_ctx);
tcg_ctx->cpu = env_cpu(env);
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
tcg_gen_callN(libafl_exec_edge_hook, NULL, 1, tmp1);
tcg_temp_free_i64(tmp0);
tcg_gen_goto_tb(0);
tcg_gen_exit_tb(tb, 0);
tcg_ctx->cpu = NULL;
trace_translate_block(tb, tb->pc, tb->tc.ptr);
/* generate machine code */
tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;
tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID;
tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset;
if (TCG_TARGET_HAS_direct_jump) {
tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg;
tcg_ctx->tb_jmp_target_addr = NULL;
} else {
tcg_ctx->tb_jmp_insn_offset = NULL;
tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg;
}
/* ??? Overflow could be handled better here. In particular, we
don't need to re-do gen_intermediate_code, nor should we re-do
the tcg optimization currently hidden inside tcg_gen_code. All
that should be required is to flush the TBs, allocate a new TB,
re-initialize it per above, and re-do the actual code generation. */
gen_code_size = tcg_gen_code(tcg_ctx, tb);
if (unlikely(gen_code_size < 0)) {
goto buffer_overflow1;
}
search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);
if (unlikely(search_size < 0)) {
goto buffer_overflow1;
}
tb->tc.size = gen_code_size;
qatomic_set(&tcg_ctx->code_gen_ptr, (void *)
ROUND_UP((uintptr_t)gen_code_buf + gen_code_size + search_size,
CODE_GEN_ALIGN));
/* init jump list */
qemu_spin_init(&tb->jmp_lock);
tb->jmp_list_head = (uintptr_t)NULL;
tb->jmp_list_next[0] = (uintptr_t)NULL;
tb->jmp_list_next[1] = (uintptr_t)NULL;
tb->jmp_dest[0] = (uintptr_t)NULL;
tb->jmp_dest[1] = (uintptr_t)NULL;
/* init original jump addresses which have been set during tcg_gen_code() */
if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) {
tb_reset_jump(tb, 0);
}
if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
tb_reset_jump(tb, 1);
}
return tb;
}
//// --- End LibAFL code ---
/* Called with mmap_lock held for user mode emulation. */ /* Called with mmap_lock held for user mode emulation. */
TranslationBlock *tb_gen_code(CPUState *cpu, TranslationBlock *tb_gen_code(CPUState *cpu,
target_ulong pc, target_ulong cs_base, target_ulong pc, target_ulong cs_base,
@ -1450,6 +1981,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tb->flags = flags; tb->flags = flags;
tb->cflags = cflags; tb->cflags = cflags;
tb->trace_vcpu_dstate = *cpu->trace_dstate; tb->trace_vcpu_dstate = *cpu->trace_dstate;
tb->icount = 0;
tcg_ctx->tb_cflags = cflags; tcg_ctx->tb_cflags = cflags;
tb_overflow: tb_overflow:
@ -1467,6 +1999,26 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tcg_func_start(tcg_ctx); tcg_func_start(tcg_ctx);
tcg_ctx->cpu = env_cpu(env); tcg_ctx->cpu = env_cpu(env);
//// --- Begin LibAFL code ---
uint32_t libafl_id = 0;
if (libafl_gen_block_hook)
libafl_id = libafl_gen_block_hook((uint64_t)pc);
if (libafl_exec_block_hook && libafl_id != (uint32_t)-1) {
if (!exec_block_hook_added) {
exec_block_hook_added = 1;
libafl_exec_block_hook_info.func = libafl_exec_block_hook;
libafl_helper_table_add(&libafl_exec_block_hook_info);
}
TCGv_i64 tmp0 = tcg_const_i64((uint64_t)pc);
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
tcg_gen_callN(libafl_exec_block_hook, NULL, 1, tmp1);
tcg_temp_free_i64(tmp0);
}
//// --- End LibAFL code ---
gen_intermediate_code(cpu, tb, max_insns); gen_intermediate_code(cpu, tb, max_insns);
assert(tb->size != 0); assert(tb->size != 0);
tcg_ctx->cpu = NULL; tcg_ctx->cpu = NULL;

View File

@ -18,6 +18,29 @@
#include "exec/plugin-gen.h" #include "exec/plugin-gen.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
//// --- Begin LibAFL code ---
#include "tcg/tcg-internal.h"
struct libafl_breakpoint {
target_ulong addr;
struct libafl_breakpoint* next;
};
extern struct libafl_breakpoint* libafl_qemu_breakpoints;
struct libafl_hook {
target_ulong addr;
void (*callback)(uint64_t);
uint64_t value;
TCGHelperInfo helper_info;
struct libafl_hook* next;
};
extern struct libafl_hook* libafl_qemu_hooks;
//// --- End LibAFL code ---
/* Pairs with tcg_clear_temp_count. /* Pairs with tcg_clear_temp_count.
To be called by #TranslatorOps.{translate_insn,tb_stop} if To be called by #TranslatorOps.{translate_insn,tb_stop} if
(1) the target is sufficiently clean to support reporting, (1) the target is sufficiently clean to support reporting,
@ -79,6 +102,29 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
plugin_gen_insn_start(cpu, db); plugin_gen_insn_start(cpu, db);
} }
//// --- Begin LibAFL code ---
struct libafl_hook* hk = libafl_qemu_hooks;
while (hk) {
if (hk->addr == db->pc_next) {
TCGv_i64 tmp0 = tcg_const_i64(hk->value);
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
tcg_gen_callN(hk->callback, NULL, 1, tmp1);
tcg_temp_free_i64(tmp0);
}
hk = hk->next;
}
struct libafl_breakpoint* bp = libafl_qemu_breakpoints;
while (bp) {
if (bp->addr == db->pc_next) {
gen_helper_libafl_qemu_handle_breakpoint(cpu_env);
}
bp = bp->next;
}
//// --- End LibAFL code ---
/* Disassemble one instruction. The translate_insn hook should /* Disassemble one instruction. The translate_insn hook should
update db->pc_next and db->is_jmp to indicate what should be update db->pc_next and db->is_jmp to indicate what should be
done next -- either exiting this loop or locate the start of done next -- either exiting this loop or locate the start of

View File

@ -1978,6 +1978,12 @@ uint32_t blk_get_max_transfer(BlockBackend *blk)
return ROUND_DOWN(max, blk_get_request_alignment(blk)); return ROUND_DOWN(max, blk_get_request_alignment(blk));
} }
int blk_get_max_hw_iov(BlockBackend *blk)
{
return MIN_NON_ZERO(blk->root->bs->bl.max_hw_iov,
blk->root->bs->bl.max_iov);
}
int blk_get_max_iov(BlockBackend *blk) int blk_get_max_iov(BlockBackend *blk)
{ {
return blk->root->bs->bl.max_iov; return blk->root->bs->bl.max_iov;

View File

@ -1273,7 +1273,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
ret = hdev_get_max_segments(s->fd, &st); ret = hdev_get_max_segments(s->fd, &st);
if (ret > 0) { if (ret > 0) {
bs->bl.max_iov = ret; bs->bl.max_hw_iov = ret;
} }
} }
} }
@ -1807,7 +1807,7 @@ static int handle_aiocb_copy_range(void *opaque)
static int handle_aiocb_discard(void *opaque) static int handle_aiocb_discard(void *opaque)
{ {
RawPosixAIOData *aiocb = opaque; RawPosixAIOData *aiocb = opaque;
int ret = -EOPNOTSUPP; int ret = -ENOTSUP;
BDRVRawState *s = aiocb->bs->opaque; BDRVRawState *s = aiocb->bs->opaque;
if (!s->has_discard) { if (!s->has_discard) {
@ -1829,7 +1829,7 @@ static int handle_aiocb_discard(void *opaque)
#ifdef CONFIG_FALLOCATE_PUNCH_HOLE #ifdef CONFIG_FALLOCATE_PUNCH_HOLE
ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
aiocb->aio_offset, aiocb->aio_nbytes); aiocb->aio_offset, aiocb->aio_nbytes);
ret = translate_err(-errno); ret = translate_err(ret);
#elif defined(__APPLE__) && (__MACH__) #elif defined(__APPLE__) && (__MACH__)
fpunchhole_t fpunchhole; fpunchhole_t fpunchhole;
fpunchhole.fp_flags = 0; fpunchhole.fp_flags = 0;

View File

@ -136,6 +136,7 @@ static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
dst->min_mem_alignment = MAX(dst->min_mem_alignment, dst->min_mem_alignment = MAX(dst->min_mem_alignment,
src->min_mem_alignment); src->min_mem_alignment);
dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov); dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov);
dst->max_hw_iov = MIN_NON_ZERO(dst->max_hw_iov, src->max_hw_iov);
} }
typedef struct BdrvRefreshLimitsState { typedef struct BdrvRefreshLimitsState {

View File

@ -320,7 +320,6 @@ static void wctablet_chr_finalize(Object *obj)
TabletChardev *tablet = WCTABLET_CHARDEV(obj); TabletChardev *tablet = WCTABLET_CHARDEV(obj);
qemu_input_handler_unregister(tablet->hs); qemu_input_handler_unregister(tablet->hs);
g_free(tablet);
} }
static void wctablet_chr_open(Chardev *chr, static void wctablet_chr_open(Chardev *chr,

29
configure vendored
View File

@ -835,6 +835,8 @@ if test "$mingw32" = "yes" ; then
fi fi
werror="" werror=""
as_shared_lib="no"
as_static_lib="no"
for opt do for opt do
optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
@ -1581,6 +1583,16 @@ for opt do
;; ;;
--disable-slirp-smbd) slirp_smbd=no --disable-slirp-smbd) slirp_smbd=no
;; ;;
--as-shared-lib)
as_shared_lib="yes"
QEMU_CFLAGS="$QEMU_CFLAGS -fPIC -DAS_LIB=1"
QEMU_CXXFLAGS="$QEMU_CXXFLAGS -fPIC -DAS_LIB=1"
;;
--as-static-lib)
as_static_lib="yes"
QEMU_CFLAGS="$QEMU_CFLAGS -fPIC -DAS_LIB=1"
QEMU_CXXFLAGS="$QEMU_CXXFLAGS -fPIC -DAS_LIB=1"
;;
*) *)
echo "ERROR: unknown option $opt" echo "ERROR: unknown option $opt"
echo "Try '$0 --help' for more information" echo "Try '$0 --help' for more information"
@ -2246,9 +2258,11 @@ static THREAD int tls_var;
int main(void) { return tls_var; } int main(void) { return tls_var; }
EOF EOF
# Check we support --no-pie first; we will need this for building ROMs. # Check we support -fno-pie and -no-pie first; we will need the former for
# building ROMs, and both for everything if --disable-pie is passed.
if compile_prog "-Werror -fno-pie" "-no-pie"; then if compile_prog "-Werror -fno-pie" "-no-pie"; then
CFLAGS_NOPIE="-fno-pie" CFLAGS_NOPIE="-fno-pie"
LDFLAGS_NOPIE="-no-pie"
fi fi
if test "$static" = "yes"; then if test "$static" = "yes"; then
@ -2264,6 +2278,7 @@ if test "$static" = "yes"; then
fi fi
elif test "$pie" = "no"; then elif test "$pie" = "no"; then
CONFIGURE_CFLAGS="$CFLAGS_NOPIE $CONFIGURE_CFLAGS" CONFIGURE_CFLAGS="$CFLAGS_NOPIE $CONFIGURE_CFLAGS"
CONFIGURE_LDFLAGS="$LDFLAGS_NOPIE $CONFIGURE_LDFLAGS"
elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then elif compile_prog "-Werror -fPIE -DPIE" "-pie"; then
CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS" CONFIGURE_CFLAGS="-fPIE -DPIE $CONFIGURE_CFLAGS"
CONFIGURE_LDFLAGS="-pie $CONFIGURE_LDFLAGS" CONFIGURE_LDFLAGS="-pie $CONFIGURE_LDFLAGS"
@ -3187,9 +3202,8 @@ glib_req_ver=2.56
glib_modules=gthread-2.0 glib_modules=gthread-2.0
if test "$modules" = yes; then if test "$modules" = yes; then
glib_modules="$glib_modules gmodule-export-2.0" glib_modules="$glib_modules gmodule-export-2.0"
fi elif test "$plugins" = "yes"; then
if test "$plugins" = "yes"; then glib_modules="$glib_modules gmodule-no-export-2.0"
glib_modules="$glib_modules gmodule-2.0"
fi fi
for i in $glib_modules; do for i in $glib_modules; do
@ -4917,6 +4931,13 @@ if test "$secret_keyring" = "yes" ; then
echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak echo "CONFIG_SECRET_KEYRING=y" >> $config_host_mak
fi fi
if test "$as_shared_lib" = "yes" ; then
echo "AS_SHARED_LIB=y" >> $config_host_mak
fi
if test "$as_static_lib" = "yes" ; then
echo "AS_STATIC_LIB=y" >> $config_host_mak
fi
echo "ROMS=$roms" >> $config_host_mak echo "ROMS=$roms" >> $config_host_mak
echo "MAKE=$make" >> $config_host_mak echo "MAKE=$make" >> $config_host_mak
echo "PYTHON=$python" >> $config_host_mak echo "PYTHON=$python" >> $config_host_mak

View File

@ -67,7 +67,7 @@ static void vcpu_insn_exec(unsigned int cpu_index, void *udata)
/* Print previous instruction in cache */ /* Print previous instruction in cache */
if (s->len) { if (s->len) {
qemu_plugin_outs(s->str); qemu_plugin_outs(s->str);
qemu_plugin_outs("s\n"); qemu_plugin_outs("\n");
} }
/* Store new instruction in cache */ /* Store new instruction in cache */

204
cpu.c
View File

@ -40,6 +40,187 @@
#include "hw/core/accel-cpu.h" #include "hw/core/accel-cpu.h"
#include "trace/trace-root.h" #include "trace/trace-root.h"
//// --- Begin LibAFL code ---
#include "tcg/tcg-op.h"
#include "tcg/tcg-internal.h"
#include "exec/helper-head.h"
struct libafl_breakpoint {
target_ulong addr;
struct libafl_breakpoint* next;
};
struct libafl_breakpoint* libafl_qemu_breakpoints = NULL;
struct libafl_hook {
target_ulong addr;
void (*callback)(uint64_t);
uint64_t value;
TCGHelperInfo helper_info;
struct libafl_hook* next;
};
struct libafl_hook* libafl_qemu_hooks = NULL;
__thread CPUArchState *libafl_qemu_env;
void libafl_helper_table_add(TCGHelperInfo* info);
static GByteArray *libafl_qemu_mem_buf = NULL;
int libafl_qemu_write_reg(int reg, uint8_t* val);
int libafl_qemu_read_reg(int reg, uint8_t* val);
int libafl_qemu_num_regs(void);
int libafl_qemu_set_breakpoint(uint64_t addr);
int libafl_qemu_remove_breakpoint(uint64_t addr);
int libafl_qemu_set_hook(uint64_t addr, void (*callback)(uint64_t), uint64_t value);
int libafl_qemu_remove_hook(uint64_t addr);
int libafl_qemu_write_reg(int reg, uint8_t* val)
{
CPUState *cpu = current_cpu;
if (!cpu) {
cpu = env_cpu(libafl_qemu_env);
if (!cpu) {
return 0;
}
}
CPUClass *cc = CPU_GET_CLASS(cpu);
if (reg < cc->gdb_num_core_regs) {
return cc->gdb_write_register(cpu, val, reg);
}
return 0;
}
int libafl_qemu_read_reg(int reg, uint8_t* val)
{
CPUState *cpu = current_cpu;
if (!cpu) {
cpu = env_cpu(libafl_qemu_env);
if (!cpu) {
return 0;
}
}
if (libafl_qemu_mem_buf == NULL) {
libafl_qemu_mem_buf = g_byte_array_sized_new(64);
}
CPUClass *cc = CPU_GET_CLASS(cpu);
if (reg < cc->gdb_num_core_regs) {
g_byte_array_set_size(libafl_qemu_mem_buf, 0);
int len = cc->gdb_read_register(cpu, libafl_qemu_mem_buf, reg);
if (len > 0) {
memcpy(val, libafl_qemu_mem_buf->data, len);
}
return len;
}
return 0;
}
int libafl_qemu_num_regs(void)
{
CPUState *cpu = current_cpu;
if (!cpu) {
cpu = env_cpu(libafl_qemu_env);
if (!cpu) {
return 0;
}
}
CPUClass *cc = CPU_GET_CLASS(cpu);
return cc->gdb_num_core_regs;
}
void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc);
int libafl_qemu_set_breakpoint(uint64_t addr)
{
CPUState *cpu;
target_ulong pc = (target_ulong) addr;
CPU_FOREACH(cpu) {
libafl_breakpoint_invalidate(cpu, pc);
}
struct libafl_breakpoint* bp = malloc(sizeof(struct libafl_breakpoint));
bp->addr = pc;
bp->next = libafl_qemu_breakpoints;
libafl_qemu_breakpoints = bp;
return 1;
}
int libafl_qemu_remove_breakpoint(uint64_t addr)
{
CPUState *cpu;
int r = 0;
target_ulong pc = (target_ulong) addr;
struct libafl_breakpoint** bp = &libafl_qemu_breakpoints;
while (*bp) {
if ((*bp)->addr == pc) {
CPU_FOREACH(cpu) {
libafl_breakpoint_invalidate(cpu, pc);
}
*bp = (*bp)->next;
r = 1;
} else {
bp = &(*bp)->next;
}
}
return r;
}
int libafl_qemu_set_hook(uint64_t addr, void (*callback)(uint64_t), uint64_t value)
{
CPUState *cpu;
target_ulong pc = (target_ulong) addr;
CPU_FOREACH(cpu) {
libafl_breakpoint_invalidate(cpu, pc);
}
struct libafl_hook* hk = malloc(sizeof(struct libafl_hook));
hk->addr = pc;
hk->callback = callback;
hk->value = value;
hk->helper_info.func = callback;
hk->helper_info.name = "libafl_hook";
hk->helper_info.flags = dh_callflag(void);
hk->helper_info.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1);
hk->next = libafl_qemu_hooks;
libafl_qemu_hooks = hk;
libafl_helper_table_add(&hk->helper_info);
return 1;
}
int libafl_qemu_remove_hook(uint64_t addr)
{
CPUState *cpu;
int r = 0;
target_ulong pc = (target_ulong) addr;
struct libafl_hook** hk = &libafl_qemu_hooks;
while (*hk) {
if ((*hk)->addr == pc) {
CPU_FOREACH(cpu) {
libafl_breakpoint_invalidate(cpu, pc);
}
*hk = (*hk)->next;
r = 1;
} else {
hk = &(*hk)->next;
}
}
return r;
}
//// --- End LibAFL code ---
uintptr_t qemu_host_page_size; uintptr_t qemu_host_page_size;
intptr_t qemu_host_page_mask; intptr_t qemu_host_page_mask;
@ -58,7 +239,12 @@ static int cpu_common_post_load(void *opaque, int version_id)
* memory we've translated code from. So we must flush all TBs, * memory we've translated code from. So we must flush all TBs,
* which will now be stale. * which will now be stale.
*/ */
/* Begin LibAFL instrumentation */
// Do not flush old tbs on loadvm, when fuzzing in system-mode
#if !defined(CONFIG_USER_ONLY) && defined(AS_SHARED_LIB)
tb_flush(cpu); tb_flush(cpu);
#endif
/* End LibAFL instrumentation */
return 0; return 0;
} }
@ -225,6 +411,15 @@ void tb_invalidate_phys_addr(target_ulong addr)
tb_invalidate_phys_page_range(addr, addr + 1); tb_invalidate_phys_page_range(addr, addr + 1);
mmap_unlock(); mmap_unlock();
} }
//// --- Begin LibAFL code ---
void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
tb_invalidate_phys_addr(pc);
}
//// --- End LibAFL code ---
#else #else
void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs) void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
{ {
@ -245,6 +440,15 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs)
ram_addr = memory_region_get_ram_addr(mr) + addr; ram_addr = memory_region_get_ram_addr(mr) + addr;
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1); tb_invalidate_phys_page_range(ram_addr, ram_addr + 1);
} }
//// --- Begin LibAFL code ---
void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
tb_flush(cpu);
}
//// --- End LibAFL code ---
#endif #endif
/* Add a breakpoint. */ /* Add a breakpoint. */

View File

@ -98,8 +98,10 @@ driver options if ``--image-opts`` is specified.
.. option:: --cache=CACHE .. option:: --cache=CACHE
The cache mode to be used with the file. See the documentation of The cache mode to be used with the file. Valid values are:
the emulator's ``-drive cache=...`` option for allowed values. ``none``, ``writeback`` (the default), ``writethrough``,
``directsync`` and ``unsafe``. See the documentation of
the emulator's ``-drive cache=...`` option for more info.
.. option:: -n, --nocache .. option:: -n, --nocache

View File

@ -51,7 +51,9 @@
*/ \ */ \
qemu_coroutine_yield(); \ qemu_coroutine_yield(); \
qemu_bh_delete(co_bh); \ qemu_bh_delete(co_bh); \
do { \
code_block; \ code_block; \
} while (0); \
/* re-enter back to qemu thread */ \ /* re-enter back to qemu thread */ \
qemu_coroutine_yield(); \ qemu_coroutine_yield(); \
} while (0) } while (0)

View File

@ -2677,10 +2677,10 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
"Set the IOMMU type. " "Set the IOMMU type. "
"Valid values are none and smmuv3"); "Valid values are none and smmuv3");
object_class_property_add_bool(oc, "default_bus_bypass_iommu", object_class_property_add_bool(oc, "default-bus-bypass-iommu",
virt_get_default_bus_bypass_iommu, virt_get_default_bus_bypass_iommu,
virt_set_default_bus_bypass_iommu); virt_set_default_bus_bypass_iommu);
object_class_property_set_description(oc, "default_bus_bypass_iommu", object_class_property_set_description(oc, "default-bus-bypass-iommu",
"Set on/off to enable/disable " "Set on/off to enable/disable "
"bypass_iommu for default root bus"); "bypass_iommu for default root bus");

View File

@ -222,7 +222,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
memory_region_transaction_commit(); memory_region_transaction_commit();
while (j--) { while (j--) {
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), j);
} }
goto fail_host_notifiers; goto fail_host_notifiers;
} }

View File

@ -61,6 +61,12 @@
} while (0) } while (0)
/* Anonymous BlockBackend for empty drive */
static BlockBackend *blk_create_empty_drive(void)
{
return blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
}
/********************************************************/ /********************************************************/
/* qdev floppy bus */ /* qdev floppy bus */
@ -486,8 +492,7 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp)
} }
if (!dev->conf.blk) { if (!dev->conf.blk) {
/* Anonymous BlockBackend for an empty drive */ dev->conf.blk = blk_create_empty_drive();
dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
ret = blk_attach_dev(dev->conf.blk, qdev); ret = blk_attach_dev(dev->conf.blk, qdev);
assert(ret == 0); assert(ret == 0);
@ -1161,7 +1166,19 @@ static FDrive *get_drv(FDCtrl *fdctrl, int unit)
static FDrive *get_cur_drv(FDCtrl *fdctrl) static FDrive *get_cur_drv(FDCtrl *fdctrl)
{ {
return get_drv(fdctrl, fdctrl->cur_drv); FDrive *cur_drv = get_drv(fdctrl, fdctrl->cur_drv);
if (!cur_drv->blk) {
/*
* Kludge: empty drive line selected. Create an anonymous
* BlockBackend to avoid NULL deref with various BlockBackend
* API calls within this model (CVE-2021-20196).
* Due to the controller QOM model limitations, we don't
* attach the created to the controller device.
*/
cur_drv->blk = blk_create_empty_drive();
}
return cur_drv;
} }
/* Status A register : 0x00 (read-only) */ /* Status A register : 0x00 (read-only) */

View File

@ -43,6 +43,7 @@ GlobalProperty hw_compat_6_0[] = {
{ "nvme-ns", "eui64-default", "off"}, { "nvme-ns", "eui64-default", "off"},
{ "e1000", "init-vet", "off" }, { "e1000", "init-vet", "off" },
{ "e1000e", "init-vet", "off" }, { "e1000e", "init-vet", "off" },
{ "vhost-vsock-device", "seqpacket", "off" },
}; };
const size_t hw_compat_6_0_len = G_N_ELEMENTS(hw_compat_6_0); const size_t hw_compat_6_0_len = G_N_ELEMENTS(hw_compat_6_0);

View File

@ -1170,8 +1170,8 @@ static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val,
} }
buf = vram_write_buffer(s); buf = vram_write_buffer(s);
posy = ADDR_TO_Y(addr); posy = ADDR_TO_Y(addr >> 2);
posx = ADDR_TO_X(addr); posx = ADDR_TO_X(addr >> 2);
if (!buf->size) { if (!buf->size) {
return; return;
@ -1232,8 +1232,8 @@ static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size)
return 0; return 0;
} }
posy = ADDR_TO_Y(addr); posy = ADDR_TO_Y(addr >> 2);
posx = ADDR_TO_X(addr); posx = ADDR_TO_X(addr >> 2);
if (posy > buf->height || posx > buf->width) { if (posy > buf->height || posx > buf->width) {
return 0; return 0;

View File

@ -2252,7 +2252,7 @@ static int qxl_pre_save(void *opaque)
} else { } else {
d->last_release_offset = (uint8_t *)d->last_release - ram_start; d->last_release_offset = (uint8_t *)d->last_release - ram_start;
} }
if (d->last_release_offset < d->vga.vram_size) { if (d->last_release_offset >= d->vga.vram_size) {
return 1; return 1;
} }

View File

@ -1763,7 +1763,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, "hpet", object_class_property_add_bool(oc, "hpet",
pc_machine_get_hpet, pc_machine_set_hpet); pc_machine_get_hpet, pc_machine_set_hpet);
object_class_property_add_bool(oc, "default_bus_bypass_iommu", object_class_property_add_bool(oc, "default-bus-bypass-iommu",
pc_machine_get_default_bus_bypass_iommu, pc_machine_get_default_bus_bypass_iommu,
pc_machine_set_default_bus_bypass_iommu); pc_machine_set_default_bus_bypass_iommu);

View File

@ -243,7 +243,7 @@ static void pc_q35_init(MachineState *machine)
NULL); NULL);
if (acpi_pcihp) { if (acpi_pcihp) {
object_register_sugar_prop(TYPE_PCIE_SLOT, "native-hotplug", object_register_sugar_prop(TYPE_PCIE_SLOT, "x-native-hotplug",
"false", true); "false", true);
} }

View File

@ -2999,3 +2999,25 @@ static void armv7m_nvic_register_types(void)
} }
type_init(armv7m_nvic_register_types) type_init(armv7m_nvic_register_types)
/* Begin LibAFL instrumentation */
#include "qemu/main-loop.h"
void libafl_send_irq(int irqn);
void libafl_send_irq(int irqn) {
bool haslock = qemu_mutex_iothread_locked();
if (!haslock) {
qemu_mutex_lock_iothread();
}
CPUState *cpu;
CPU_FOREACH(cpu) {
CPUARMState* env = cpu->env_ptr;
NVICState* nvic = env->nvic;
// set_irq_level(nvic, irqn, 1);
// set_irq_level(nvic, irqn, 0);
armv7m_nvic_set_pending(nvic, irqn+16, false);
}
if (!haslock) {
qemu_mutex_unlock_iothread();
}
}
/* End LibAFL instrumentation */

View File

@ -304,7 +304,14 @@ type_init(virt_machine_register_types)
} \ } \
type_init(machvirt_machine_##major##_##minor##_init); type_init(machvirt_machine_##major##_##minor##_init);
static void virt_machine_6_0_options(MachineClass *mc) static void virt_machine_6_1_options(MachineClass *mc)
{ {
} }
DEFINE_VIRT_MACHINE(6, 0, true) DEFINE_VIRT_MACHINE(6, 1, true)
static void virt_machine_6_0_options(MachineClass *mc)
{
virt_machine_6_1_options(mc);
compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len);
}
DEFINE_VIRT_MACHINE(6, 0, false)

View File

@ -107,6 +107,7 @@ struct E1000State_st {
e1000x_txd_props props; e1000x_txd_props props;
e1000x_txd_props tso_props; e1000x_txd_props tso_props;
uint16_t tso_frames; uint16_t tso_frames;
bool busy;
} tx; } tx;
struct { struct {
@ -763,6 +764,11 @@ start_xmit(E1000State *s)
return; return;
} }
if (s->tx.busy) {
return;
}
s->tx.busy = true;
while (s->mac_reg[TDH] != s->mac_reg[TDT]) { while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
base = tx_desc_base(s) + base = tx_desc_base(s) +
sizeof(struct e1000_tx_desc) * s->mac_reg[TDH]; sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
@ -789,6 +795,7 @@ start_xmit(E1000State *s)
break; break;
} }
} }
s->tx.busy = false;
set_ics(s, 0, cause); set_ics(s, 0, cause);
} }

View File

@ -1746,10 +1746,13 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
VirtIONet *n = qemu_get_nic_opaque(nc); VirtIONet *n = qemu_get_nic_opaque(nc);
VirtIONetQueue *q = virtio_net_get_subqueue(nc); VirtIONetQueue *q = virtio_net_get_subqueue(nc);
VirtIODevice *vdev = VIRTIO_DEVICE(n); VirtIODevice *vdev = VIRTIO_DEVICE(n);
VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE];
size_t lens[VIRTQUEUE_MAX_SIZE];
struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
struct virtio_net_hdr_mrg_rxbuf mhdr; struct virtio_net_hdr_mrg_rxbuf mhdr;
unsigned mhdr_cnt = 0; unsigned mhdr_cnt = 0;
size_t offset, i, guest_offset; size_t offset, i, guest_offset, j;
ssize_t err;
if (!virtio_net_can_receive(nc)) { if (!virtio_net_can_receive(nc)) {
return -1; return -1;
@ -1780,6 +1783,12 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
total = 0; total = 0;
if (i == VIRTQUEUE_MAX_SIZE) {
virtio_error(vdev, "virtio-net unexpected long buffer chain");
err = size;
goto err;
}
elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement));
if (!elem) { if (!elem) {
if (i) { if (i) {
@ -1791,7 +1800,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
n->guest_hdr_len, n->host_hdr_len, n->guest_hdr_len, n->host_hdr_len,
vdev->guest_features); vdev->guest_features);
} }
return -1; err = -1;
goto err;
} }
if (elem->in_num < 1) { if (elem->in_num < 1) {
@ -1799,7 +1809,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
"virtio-net receive queue contains no in buffers"); "virtio-net receive queue contains no in buffers");
virtqueue_detach_element(q->rx_vq, elem, 0); virtqueue_detach_element(q->rx_vq, elem, 0);
g_free(elem); g_free(elem);
return -1; err = -1;
goto err;
} }
sg = elem->in_sg; sg = elem->in_sg;
@ -1836,12 +1847,13 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
if (!n->mergeable_rx_bufs && offset < size) { if (!n->mergeable_rx_bufs && offset < size) {
virtqueue_unpop(q->rx_vq, elem, total); virtqueue_unpop(q->rx_vq, elem, total);
g_free(elem); g_free(elem);
return size; err = size;
goto err;
} }
/* signal other side */ elems[i] = elem;
virtqueue_fill(q->rx_vq, elem, total, i++); lens[i] = total;
g_free(elem); i++;
} }
if (mhdr_cnt) { if (mhdr_cnt) {
@ -1851,10 +1863,23 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
&mhdr.num_buffers, sizeof mhdr.num_buffers); &mhdr.num_buffers, sizeof mhdr.num_buffers);
} }
for (j = 0; j < i; j++) {
/* signal other side */
virtqueue_fill(q->rx_vq, elems[j], lens[j], j);
g_free(elems[j]);
}
virtqueue_flush(q->rx_vq, i); virtqueue_flush(q->rx_vq, i);
virtio_notify(vdev, q->rx_vq); virtio_notify(vdev, q->rx_vq);
return size; return size;
err:
for (j = 0; j < i; j++) {
g_free(elems[j]);
}
return err;
} }
static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf,

View File

@ -1441,6 +1441,7 @@ static void vmxnet3_activate_device(VMXNET3State *s)
vmxnet3_setup_rx_filtering(s); vmxnet3_setup_rx_filtering(s);
/* Cache fields from shared memory */ /* Cache fields from shared memory */
s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu); s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu);
assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu < VMXNET3_MAX_MTU);
VMW_CFPRN("MTU is %u", s->mtu); VMW_CFPRN("MTU is %u", s->mtu);
s->max_rx_frags = s->max_rx_frags =
@ -1486,6 +1487,9 @@ static void vmxnet3_activate_device(VMXNET3State *s)
/* Read rings memory locations for TX queues */ /* Read rings memory locations for TX queues */
pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.txRingBasePA); pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.txRingBasePA);
size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.txRingSize); size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.txRingSize);
if (size > VMXNET3_TX_RING_MAX_SIZE) {
size = VMXNET3_TX_RING_MAX_SIZE;
}
vmxnet3_ring_init(d, &s->txq_descr[i].tx_ring, pa, size, vmxnet3_ring_init(d, &s->txq_descr[i].tx_ring, pa, size,
sizeof(struct Vmxnet3_TxDesc), false); sizeof(struct Vmxnet3_TxDesc), false);
@ -1496,6 +1500,9 @@ static void vmxnet3_activate_device(VMXNET3State *s)
/* TXC ring */ /* TXC ring */
pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.compRingBasePA); pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.compRingBasePA);
size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.compRingSize); size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.compRingSize);
if (size > VMXNET3_TC_RING_MAX_SIZE) {
size = VMXNET3_TC_RING_MAX_SIZE;
}
vmxnet3_ring_init(d, &s->txq_descr[i].comp_ring, pa, size, vmxnet3_ring_init(d, &s->txq_descr[i].comp_ring, pa, size,
sizeof(struct Vmxnet3_TxCompDesc), true); sizeof(struct Vmxnet3_TxCompDesc), true);
VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring); VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring);
@ -1537,6 +1544,9 @@ static void vmxnet3_activate_device(VMXNET3State *s)
/* RX rings */ /* RX rings */
pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.rxRingBasePA[j]); pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.rxRingBasePA[j]);
size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.rxRingSize[j]); size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.rxRingSize[j]);
if (size > VMXNET3_RX_RING_MAX_SIZE) {
size = VMXNET3_RX_RING_MAX_SIZE;
}
vmxnet3_ring_init(d, &s->rxq_descr[i].rx_ring[j], pa, size, vmxnet3_ring_init(d, &s->rxq_descr[i].rx_ring[j], pa, size,
sizeof(struct Vmxnet3_RxDesc), false); sizeof(struct Vmxnet3_RxDesc), false);
VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d", VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d",
@ -1546,6 +1556,9 @@ static void vmxnet3_activate_device(VMXNET3State *s)
/* RXC ring */ /* RXC ring */
pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.compRingBasePA); pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.compRingBasePA);
size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.compRingSize); size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.compRingSize);
if (size > VMXNET3_RC_RING_MAX_SIZE) {
size = VMXNET3_RC_RING_MAX_SIZE;
}
vmxnet3_ring_init(d, &s->rxq_descr[i].comp_ring, pa, size, vmxnet3_ring_init(d, &s->rxq_descr[i].comp_ring, pa, size,
sizeof(struct Vmxnet3_RxCompDesc), true); sizeof(struct Vmxnet3_RxCompDesc), true);
VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size); VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size);

View File

@ -4164,6 +4164,11 @@ static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
int i = 0; int i = 0;
uint32_t nsid; uint32_t nsid;
if (off >= sizeof(nslist)) {
trace_pci_nvme_err_invalid_log_page_offset(off, sizeof(nslist));
return NVME_INVALID_FIELD | NVME_DNR;
}
memset(nslist, 0x0, sizeof(nslist)); memset(nslist, 0x0, sizeof(nslist));
trans_len = MIN(sizeof(nslist) - off, buf_len); trans_len = MIN(sizeof(nslist) - off, buf_len);

View File

@ -448,11 +448,11 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
PCIBridgeQemuCap cap = { PCIBridgeQemuCap cap = {
.len = cap_len, .len = cap_len,
.type = REDHAT_PCI_CAP_RESOURCE_RESERVE, .type = REDHAT_PCI_CAP_RESOURCE_RESERVE,
.bus_res = res_reserve.bus, .bus_res = cpu_to_le32(res_reserve.bus),
.io = res_reserve.io, .io = cpu_to_le64(res_reserve.io),
.mem = res_reserve.mem_non_pref, .mem = cpu_to_le32(res_reserve.mem_non_pref),
.mem_pref_32 = res_reserve.mem_pref_32, .mem_pref_32 = cpu_to_le32(res_reserve.mem_pref_32),
.mem_pref_64 = res_reserve.mem_pref_64 .mem_pref_64 = cpu_to_le64(res_reserve.mem_pref_64)
}; };
int offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, int offset = pci_add_capability(dev, PCI_CAP_ID_VNDR,

View File

@ -148,7 +148,7 @@ static Property pcie_slot_props[] = {
DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true), DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true),
DEFINE_PROP_BOOL("native-hotplug", PCIESlot, native_hotplug, true), DEFINE_PROP_BOOL("x-native-hotplug", PCIESlot, native_hotplug, true),
DEFINE_PROP_END_OF_LIST() DEFINE_PROP_END_OF_LIST()
}; };

View File

@ -1087,6 +1087,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
uint8_t *p = *p_outbuf + 2; uint8_t *p = *p_outbuf + 2;
int length; int length;
assert(page < ARRAY_SIZE(mode_sense_valid));
if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) { if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) {
return -1; return -1;
} }
@ -1428,6 +1429,11 @@ static int scsi_disk_check_mode_select(SCSIDiskState *s, int page,
return -1; return -1;
} }
/* MODE_PAGE_ALLS is only valid for MODE SENSE commands */
if (page == MODE_PAGE_ALLS) {
return -1;
}
p = mode_current; p = mode_current;
memset(mode_current, 0, inlen + 2); memset(mode_current, 0, inlen + 2);
len = mode_sense_page(s, page, &p, 0); len = mode_sense_page(s, page, &p, 0);

View File

@ -180,7 +180,7 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
page = r->req.cmd.buf[2]; page = r->req.cmd.buf[2];
if (page == 0xb0) { if (page == 0xb0) {
uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk); uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk);
uint32_t max_iov = blk_get_max_iov(s->conf.blk); uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk);
assert(max_transfer); assert(max_transfer);
max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size) max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size)

View File

@ -38,7 +38,6 @@ static inline int64_t systick_scale(SysTickState *s)
return 1000; return 1000;
} }
} }
static void systick_timer_tick(void *opaque) static void systick_timer_tick(void *opaque)
{ {
SysTickState *s = (SysTickState *)opaque; SysTickState *s = (SysTickState *)opaque;
@ -248,3 +247,28 @@ static void armv7m_systick_register_types(void)
} }
type_init(armv7m_systick_register_types) type_init(armv7m_systick_register_types)
/* Begin LibAFL instrumentation */
extern void libafl_send_irq(int irqn);
volatile unsigned int libafl_int_offset = 0;
static ptimer_state* mytimer;
/* This can be moved to a helper function later */
static void libafl_timed_int_hook(void*);
static void libafl_timed_int_hook(void* arg)
{
libafl_send_irq(0);
}
void libafl_start_int_timer( void );
void libafl_start_int_timer( void ) {
if (libafl_int_offset==0) {return;}
if (!mytimer) {
mytimer = ptimer_init(&libafl_timed_int_hook, NULL, 0);
}
ptimer_transaction_begin(mytimer);
ptimer_stop(mytimer);
ptimer_set_period(mytimer, libafl_int_offset);
ptimer_set_count(mytimer, 8);
ptimer_run(mytimer, 1);
ptimer_transaction_commit(mytimer);
}
/* End LibAFL instrumentation */

View File

@ -840,6 +840,9 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
} }
break; break;
case UAS_PIPE_ID_STATUS: case UAS_PIPE_ID_STATUS:
if (p->stream > UAS_MAX_STREAMS) {
goto err_stream;
}
if (p->stream) { if (p->stream) {
QTAILQ_FOREACH(st, &uas->results, next) { QTAILQ_FOREACH(st, &uas->results, next) {
if (st->stream == p->stream) { if (st->stream == p->stream) {
@ -867,6 +870,9 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
break; break;
case UAS_PIPE_ID_DATA_IN: case UAS_PIPE_ID_DATA_IN:
case UAS_PIPE_ID_DATA_OUT: case UAS_PIPE_ID_DATA_OUT:
if (p->stream > UAS_MAX_STREAMS) {
goto err_stream;
}
if (p->stream) { if (p->stream) {
req = usb_uas_find_request(uas, p->stream); req = usb_uas_find_request(uas, p->stream);
} else { } else {
@ -902,6 +908,11 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p)
p->status = USB_RET_STALL; p->status = USB_RET_STALL;
break; break;
} }
err_stream:
error_report("%s: invalid stream %d", __func__, p->stream);
p->status = USB_RET_STALL;
return;
} }
static void usb_uas_unrealize(USBDevice *dev) static void usb_uas_unrealize(USBDevice *dev)

View File

@ -551,6 +551,7 @@ static int vfio_host_win_del(VFIOContainer *container, hwaddr min_iova,
QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) {
if (hostwin->min_iova == min_iova && hostwin->max_iova == max_iova) { if (hostwin->min_iova == min_iova && hostwin->max_iova == max_iova) {
QLIST_REMOVE(hostwin, hostwin_next); QLIST_REMOVE(hostwin, hostwin_next);
g_free(hostwin);
return 0; return 0;
} }
} }
@ -2230,6 +2231,7 @@ static void vfio_disconnect_container(VFIOGroup *group)
if (QLIST_EMPTY(&container->group_list)) { if (QLIST_EMPTY(&container->group_list)) {
VFIOAddressSpace *space = container->space; VFIOAddressSpace *space = container->space;
VFIOGuestIOMMU *giommu, *tmp; VFIOGuestIOMMU *giommu, *tmp;
VFIOHostDMAWindow *hostwin, *next;
QLIST_REMOVE(container, next); QLIST_REMOVE(container, next);
@ -2240,6 +2242,12 @@ static void vfio_disconnect_container(VFIOGroup *group)
g_free(giommu); g_free(giommu);
} }
QLIST_FOREACH_SAFE(hostwin, &container->hostwin_list, hostwin_next,
next) {
QLIST_REMOVE(hostwin, hostwin_next);
g_free(hostwin);
}
trace_vfio_disconnect_container(container->fd); trace_vfio_disconnect_container(container->fd);
close(container->fd); close(container->fd);
g_free(container); g_free(container);

View File

@ -1469,6 +1469,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]", name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]",
user, queue_idx); user, queue_idx);
if (!n->mr.ram) /* Don't init again after suspend. */
memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name, memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name,
page_size, addr); page_size, addr);
g_free(name); g_free(name);

View File

@ -114,10 +114,21 @@ static uint64_t vhost_vsock_get_features(VirtIODevice *vdev,
Error **errp) Error **errp)
{ {
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
VHostVSock *vsock = VHOST_VSOCK(vdev);
if (vsock->seqpacket != ON_OFF_AUTO_OFF) {
virtio_add_feature(&requested_features, VIRTIO_VSOCK_F_SEQPACKET); virtio_add_feature(&requested_features, VIRTIO_VSOCK_F_SEQPACKET);
return vhost_get_features(&vvc->vhost_dev, feature_bits, }
requested_features = vhost_get_features(&vvc->vhost_dev, feature_bits,
requested_features); requested_features);
if (vsock->seqpacket == ON_OFF_AUTO_ON &&
!virtio_has_feature(requested_features, VIRTIO_VSOCK_F_SEQPACKET)) {
error_setg(errp, "vhost-vsock backend doesn't support seqpacket");
}
return requested_features;
} }
static const VMStateDescription vmstate_virtio_vhost_vsock = { static const VMStateDescription vmstate_virtio_vhost_vsock = {
@ -218,6 +229,8 @@ static void vhost_vsock_device_unrealize(DeviceState *dev)
static Property vhost_vsock_properties[] = { static Property vhost_vsock_properties[] = {
DEFINE_PROP_UINT64("guest-cid", VHostVSock, conf.guest_cid, 0), DEFINE_PROP_UINT64("guest-cid", VHostVSock, conf.guest_cid, 0),
DEFINE_PROP_STRING("vhostfd", VHostVSock, conf.vhostfd), DEFINE_PROP_STRING("vhostfd", VHostVSock, conf.vhostfd),
DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSock, seqpacket,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -30,6 +30,7 @@
#include "trace.h" #include "trace.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "migration/misc.h" #include "migration/misc.h"
#include "migration/migration.h"
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h" #include "hw/virtio/virtio-access.h"
@ -662,6 +663,18 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data)
return 0; return 0;
} }
/*
* Pages hinted via qemu_guest_free_page_hint() are cleared from the dirty
* bitmap and will not get migrated, especially also not when the postcopy
* destination starts using them and requests migration from the source; the
* faulting thread will stall until postcopy migration finishes and
* all threads are woken up. Let's not start free page hinting if postcopy
* is possible.
*/
if (migrate_postcopy_ram()) {
return 0;
}
switch (pnd->reason) { switch (pnd->reason) {
case PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC: case PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC:
virtio_balloon_free_page_stop(dev); virtio_balloon_free_page_stop(dev);

View File

@ -88,13 +88,8 @@ static void virtio_mem_pci_size_change_notify(Notifier *notifier, void *data)
size_change_notifier); size_change_notifier);
DeviceState *dev = DEVICE(pci_mem); DeviceState *dev = DEVICE(pci_mem);
const uint64_t * const size_p = data; const uint64_t * const size_p = data;
const char *id = NULL;
if (dev->id) { qapi_event_send_memory_device_size_change(!!dev->id, dev->id, *size_p);
id = g_strdup(dev->id);
}
qapi_event_send_memory_device_size_change(!!id, id, *size_p);
} }
static void virtio_mem_pci_class_init(ObjectClass *klass, void *data) static void virtio_mem_pci_class_init(ObjectClass *klass, void *data)

View File

@ -249,13 +249,10 @@ static void vring_packed_event_read(VirtIODevice *vdev,
hwaddr off_off = offsetof(VRingPackedDescEvent, off_wrap); hwaddr off_off = offsetof(VRingPackedDescEvent, off_wrap);
hwaddr off_flags = offsetof(VRingPackedDescEvent, flags); hwaddr off_flags = offsetof(VRingPackedDescEvent, flags);
address_space_read_cached(cache, off_flags, &e->flags, e->flags = virtio_lduw_phys_cached(vdev, cache, off_flags);
sizeof(e->flags));
/* Make sure flags is seen before off_wrap */ /* Make sure flags is seen before off_wrap */
smp_rmb(); smp_rmb();
address_space_read_cached(cache, off_off, &e->off_wrap, e->off_wrap = virtio_lduw_phys_cached(vdev, cache, off_off);
sizeof(e->off_wrap));
virtio_tswap16s(vdev, &e->off_wrap);
virtio_tswap16s(vdev, &e->flags); virtio_tswap16s(vdev, &e->flags);
} }
@ -265,8 +262,7 @@ static void vring_packed_off_wrap_write(VirtIODevice *vdev,
{ {
hwaddr off = offsetof(VRingPackedDescEvent, off_wrap); hwaddr off = offsetof(VRingPackedDescEvent, off_wrap);
virtio_tswap16s(vdev, &off_wrap); virtio_stw_phys_cached(vdev, cache, off, off_wrap);
address_space_write_cached(cache, off, &off_wrap, sizeof(off_wrap));
address_space_cache_invalidate(cache, off, sizeof(off_wrap)); address_space_cache_invalidate(cache, off, sizeof(off_wrap));
} }
@ -275,8 +271,7 @@ static void vring_packed_flags_write(VirtIODevice *vdev,
{ {
hwaddr off = offsetof(VRingPackedDescEvent, flags); hwaddr off = offsetof(VRingPackedDescEvent, flags);
virtio_tswap16s(vdev, &flags); virtio_stw_phys_cached(vdev, cache, off, flags);
address_space_write_cached(cache, off, &flags, sizeof(flags));
address_space_cache_invalidate(cache, off, sizeof(flags)); address_space_cache_invalidate(cache, off, sizeof(flags));
} }
@ -509,11 +504,9 @@ static void vring_packed_desc_read_flags(VirtIODevice *vdev,
MemoryRegionCache *cache, MemoryRegionCache *cache,
int i) int i)
{ {
address_space_read_cached(cache, hwaddr off = i * sizeof(VRingPackedDesc) + offsetof(VRingPackedDesc, flags);
i * sizeof(VRingPackedDesc) +
offsetof(VRingPackedDesc, flags), *flags = virtio_lduw_phys_cached(vdev, cache, off);
flags, sizeof(*flags));
virtio_tswap16s(vdev, flags);
} }
static void vring_packed_desc_read(VirtIODevice *vdev, static void vring_packed_desc_read(VirtIODevice *vdev,
@ -566,8 +559,7 @@ static void vring_packed_desc_write_flags(VirtIODevice *vdev,
{ {
hwaddr off = i * sizeof(VRingPackedDesc) + offsetof(VRingPackedDesc, flags); hwaddr off = i * sizeof(VRingPackedDesc) + offsetof(VRingPackedDesc, flags);
virtio_tswap16s(vdev, &desc->flags); virtio_stw_phys_cached(vdev, cache, off, desc->flags);
address_space_write_cached(cache, off, &desc->flags, sizeof(desc->flags));
address_space_cache_invalidate(cache, off, sizeof(desc->flags)); address_space_cache_invalidate(cache, off, sizeof(desc->flags));
} }

View File

@ -702,6 +702,13 @@ typedef struct BlockLimits {
*/ */
uint64_t max_hw_transfer; uint64_t max_hw_transfer;
/* Maximal number of scatter/gather elements allowed by the hardware.
* Applies whenever transfers to the device bypass the kernel I/O
* scheduler, for example with SG_IO. If larger than max_iov
* or if zero, blk_get_max_hw_iov will fall back to max_iov.
*/
int max_hw_iov;
/* memory alignment, in bytes so that no bounce buffer is needed */ /* memory alignment, in bytes so that no bounce buffer is needed */
size_t min_mem_alignment; size_t min_mem_alignment;

View File

@ -29,7 +29,7 @@
#include "hw/acpi/acpi_dev_interface.h" #include "hw/acpi/acpi_dev_interface.h"
#include "hw/acpi/tco.h" #include "hw/acpi/tco.h"
#define ACPI_PCIHP_ADDR_ICH9 0x0cc4 #define ACPI_PCIHP_ADDR_ICH9 0x0cc0
typedef struct ICH9LPCPMRegs { typedef struct ICH9LPCPMRegs {
/* /*

View File

@ -30,6 +30,9 @@ struct VHostVSock {
VHostVSockCommon parent; VHostVSockCommon parent;
VHostVSockConf conf; VHostVSockConf conf;
/* features */
OnOffAuto seqpacket;
/*< public >*/ /*< public >*/
}; };

View File

@ -27,6 +27,7 @@
#include "qemu/thread.h" #include "qemu/thread.h"
#include "qemu/queue.h" #include "qemu/queue.h"
#include "qemu/atomic.h" #include "qemu/atomic.h"
#include "qemu/notify.h"
#include "qemu/sys_membarrier.h" #include "qemu/sys_membarrier.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -66,6 +67,13 @@ struct rcu_reader_data {
/* Data used for registry, protected by rcu_registry_lock */ /* Data used for registry, protected by rcu_registry_lock */
QLIST_ENTRY(rcu_reader_data) node; QLIST_ENTRY(rcu_reader_data) node;
/*
* NotifierList used to force an RCU grace period. Accessed under
* rcu_registry_lock. Note that the notifier is called _outside_
* the thread!
*/
NotifierList force_rcu;
}; };
extern __thread struct rcu_reader_data rcu_reader; extern __thread struct rcu_reader_data rcu_reader;
@ -180,6 +188,13 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(RCUReadAuto, rcu_read_auto_unlock)
#define RCU_READ_LOCK_GUARD() \ #define RCU_READ_LOCK_GUARD() \
g_autoptr(RCUReadAuto) _rcu_read_auto __attribute__((unused)) = rcu_read_auto_lock() g_autoptr(RCUReadAuto) _rcu_read_auto __attribute__((unused)) = rcu_read_auto_lock()
/*
* Force-RCU notifiers tell readers that they should exit their
* read-side critical section.
*/
void rcu_add_force_rcu_notifier(Notifier *n);
void rcu_remove_force_rcu_notifier(Notifier *n);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -210,6 +210,7 @@ uint32_t blk_get_request_alignment(BlockBackend *blk);
uint32_t blk_get_max_transfer(BlockBackend *blk); uint32_t blk_get_max_transfer(BlockBackend *blk);
uint64_t blk_get_max_hw_transfer(BlockBackend *blk); uint64_t blk_get_max_hw_transfer(BlockBackend *blk);
int blk_get_max_iov(BlockBackend *blk); int blk_get_max_iov(BlockBackend *blk);
int blk_get_max_hw_iov(BlockBackend *blk);
void blk_set_guest_block_size(BlockBackend *blk, int align); void blk_set_guest_block_size(BlockBackend *blk, int align);
void *blk_try_blockalign(BlockBackend *blk, size_t size); void *blk_try_blockalign(BlockBackend *blk, size_t size);
void *blk_blockalign(BlockBackend *blk, size_t size); void *blk_blockalign(BlockBackend *blk, size_t size);

View File

@ -88,6 +88,16 @@ void cpu_loop(CPUARMState *env)
process_queued_cpu_work(cs); process_queued_cpu_work(cs);
switch (trapnr) { switch (trapnr) {
//// --- Begin LibAFL code ---
#define EXCP_LIBAFL_BP 0xf4775747
case EXCP_LIBAFL_BP:
return;
//// --- End LibAFL code ---
case EXCP_SWI: case EXCP_SWI:
ret = do_syscall(env, ret = do_syscall(env,
env->xregs[8], env->xregs[8],

View File

@ -298,6 +298,16 @@ void cpu_loop(CPUARMState *env)
process_queued_cpu_work(cs); process_queued_cpu_work(cs);
switch(trapnr) { switch(trapnr) {
//// --- Begin LibAFL code ---
#define EXCP_LIBAFL_BP 0xf4775747
case EXCP_LIBAFL_BP:
return;
//// --- End LibAFL code ---
case EXCP_UDEF: case EXCP_UDEF:
case EXCP_NOCP: case EXCP_NOCP:
case EXCP_INVSTATE: case EXCP_INVSTATE:

View File

@ -209,6 +209,16 @@ void cpu_loop(CPUX86State *env)
process_queued_cpu_work(cs); process_queued_cpu_work(cs);
switch(trapnr) { switch(trapnr) {
//// --- Begin LibAFL code ---
#define EXCP_LIBAFL_BP 0xf4775747
case EXCP_LIBAFL_BP:
return;
//// --- End LibAFL code ---
case 0x80: case 0x80:
/* linux syscall from int $0x80 */ /* linux syscall from int $0x80 */
ret = do_syscall(env, ret = do_syscall(env,

View File

@ -582,6 +582,16 @@ static int parse_args(int argc, char **argv)
r++; r++;
} }
if (!strncmp(r, "libafl", 6)) {
if (optind >= argc) {
(void) fprintf(stderr,
"qemu: missing argument for option '%s'\n", r);
exit(EXIT_FAILURE);
}
optind++;
continue;
}
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (!strcmp(r, arginfo->argv)) { if (!strcmp(r, arginfo->argv)) {
if (arginfo->has_arg) { if (arginfo->has_arg) {
@ -611,16 +621,51 @@ static int parse_args(int argc, char **argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
exec_path = argv[optind]; exec_path = strdup(argv[optind]);
return optind; return optind;
} }
//// --- Begin LibAFL code ---
uint64_t libafl_load_addr(void);
int libafl_qemu_main(void);
int libafl_qemu_run(void);
extern __thread CPUArchState *libafl_qemu_env;
struct image_info libafl_image_info;
struct linux_binprm bprm;
uint64_t libafl_load_addr(void) {
return libafl_image_info.load_addr;
}
__attribute__((weak)) int libafl_qemu_main(void)
{
libafl_qemu_run();
return 0;
}
int libafl_qemu_run(void)
{
cpu_loop(libafl_qemu_env);
return 1;
}
//// --- End LibAFL code ---
#ifdef AS_LIB
int qemu_user_init(int argc, char **argv, char **envp);
int qemu_user_init(int argc, char **argv, char **envp)
#else
int main(int argc, char **argv, char **envp) int main(int argc, char **argv, char **envp)
#endif
{ {
struct target_pt_regs regs1, *regs = &regs1; struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1; //struct image_info info1, *info = &info1;
struct linux_binprm bprm; struct image_info *info = &libafl_image_info;
// struct linux_binprm bprm;
TaskState *ts; TaskState *ts;
CPUArchState *env; CPUArchState *env;
CPUState *cpu; CPUState *cpu;
@ -882,7 +927,18 @@ int main(int argc, char **argv, char **envp)
} }
gdb_handlesig(cpu, 0); gdb_handlesig(cpu, 0);
} }
cpu_loop(env); // cpu_loop(env);
//// --- Begin LibAFL code ---
libafl_qemu_env = env;
#ifndef AS_LIB
return libafl_qemu_main();
#endif
//// --- End LibAFL code ---
/* never exits */ /* never exits */
return 0; return 0;
} }

View File

@ -756,6 +756,23 @@ void target_set_brk(abi_ulong new_brk)
brk_page = HOST_PAGE_ALIGN(target_brk); brk_page = HOST_PAGE_ALIGN(target_brk);
} }
//// --- Begin LibAFL code ---
uint64_t libafl_get_brk(void);
uint64_t libafl_set_brk(uint64_t new_brk);
uint64_t libafl_get_brk(void) {
return (uint64_t)target_brk;
}
uint64_t libafl_set_brk(uint64_t new_brk) {
uint64_t old_brk = (uint64_t)target_brk;
target_brk = (abi_ulong)new_brk;
return old_brk;
}
//// --- End LibAFL code ---
//#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0) //#define DEBUGF_BRK(message, args...) do { fprintf(stderr, (message), ## args); } while (0)
#define DEBUGF_BRK(message, args...) #define DEBUGF_BRK(message, args...)
@ -13115,6 +13132,67 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return ret; return ret;
} }
//// --- Begin LibAFL code ---
struct libafl_mapinfo {
uint64_t start, end;
uint64_t offset;
const char* path;
int flags, is_priv;
};
GSList * libafl_maps_next(GSList *map_info, struct libafl_mapinfo* ret);
GSList * libafl_maps_next(GSList *map_info, struct libafl_mapinfo* ret) {
if (!map_info || !ret)
return NULL;
GSList *s = g_slist_next(map_info);
if (!s)
return NULL;
MapInfo *e = (MapInfo *) s->data;
if (h2g_valid(e->start)) {
unsigned long min = e->start;
unsigned long max = e->end;
int flags = page_get_flags(h2g(min));
max = h2g_valid(max - 1) ?
max : (uintptr_t) g2h_untagged(GUEST_ADDR_MAX) + 1;
if (page_check_range(h2g(min), max - min, flags) == -1) {
return libafl_maps_next(s, ret);
}
int libafl_flags = 0;
if (flags & PAGE_READ) libafl_flags |= PROT_READ;
if (flags & PAGE_WRITE_ORG) libafl_flags |= PROT_WRITE;
if (flags & PAGE_EXEC) libafl_flags |= PROT_EXEC;
ret->start = (uint64_t)min;
ret->end = (uint64_t)max;
ret->offset = (uint64_t)e->offset;
ret->path = e->path;
ret->flags = libafl_flags;
ret->is_priv = e->is_priv;
return s;
} else {
return libafl_maps_next(s, ret);
}
}
struct syshook_ret {
uint64_t retval;
bool skip_syscall;
};
struct syshook_ret (*libafl_pre_syscall_hook)(int, uint64_t, uint64_t, uint64_t,
uint64_t, uint64_t, uint64_t,
uint64_t, uint64_t);
uint64_t (*libafl_post_syscall_hook)(uint64_t, int, uint64_t, uint64_t,
uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t, uint64_t);
//// --- End LibAFL code ---
abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg5, abi_long arg6, abi_long arg7,
@ -13144,9 +13222,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
print_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6); print_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6);
} }
//// --- Begin LibAFL code ---
if (libafl_pre_syscall_hook) {
struct syshook_ret hook_ret = libafl_pre_syscall_hook(num,
(uint64_t)arg1,
(uint64_t)arg2,
(uint64_t)arg3,
(uint64_t)arg4,
(uint64_t)arg5,
(uint64_t)arg6,
(uint64_t)arg7,
(uint64_t)arg8);
if (hook_ret.skip_syscall) {
ret = (abi_ulong)hook_ret.retval;
goto after_syscall;
}
}
//// --- End LibAFL code ---
ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4, ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
arg5, arg6, arg7, arg8); arg5, arg6, arg7, arg8);
//// --- Begin LibAFL code ---
if (libafl_post_syscall_hook) {
ret = (abi_ulong)libafl_post_syscall_hook((uint64_t)ret, num,
(uint64_t)arg1,
(uint64_t)arg2,
(uint64_t)arg3,
(uint64_t)arg4,
(uint64_t)arg5,
(uint64_t)arg6,
(uint64_t)arg7,
(uint64_t)arg8);
}
after_syscall:
//// --- End LibAFL code ---
if (unlikely(qemu_loglevel_mask(LOG_STRACE))) { if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
print_syscall_ret(cpu_env, num, ret, arg1, arg2, print_syscall_ret(cpu_env, num, ret, arg1, arg2,
arg3, arg4, arg5, arg6); arg3, arg4, arg5, arg6);

View File

@ -1797,7 +1797,8 @@ if capstone_opt == 'internal'
build_by_default: false, build_by_default: false,
sources: capstone_files, sources: capstone_files,
c_args: capstone_cargs, c_args: capstone_cargs,
include_directories: 'capstone/include') include_directories: 'capstone/include',
pic: 'AS_SHARED_LIB' in config_host)
capstone = declare_dependency(link_with: libcapstone, capstone = declare_dependency(link_with: libcapstone,
include_directories: 'capstone/include/capstone') include_directories: 'capstone/include/capstone')
endif endif
@ -1877,7 +1878,8 @@ if have_system
build_by_default: false, build_by_default: false,
sources: slirp_files, sources: slirp_files,
c_args: slirp_cargs, c_args: slirp_cargs,
include_directories: slirp_inc) include_directories: slirp_inc,
pic: 'AS_SHARED_LIB' in config_host)
slirp = declare_dependency(link_with: libslirp, slirp = declare_dependency(link_with: libslirp,
dependencies: slirp_deps, dependencies: slirp_deps,
include_directories: slirp_inc) include_directories: slirp_inc)
@ -1934,7 +1936,8 @@ if have_system
libfdt = static_library('fdt', libfdt = static_library('fdt',
build_by_default: false, build_by_default: false,
sources: fdt_files, sources: fdt_files,
include_directories: fdt_inc) include_directories: fdt_inc,
pic: 'AS_SHARED_LIB' in config_host)
fdt = declare_dependency(link_with: libfdt, fdt = declare_dependency(link_with: libfdt,
include_directories: fdt_inc) include_directories: fdt_inc)
endif endif
@ -2202,7 +2205,8 @@ util_ss.add_all(trace_ss)
util_ss = util_ss.apply(config_all, strict: false) util_ss = util_ss.apply(config_all, strict: false)
libqemuutil = static_library('qemuutil', libqemuutil = static_library('qemuutil',
sources: util_ss.sources() + stub_ss.sources() + genh, sources: util_ss.sources() + stub_ss.sources() + genh,
dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman]) dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman],
pic: 'AS_SHARED_LIB' in config_host)
qemuutil = declare_dependency(link_with: libqemuutil, qemuutil = declare_dependency(link_with: libqemuutil,
sources: genh + version_res) sources: genh + version_res)
@ -2267,7 +2271,8 @@ if get_option('b_lto')
pagevary_flags += '-fno-sanitize=cfi-icall' pagevary_flags += '-fno-sanitize=cfi-icall'
endif endif
pagevary = static_library('page-vary-common', sources: pagevary, pagevary = static_library('page-vary-common', sources: pagevary,
c_args: pagevary_flags) c_args: pagevary_flags,
pic: 'AS_SHARED_LIB' in config_host)
pagevary = declare_dependency(link_with: pagevary) pagevary = declare_dependency(link_with: pagevary)
endif endif
common_ss.add(pagevary) common_ss.add(pagevary)
@ -2393,7 +2398,8 @@ if enable_modules
input: modinfo_files, input: modinfo_files,
command: [modinfo_generate, '@INPUT@'], command: [modinfo_generate, '@INPUT@'],
capture: true) capture: true)
modinfo_lib = static_library('modinfo', modinfo_src) modinfo_lib = static_library('modinfo', modinfo_src,
pic: 'AS_SHARED_LIB' in config_host)
modinfo_dep = declare_dependency(link_whole: modinfo_lib) modinfo_dep = declare_dependency(link_whole: modinfo_lib)
softmmu_ss.add(modinfo_dep) softmmu_ss.add(modinfo_dep)
endif endif
@ -2412,7 +2418,8 @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms',
qom_ss = qom_ss.apply(config_host, strict: false) qom_ss = qom_ss.apply(config_host, strict: false)
libqom = static_library('qom', qom_ss.sources() + genh, libqom = static_library('qom', qom_ss.sources() + genh,
dependencies: [qom_ss.dependencies()], dependencies: [qom_ss.dependencies()],
name_suffix: 'fa') name_suffix: 'fa',
pic: 'AS_SHARED_LIB' in config_host)
qom = declare_dependency(link_whole: libqom) qom = declare_dependency(link_whole: libqom)
@ -2420,7 +2427,8 @@ authz_ss = authz_ss.apply(config_host, strict: false)
libauthz = static_library('authz', authz_ss.sources() + genh, libauthz = static_library('authz', authz_ss.sources() + genh,
dependencies: [authz_ss.dependencies()], dependencies: [authz_ss.dependencies()],
name_suffix: 'fa', name_suffix: 'fa',
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
authz = declare_dependency(link_whole: libauthz, authz = declare_dependency(link_whole: libauthz,
dependencies: qom) dependencies: qom)
@ -2429,7 +2437,8 @@ crypto_ss = crypto_ss.apply(config_host, strict: false)
libcrypto = static_library('crypto', crypto_ss.sources() + genh, libcrypto = static_library('crypto', crypto_ss.sources() + genh,
dependencies: [crypto_ss.dependencies()], dependencies: [crypto_ss.dependencies()],
name_suffix: 'fa', name_suffix: 'fa',
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
crypto = declare_dependency(link_whole: libcrypto, crypto = declare_dependency(link_whole: libcrypto,
dependencies: [authz, qom]) dependencies: [authz, qom])
@ -2439,13 +2448,15 @@ libio = static_library('io', io_ss.sources() + genh,
dependencies: [io_ss.dependencies()], dependencies: [io_ss.dependencies()],
link_with: libqemuutil, link_with: libqemuutil,
name_suffix: 'fa', name_suffix: 'fa',
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
io = declare_dependency(link_whole: libio, dependencies: [crypto, qom]) io = declare_dependency(link_whole: libio, dependencies: [crypto, qom])
libmigration = static_library('migration', sources: migration_files + genh, libmigration = static_library('migration', sources: migration_files + genh,
name_suffix: 'fa', name_suffix: 'fa',
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
migration = declare_dependency(link_with: libmigration, migration = declare_dependency(link_with: libmigration,
dependencies: [zlib, qom, io]) dependencies: [zlib, qom, io])
softmmu_ss.add(migration) softmmu_ss.add(migration)
@ -2455,7 +2466,8 @@ libblock = static_library('block', block_ss.sources() + genh,
dependencies: block_ss.dependencies(), dependencies: block_ss.dependencies(),
link_depends: block_syms, link_depends: block_syms,
name_suffix: 'fa', name_suffix: 'fa',
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
block = declare_dependency(link_whole: [libblock], block = declare_dependency(link_whole: [libblock],
link_args: '@block.syms', link_args: '@block.syms',
@ -2465,7 +2477,8 @@ blockdev_ss = blockdev_ss.apply(config_host, strict: false)
libblockdev = static_library('blockdev', blockdev_ss.sources() + genh, libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
dependencies: blockdev_ss.dependencies(), dependencies: blockdev_ss.dependencies(),
name_suffix: 'fa', name_suffix: 'fa',
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
blockdev = declare_dependency(link_whole: [libblockdev], blockdev = declare_dependency(link_whole: [libblockdev],
dependencies: [block]) dependencies: [block])
@ -2474,20 +2487,23 @@ qmp_ss = qmp_ss.apply(config_host, strict: false)
libqmp = static_library('qmp', qmp_ss.sources() + genh, libqmp = static_library('qmp', qmp_ss.sources() + genh,
dependencies: qmp_ss.dependencies(), dependencies: qmp_ss.dependencies(),
name_suffix: 'fa', name_suffix: 'fa',
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
qmp = declare_dependency(link_whole: [libqmp]) qmp = declare_dependency(link_whole: [libqmp])
libchardev = static_library('chardev', chardev_ss.sources() + genh, libchardev = static_library('chardev', chardev_ss.sources() + genh,
name_suffix: 'fa', name_suffix: 'fa',
dependencies: [gnutls], dependencies: [gnutls],
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
chardev = declare_dependency(link_whole: libchardev) chardev = declare_dependency(link_whole: libchardev)
libhwcore = static_library('hwcore', sources: hwcore_files + genh, libhwcore = static_library('hwcore', sources: hwcore_files + genh,
name_suffix: 'fa', name_suffix: 'fa',
build_by_default: false) build_by_default: false,
pic: 'AS_SHARED_LIB' in config_host)
hwcore = declare_dependency(link_whole: libhwcore) hwcore = declare_dependency(link_whole: libhwcore)
common_ss.add(hwcore) common_ss.add(hwcore)
@ -2515,7 +2531,8 @@ common_all = static_library('common',
sources: common_all.sources() + genh, sources: common_all.sources() + genh,
implicit_include_directories: false, implicit_include_directories: false,
dependencies: common_all.dependencies(), dependencies: common_all.dependencies(),
name_suffix: 'fa') name_suffix: 'fa',
pic: 'AS_SHARED_LIB' in config_host)
feature_to_c = find_program('scripts/feature_to_c.sh') feature_to_c = find_program('scripts/feature_to_c.sh')
@ -2609,7 +2626,8 @@ foreach target : target_dirs
include_directories: target_inc, include_directories: target_inc,
c_args: c_args, c_args: c_args,
build_by_default: false, build_by_default: false,
name_suffix: 'fa') name_suffix: 'fa',
pic: 'AS_SHARED_LIB' in config_host)
if target.endswith('-softmmu') if target.endswith('-softmmu')
execs = [{ execs = [{
@ -2649,6 +2667,7 @@ foreach target : target_dirs
exe_name += '-unsigned' exe_name += '-unsigned'
endif endif
if 'AS_SHARED_LIB' not in config_host and 'AS_STATIC_LIB' not in config_host
emulator = executable(exe_name, exe['sources'], emulator = executable(exe_name, exe['sources'],
install: true, install: true,
c_args: c_args, c_args: c_args,
@ -2658,6 +2677,24 @@ foreach target : target_dirs
link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []), link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []),
link_args: link_args, link_args: link_args,
gui_app: exe['gui']) gui_app: exe['gui'])
else
if 'AS_SHARED_LIB' in config_host
emulator = shared_library(exe_name, exe['sources'],
install: true,
c_args: c_args,
dependencies: arch_deps + deps + exe['dependencies'],
objects: lib.extract_all_objects(recursive: true),
link_language: link_language,
link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []),
link_args: link_args)
endif
if 'AS_STATIC_LIB' in config_host
emulator = static_library(exe_name, exe['sources'],
c_args: c_args,
dependencies: arch_deps + deps + exe['dependencies'],
objects: lib.extract_all_objects(recursive: true))
endif
endif
if targetos == 'darwin' if targetos == 'darwin'
icon = 'pc-bios/qemu.rsrc' icon = 'pc-bios/qemu.rsrc'

View File

@ -1496,7 +1496,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
} }
if (strcmp(target, "passwd") == 0 || if (strcmp(target, "passwd") == 0 ||
strcmp(target, "password") == 0) { strcmp(target, "password") == 0) {
if (arg) { if (!arg) {
MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
monitor_read_password(hmp_mon, hmp_change_read_arg, NULL); monitor_read_password(hmp_mon, hmp_change_read_arg, NULL);
return; return;

70
myconfigure.sh Executable file
View File

@ -0,0 +1,70 @@
#!/bin/sh
cd "$(dirname "$0")"
mkdir -p build
cd build
../configure --target-list=arm-linux-user,arm-softmmu,x86_64-linux-user,x86_64-softmmu \
--audio-drv-list= \
--disable-blobs \
--disable-bochs \
--disable-brlapi \
--disable-bsd-user \
--disable-bzip2 \
--disable-cap-ng \
--disable-cloop \
--disable-curl \
--disable-curses \
--disable-dmg \
--enable-fdt \
--disable-gcrypt \
--disable-glusterfs \
--disable-gnutls \
--disable-gtk \
--disable-guest-agent \
--disable-iconv \
--disable-libiscsi \
--disable-libnfs \
--disable-libssh \
--disable-libusb \
--disable-linux-aio \
--disable-live-block-migration \
--disable-lzo \
--disable-nettle \
--disable-numa \
--disable-opengl \
--disable-parallels \
--disable-plugins \
--disable-qcow1 \
--disable-qed \
--disable-rbd \
--disable-rdma \
--disable-replication \
--disable-sdl \
--disable-seccomp \
--disable-smartcard \
--disable-snappy \
--disable-spice \
--enable-system \
--disable-tools \
--disable-tpm \
--disable-usb-redir \
--disable-vde \
--disable-vdi \
--disable-vhost-crypto \
--disable-vhost-kernel \
--disable-vhost-net \
--disable-vhost-scsi \
--disable-vhost-user \
--disable-vhost-vdpa \
--disable-vhost-vsock \
--disable-virglrenderer \
--disable-virtfs \
--disable-vnc \
--disable-vnc-jpeg \
--disable-vnc-png \
--disable-vnc-sasl \
--disable-vte \
--disable-vvfat \
--disable-xen \
--disable-xen-pci-passthrough \
--disable-xfsctl \
--as-shared-lib

69
myconfigureunshared.sh Executable file
View File

@ -0,0 +1,69 @@
#!/bin/sh
cd "$(dirname "$0")"
mkdir -p build
cd build
../configure --target-list=arm-linux-user,arm-softmmu \
--audio-drv-list= \
--disable-blobs \
--disable-bochs \
--disable-brlapi \
--disable-bsd-user \
--disable-bzip2 \
--disable-cap-ng \
--disable-cloop \
--disable-curl \
--disable-curses \
--disable-dmg \
--enable-fdt \
--disable-gcrypt \
--disable-glusterfs \
--disable-gnutls \
--disable-gtk \
--disable-guest-agent \
--disable-iconv \
--disable-libiscsi \
--disable-libnfs \
--disable-libssh \
--disable-libusb \
--disable-linux-aio \
--disable-live-block-migration \
--disable-lzo \
--disable-nettle \
--disable-numa \
--disable-opengl \
--disable-parallels \
--disable-plugins \
--disable-qcow1 \
--disable-qed \
--disable-rbd \
--disable-rdma \
--disable-replication \
--disable-sdl \
--disable-seccomp \
--disable-smartcard \
--disable-snappy \
--disable-spice \
--enable-system \
--disable-tools \
--disable-tpm \
--disable-usb-redir \
--disable-vde \
--disable-vdi \
--disable-vhost-crypto \
--disable-vhost-kernel \
--disable-vhost-net \
--disable-vhost-scsi \
--disable-vhost-user \
--disable-vhost-vdpa \
--disable-vhost-vsock \
--disable-virglrenderer \
--disable-virtfs \
--disable-vnc \
--disable-vnc-jpeg \
--disable-vnc-png \
--disable-vnc-sasl \
--disable-vte \
--disable-vvfat \
--disable-xen \
--disable-xen-pci-passthrough \
--disable-xfsctl

31
mytest.c Normal file
View File

@ -0,0 +1,31 @@
#include <stdio.h>
#include <stdint.h>
void libafl_qemu_main_loop( void );
void libafl_qemu_sys_init(int argc, char **argv, char **envp);
void libafl_qemu_cleanup( void );
void libafl_qemu_set_breakpoint( unsigned long int );
void libafl_qemu_remove_native_breakpoint( unsigned long int );
void libafl_qemu_set_native_breakpoint( unsigned long int );
void libafl_snapshot_save( const char* );
void libafl_snapshot_load( const char* );
int64_t libafl_get_clock( void );
int main(int argc, char **argv, char **envp)
{
libafl_qemu_sys_init(argc, argv, envp);
libafl_qemu_set_native_breakpoint(0x4c60);//send 217028
libafl_qemu_main_loop();
libafl_qemu_remove_native_breakpoint(0x4c60);
libafl_qemu_set_native_breakpoint(0x00004f5c);
libafl_snapshot_save("Start");
printf("Snap start icount: %lu\n",libafl_get_clock());
libafl_qemu_main_loop();
printf("tr1 icount: %lu\n",libafl_get_clock());
libafl_snapshot_load("Start");
libafl_qemu_main_loop();
printf("tr2 icount: %lu\n",libafl_get_clock());
libafl_qemu_cleanup();
return 0;
}

12
myteststarter.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
if [ ! -f dummy.qcow2 ]; then
qemu-img create -f qcow2 dummy.qcow2 32M
fi
export LD_LIBRARY_PATH=./build
build/qemu-system-arm -machine mps2-an385 -monitor null -semihosting \
--semihosting-config enable=on,target=native \
-kernel $1 \
-serial stdio -nographic \
-snapshot -drive if=none,format=qcow2,file=dummy.qcow2 \
-icount shift=3,align=off,sleep=off \
-S

View File

@ -1413,6 +1413,9 @@ static int nbd_receive_request(NBDClient *client, NBDRequest *request,
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
if (ret == 0) {
return -EIO;
}
/* Request /* Request
[ 0 .. 3] magic (NBD_REQUEST_MAGIC) [ 0 .. 3] magic (NBD_REQUEST_MAGIC)

View File

@ -1,9 +1,11 @@
plugin_ldflags = []
# Modules need more symbols than just those in plugins/qemu-plugins.symbols
if not enable_modules
if 'CONFIG_HAS_LD_DYNAMIC_LIST' in config_host if 'CONFIG_HAS_LD_DYNAMIC_LIST' in config_host
plugin_ldflags = ['-Wl,--dynamic-list=' + (meson.build_root() / 'qemu-plugins-ld.symbols')] plugin_ldflags = ['-Wl,--dynamic-list=' + (meson.build_root() / 'qemu-plugins-ld.symbols')]
elif 'CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST' in config_host elif 'CONFIG_HAS_LD_EXPORTED_SYMBOLS_LIST' in config_host
plugin_ldflags = ['-Wl,-exported_symbols_list,' + (meson.build_root() / 'qemu-plugins-ld64.symbols')] plugin_ldflags = ['-Wl,-exported_symbols_list,' + (meson.build_root() / 'qemu-plugins-ld64.symbols')]
else endif
plugin_ldflags = []
endif endif
specific_ss.add(when: 'CONFIG_PLUGIN', if_true: [files( specific_ss.add(when: 'CONFIG_PLUGIN', if_true: [files(

View File

@ -135,7 +135,9 @@ static void usage(const char *name)
" 'snapshot.id=[ID],snapshot.name=[NAME]', or\n" " 'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
" '[ID_OR_NAME]'\n" " '[ID_OR_NAME]'\n"
" -n, --nocache disable host cache\n" " -n, --nocache disable host cache\n"
" --cache=MODE set cache mode (none, writeback, ...)\n" " --cache=MODE set cache mode used to access the disk image, the\n"
" valid options are: 'none', 'writeback' (default),\n"
" 'writethrough', 'directsync' and 'unsafe'\n"
" --aio=MODE set AIO mode (native, io_uring or threads)\n" " --aio=MODE set AIO mode (native, io_uring or threads)\n"
" --discard=MODE set discard mode (ignore, unmap)\n" " --discard=MODE set discard mode (ignore, unmap)\n"
" --detect-zeroes=MODE set detect-zeroes mode (off, on, unmap)\n" " --detect-zeroes=MODE set detect-zeroes mode (off, on, unmap)\n"
@ -552,7 +554,7 @@ int main(int argc, char **argv)
bool alloc_depth = false; bool alloc_depth = false;
const char *tlscredsid = NULL; const char *tlscredsid = NULL;
bool imageOpts = false; bool imageOpts = false;
bool writethrough = true; bool writethrough = false; /* Client will flush as needed. */
bool fork_process = false; bool fork_process = false;
bool list = false; bool list = false;
int old_stderr = -1; int old_stderr = -1;

View File

@ -305,7 +305,10 @@ void cpu_handle_guest_debug(CPUState *cpu)
cpu_single_step(cpu, 0); cpu_single_step(cpu, 0);
} }
} else { } else {
gdb_set_stop_cpu(cpu); /* Begin LibAFL changes */
// With LibAFL Breakpoints there is no gdb attached.
// gdb_set_stop_cpu(cpu);
/* End LibAFL changes */
qemu_system_debug_request(); qemu_system_debug_request();
cpu->stopped = true; cpu->stopped = true;
} }

View File

@ -44,11 +44,139 @@ int main(int argc, char **argv)
#define main qemu_main #define main qemu_main
#endif /* CONFIG_COCOA */ #endif /* CONFIG_COCOA */
/* Begin LibAFL instrumentation */
#include "sysemu/runstate.h"
#include "sysemu/cpu-timers.h"
#include "migration/snapshot.h"
#include "hw/core/cpu.h"
#include "qapi/error.h"
#include "exec/memory.h"
void libafl_qemu_main_loop( void );
void libafl_qemu_run( void );
void libafl_qemu_sys_init(int argc, char **argv, char **envp);
void libafl_qemu_cleanup( void );
void libafl_qemu_sys_init(int argc, char **argv, char **envp) { qemu_init(argc, argv, envp); }
void libafl_qemu_cleanup( void ) { qemu_cleanup(); }
void libafl_qemu_set_native_breakpoint( vaddr );
void libafl_qemu_remove_native_breakpoint( vaddr );
int libafl_snapshot_save( const char* );
int libafl_snapshot_load( const char* );
void libafl_phys_read(vaddr, uint8_t*, int);
void libafl_phys_write(vaddr, uint8_t*, int);
int64_t libafl_get_clock( void );
#ifdef TARGET_ARM
extern void libafl_start_int_timer(void);
#endif
void libafl_qemu_main_loop( void )
{
#ifdef TARGET_ARM
libafl_start_int_timer();
#endif
vm_start();
qemu_main_loop();
}
void libafl_qemu_run( void ) { libafl_qemu_main_loop(); }
void libafl_qemu_set_native_breakpoint(vaddr pc)
{
CPUState *cpu;
CPU_FOREACH(cpu) {
cpu_breakpoint_insert(cpu, pc, BP_GDB, NULL);
}
}
void libafl_qemu_remove_native_breakpoint(vaddr pc)
{
CPUState *cpu;
CPU_FOREACH(cpu) {
cpu_breakpoint_remove(cpu, pc, BP_GDB);
}
}
int libafl_snapshot_save( const char* name )
{
Error *err = NULL;
save_snapshot(name, true, NULL, false, NULL, &err);
return err == 0;
}
int libafl_snapshot_load( const char* name )
{
Error *err = NULL;
load_snapshot(name, NULL, false, NULL, &err);
return err == 0;
}
void libafl_phys_read(vaddr addr, uint8_t* buf, int len)
{
cpu_physical_memory_read(addr, buf, len);
}
void libafl_phys_write(vaddr addr, uint8_t* buf, int len)
{
cpu_physical_memory_write(addr, buf, len);
}
int64_t libafl_get_clock( void )
{
return icount_get_raw();
}
#ifndef AS_SHARED_LIB
#ifdef TARGET_ARM
extern unsigned int libafl_int_offset;
#endif
int main(int argc, char **argv, char **envp) int main(int argc, char **argv, char **envp)
{ {
qemu_init(argc, argv, envp); qemu_init(argc, argv, envp);
qemu_main_loop(); qemu_main_loop();
qemu_cleanup(); qemu_cleanup();
//LIBAFL Instrumentation Demo
/*
// unsigned char buf[32] = "_`abcdefghijklmnopqrstuvwxyz{|}~";
#ifdef TARGET_ARM
libafl_int_offset = 375000;
#endif
// unsigned char buf[32] = "\x02\x9b\x02\x9b\x02\x9b\x02\x9b"; // 0xFA71 x 4
unsigned char buf[32] = "\x05\x29\x07\x1f\x0b\x17\x01\x17"; // 5*73 7*59 11*43
unsigned char len = 8;
libafl_qemu_sys_init(argc, argv, envp);
int pheader = 0x5be4;
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
libafl_phys_read(0x20000110-0x20000100+pheader, buf,32);
libafl_phys_write(0x20000108-0x20000100+pheader, &len,1);
printf("FUZZ_INPUT[0]: %x\n", buf[0]);
libafl_qemu_set_native_breakpoint(0xae);
libafl_snapshot_save("Start");
int counter = 3;
do {
libafl_qemu_main_loop();
libafl_snapshot_load("Start");
puts("Reload has occured");
counter--;
} while (runstate_check(RUN_STATE_DEBUG) && counter);
libafl_qemu_cleanup();
*/
/*
// Clock comparison
unsigned char ex1[32] = "_`abcdefghijklmnopqrstuvwxyz{|}~";
// unsigned char ex1[32] = "a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
unsigned char ex2[32] = "a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
libafl_qemu_sys_init(argc, argv, envp);
libafl_qemu_set_native_breakpoint(0x4be0);
libafl_snapshot_save("Start");
libafl_phys_write(0x20000110-0x20000100+0x00006ae4, ex1,32);
libafl_qemu_main_loop();
printf("Post ex1: %ld\n",libafl_get_clock());
libafl_snapshot_load("Start");
libafl_phys_write(0x20000110-0x20000100+0x00006ae4, ex2,32);
libafl_qemu_main_loop();
printf("Post ex2: %ld\n",libafl_get_clock());
*/
return 0; return 0;
} }
#endif
/* End LibAFL instrumentation */

View File

@ -668,6 +668,10 @@ static bool main_loop_should_exit(void)
if (qemu_debug_requested()) { if (qemu_debug_requested()) {
vm_stop(RUN_STATE_DEBUG); vm_stop(RUN_STATE_DEBUG);
/* Begin LibAFL instrumentation */
// main loop will exit back to fuzzer
return true;
/* End LibAFL instrumentation */
} }
if (qemu_suspend_requested()) { if (qemu_suspend_requested()) {
qemu_system_suspend(); qemu_system_suspend();

10
starter.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
if [ ! -f dummy.qcow2 ]; then
qemu-img create -f qcow2 dummy.qcow2 32M
fi
build/qemu-system-arm -machine mps2-an385 -monitor null -semihosting \
--semihosting-config enable=on,target=native \
-kernel $1 \
-serial stdio -nographic \
-snapshot -drive if=none,format=qcow2,file=dummy.qcow2 \
-icount shift=auto,align=off,sleep=off

View File

@ -816,6 +816,7 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
shadow_regions[j].gpa = dev->regions[i].gpa; shadow_regions[j].gpa = dev->regions[i].gpa;
shadow_regions[j].size = dev->regions[i].size; shadow_regions[j].size = dev->regions[i].size;
shadow_regions[j].qva = dev->regions[i].qva; shadow_regions[j].qva = dev->regions[i].qva;
shadow_regions[j].mmap_addr = dev->regions[i].mmap_addr;
shadow_regions[j].mmap_offset = dev->regions[i].mmap_offset; shadow_regions[j].mmap_offset = dev->regions[i].mmap_offset;
j++; j++;
} else { } else {

View File

@ -265,12 +265,15 @@ static void arm_cpu_reset(DeviceState *dev)
env->uncached_cpsr = ARM_CPU_MODE_SVC; env->uncached_cpsr = ARM_CPU_MODE_SVC;
} }
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F; env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
#endif
if (arm_feature(env, ARM_FEATURE_M)) { if (arm_feature(env, ARM_FEATURE_M)) {
#ifndef CONFIG_USER_ONLY
uint32_t initial_msp; /* Loaded from 0x0 */ uint32_t initial_msp; /* Loaded from 0x0 */
uint32_t initial_pc; /* Loaded from 0x4 */ uint32_t initial_pc; /* Loaded from 0x4 */
uint8_t *rom; uint8_t *rom;
uint32_t vecbase; uint32_t vecbase;
#endif
if (cpu_isar_feature(aa32_lob, cpu)) { if (cpu_isar_feature(aa32_lob, cpu)) {
/* /*
@ -324,6 +327,8 @@ static void arm_cpu_reset(DeviceState *dev)
env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK | env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK; R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
} }
#ifndef CONFIG_USER_ONLY
/* Unlike A/R profile, M profile defines the reset LR value */ /* Unlike A/R profile, M profile defines the reset LR value */
env->regs[14] = 0xffffffff; env->regs[14] = 0xffffffff;
@ -352,8 +357,22 @@ static void arm_cpu_reset(DeviceState *dev)
env->regs[13] = initial_msp & 0xFFFFFFFC; env->regs[13] = initial_msp & 0xFFFFFFFC;
env->regs[15] = initial_pc & ~1; env->regs[15] = initial_pc & ~1;
env->thumb = initial_pc & 1; env->thumb = initial_pc & 1;
#else
/*
* For user mode we run non-secure and with access to the FPU.
* The FPU context is active (ie does not need further setup)
* and is owned by non-secure.
*/
env->v7m.secure = false;
env->v7m.nsacr = 0xcff;
env->v7m.cpacr[M_REG_NS] = 0xf0ffff;
env->v7m.fpccr[M_REG_S] &=
~(R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK);
env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
#endif
} }
#ifndef CONFIG_USER_ONLY
/* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently /* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
* executing as AArch32 then check if highvecs are enabled and * executing as AArch32 then check if highvecs are enabled and
* adjust the PC accordingly. * adjust the PC accordingly.

View File

@ -4186,6 +4186,12 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
tcg_gen_movi_i64(cpu_reg(s, rd), base + offset); tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
} }
//// --- Begin LibAFL code ---
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot);
//// --- End LibAFL code ---
/* /*
* Add/subtract (immediate) * Add/subtract (immediate)
* *
@ -4217,6 +4223,16 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
imm <<= 12; imm <<= 12;
} }
//// --- Begin LibAFL code ---
if (rd == 31 && sub_op) { // cmp xX, imm
TCGv_i64 tcg_imm = tcg_const_i64(imm);
libafl_gen_cmp(s->pc_curr, tcg_rn, tcg_imm, is_64bit ? MO_64 : MO_32);
tcg_temp_free_i64(tcg_imm);
}
//// --- End LibAFL code ---
tcg_result = tcg_temp_new_i64(); tcg_result = tcg_temp_new_i64();
if (!setflags) { if (!setflags) {
if (sub_op) { if (sub_op) {
@ -4879,6 +4895,13 @@ static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
tcg_rm = read_cpu_reg(s, rm, sf); tcg_rm = read_cpu_reg(s, rm, sf);
ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3); ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3);
//// --- Begin LibAFL code ---
if (rd == 31 && sub_op) // cmp xX, xY
libafl_gen_cmp(s->pc_curr, tcg_rn, tcg_rm, sf ? MO_64 : MO_32);
//// --- End LibAFL code ---
tcg_result = tcg_temp_new_i64(); tcg_result = tcg_temp_new_i64();
if (!setflags) { if (!setflags) {
@ -4943,6 +4966,13 @@ static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6); shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6);
//// --- Begin LibAFL code ---
if (rd == 31 && sub_op) // cmp xX, xY
libafl_gen_cmp(s->pc_curr, tcg_rn, tcg_rm, sf ? MO_64 : MO_32);
//// --- End LibAFL code ---
tcg_result = tcg_temp_new_i64(); tcg_result = tcg_temp_new_i64();
if (!setflags) { if (!setflags) {
@ -5225,6 +5255,12 @@ static void disas_cc(DisasContext *s, uint32_t insn)
} }
tcg_rn = cpu_reg(s, rn); tcg_rn = cpu_reg(s, rn);
//// --- Begin LibAFL code ---
libafl_gen_cmp(s->pc_curr, tcg_rn, tcg_y, sf ? MO_64 : MO_32);
//// --- End LibAFL code ---
/* Set the flags for the new comparison. */ /* Set the flags for the new comparison. */
tcg_tmp = tcg_temp_new_i64(); tcg_tmp = tcg_temp_new_i64();
if (op) { if (op) {

View File

@ -2615,8 +2615,14 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
} }
} }
//// --- Begin LibAFL code ---
void libafl_gen_jmp(target_ulong src, target_ulong dst); // see translate-all.c
//// --- End LibAFL code ---
static inline void gen_jmp(DisasContext *s, uint32_t dest) static inline void gen_jmp(DisasContext *s, uint32_t dest)
{ {
//// --- Begin LibAFL code ---
libafl_gen_jmp(s->pc_curr,dest);
//// --- End LibAFL code ---
gen_jmp_tb(s, dest, 0); gen_jmp_tb(s, dest, 0);
} }
@ -5424,6 +5430,12 @@ static bool store_reg_kind(DisasContext *s, int rd,
g_assert_not_reached(); g_assert_not_reached();
} }
//// --- Begin LibAFL code ---
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot);
//// --- End LibAFL code ---
/* /*
* Data Processing (register) * Data Processing (register)
* *
@ -5440,6 +5452,24 @@ static bool op_s_rrr_shi(DisasContext *s, arg_s_rrr_shi *a,
gen_arm_shift_im(tmp2, a->shty, a->shim, logic_cc); gen_arm_shift_im(tmp2, a->shty, a->shim, logic_cc);
tmp1 = load_reg(s, a->rn); tmp1 = load_reg(s, a->rn);
//// --- Begin LibAFL code ---
if (gen == gen_sub_CC || /*gen == gen_add_CC ||*/ gen == gen_rsb_CC) {
#ifdef TARGET_AARCH64
TCGv tmp1_64 = tcg_temp_new();
TCGv tmp2_64 = tcg_temp_new();
tcg_gen_extu_i32_i64(tmp1_64, tmp1);
tcg_gen_extu_i32_i64(tmp2_64, tmp2);
libafl_gen_cmp(s->pc_curr, tmp1_64, tmp2_64, MO_32);
tcg_temp_free(tmp1_64);
tcg_temp_free(tmp2_64);
#else
libafl_gen_cmp(s->pc_curr, tmp1, tmp2, MO_32);
#endif
}
//// --- End LibAFL code ---
gen(tmp1, tmp1, tmp2); gen(tmp1, tmp1, tmp2);
tcg_temp_free_i32(tmp2); tcg_temp_free_i32(tmp2);
@ -5532,6 +5562,24 @@ static bool op_s_rri_rot(DisasContext *s, arg_s_rri_rot *a,
tmp2 = tcg_const_i32(imm); tmp2 = tcg_const_i32(imm);
tmp1 = load_reg(s, a->rn); tmp1 = load_reg(s, a->rn);
//// --- Begin LibAFL code ---
if (gen == gen_sub_CC || /*gen == gen_add_CC ||*/ gen == gen_rsb_CC) {
#ifdef TARGET_AARCH64
TCGv tmp1_64 = tcg_temp_new();
TCGv tmp2_64 = tcg_temp_new();
tcg_gen_extu_i32_i64(tmp1_64, tmp1);
tcg_gen_extu_i32_i64(tmp2_64, tmp2);
libafl_gen_cmp(s->pc_curr, tmp1_64, tmp2_64, MO_32);
tcg_temp_free(tmp1_64);
tcg_temp_free(tmp2_64);
#else
libafl_gen_cmp(s->pc_curr, tmp1, tmp2, MO_32);
#endif
}
//// --- End LibAFL code ---
gen(tmp1, tmp1, tmp2); gen(tmp1, tmp1, tmp2);
tcg_temp_free_i32(tmp2); tcg_temp_free_i32(tmp2);

View File

@ -3102,7 +3102,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO | MSR_ARCH_CAP_SKIP_L1DFL_VMENTRY | MSR_ARCH_CAP_MDS_NO |
MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO, MSR_ARCH_CAP_PSCHANGE_MC_NO | MSR_ARCH_CAP_TAA_NO,
.features[FEAT_7_1_EAX] = .features[FEAT_7_1_EAX] =
CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16, CPUID_7_1_EAX_AVX512_BF16,
/* XSAVES is added in version 2 */ /* XSAVES is added in version 2 */
.features[FEAT_XSAVE] = .features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |

View File

@ -257,6 +257,7 @@ typedef enum X86Seg {
| CR4_DE_MASK | CR4_PSE_MASK | CR4_PAE_MASK \ | CR4_DE_MASK | CR4_PSE_MASK | CR4_PAE_MASK \
| CR4_MCE_MASK | CR4_PGE_MASK | CR4_PCE_MASK \ | CR4_MCE_MASK | CR4_PGE_MASK | CR4_PCE_MASK \
| CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK |CR4_UMIP_MASK \ | CR4_OSFXSR_MASK | CR4_OSXMMEXCPT_MASK |CR4_UMIP_MASK \
| CR4_LA57_MASK \
| CR4_FSGSBASE_MASK | CR4_PCIDE_MASK | CR4_OSXSAVE_MASK \ | CR4_FSGSBASE_MASK | CR4_PCIDE_MASK | CR4_OSXSAVE_MASK \
| CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK)) | CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_PKE_MASK | CR4_PKS_MASK))

View File

@ -90,19 +90,10 @@ static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_f
target_ulong pdpe_addr; target_ulong pdpe_addr;
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) { if (pg_mode & PG_MODE_LMA) {
bool la57 = pg_mode & PG_MODE_LA57; bool la57 = pg_mode & PG_MODE_LA57;
uint64_t pml5e_addr, pml5e; uint64_t pml5e_addr, pml5e;
uint64_t pml4e_addr, pml4e; uint64_t pml4e_addr, pml4e;
int32_t sext;
/* test virtual address sign extension */
sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47;
if (get_hphys_func && sext != 0 && sext != -1) {
env->error_code = 0;
cs->exception_index = EXCP0D_GPF;
return 1;
}
if (la57) { if (la57) {
pml5e_addr = ((cr3 & ~0xfff) + pml5e_addr = ((cr3 & ~0xfff) +
@ -287,7 +278,7 @@ do_check_protect_pse36:
*prot |= PAGE_EXEC; *prot |= PAGE_EXEC;
} }
if (!(env->hflags & HF_LMA_MASK)) { if (!(pg_mode & PG_MODE_LMA)) {
pkr = 0; pkr = 0;
} else if (ptep & PG_USER_MASK) { } else if (ptep & PG_USER_MASK) {
pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0; pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0;
@ -423,6 +414,18 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size,
page_size = 4096; page_size = 4096;
} else { } else {
pg_mode = get_pg_mode(env); pg_mode = get_pg_mode(env);
if (pg_mode & PG_MODE_LMA) {
int32_t sext;
/* test virtual address sign extension */
sext = (int64_t)addr >> (pg_mode & PG_MODE_LA57 ? 56 : 47);
if (sext != 0 && sext != -1) {
env->error_code = 0;
cs->exception_index = EXCP0D_GPF;
return 1;
}
}
error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1, error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1,
mmu_idx, pg_mode, mmu_idx, pg_mode,
&paddr, &page_size, &prot); &paddr, &page_size, &prot);

View File

@ -32,6 +32,12 @@
#include "exec/log.h" #include "exec/log.h"
//// --- Begin LibAFL code ---
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot);
//// --- End LibAFL code ---
#define PREFIX_REPZ 0x01 #define PREFIX_REPZ 0x01
#define PREFIX_REPNZ 0x02 #define PREFIX_REPNZ 0x02
#define PREFIX_LOCK 0x04 #define PREFIX_LOCK 0x04
@ -1445,6 +1451,13 @@ static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
tcg_gen_sub_tl(s1->T0, s1->cc_srcT, s1->T1); tcg_gen_sub_tl(s1->T0, s1->cc_srcT, s1->T1);
} else { } else {
tcg_gen_mov_tl(s1->cc_srcT, s1->T0); tcg_gen_mov_tl(s1->cc_srcT, s1->T0);
//// --- Begin LibAFL code ---
libafl_gen_cmp(s1->pc, s1->T0, s1->T1, ot);
//// --- End LibAFL code ---
tcg_gen_sub_tl(s1->T0, s1->T0, s1->T1); tcg_gen_sub_tl(s1->T0, s1->T0, s1->T1);
gen_op_st_rm_T0_A0(s1, ot, d); gen_op_st_rm_T0_A0(s1, ot, d);
} }
@ -1488,6 +1501,13 @@ static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
case OP_CMPL: case OP_CMPL:
tcg_gen_mov_tl(cpu_cc_src, s1->T1); tcg_gen_mov_tl(cpu_cc_src, s1->T1);
tcg_gen_mov_tl(s1->cc_srcT, s1->T0); tcg_gen_mov_tl(s1->cc_srcT, s1->T0);
//// --- Begin LibAFL code ---
libafl_gen_cmp(s1->pc, s1->T0, s1->T1, ot);
//// --- End LibAFL code ---
tcg_gen_sub_tl(cpu_cc_dst, s1->T0, s1->T1); tcg_gen_sub_tl(cpu_cc_dst, s1->T0, s1->T1);
set_cc_op(s1, CC_OP_SUBB + ot); set_cc_op(s1, CC_OP_SUBB + ot);
break; break;

View File

@ -2477,8 +2477,13 @@ static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
tcg_out_vldst(s, INSN_VLD1 | 0x7d0, arg, arg1, arg2); tcg_out_vldst(s, INSN_VLD1 | 0x7d0, arg, arg1, arg2);
return; return;
case TCG_TYPE_V128: case TCG_TYPE_V128:
/* regs 2; size 8; align 16 */ /*
tcg_out_vldst(s, INSN_VLD1 | 0xae0, arg, arg1, arg2); * We have only 8-byte alignment for the stack per the ABI.
* Rather than dynamically re-align the stack, it's easier
* to simply not request alignment beyond that. So:
* regs 2; size 8; align 8
*/
tcg_out_vldst(s, INSN_VLD1 | 0xad0, arg, arg1, arg2);
return; return;
default: default:
g_assert_not_reached(); g_assert_not_reached();
@ -2497,8 +2502,8 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
tcg_out_vldst(s, INSN_VST1 | 0x7d0, arg, arg1, arg2); tcg_out_vldst(s, INSN_VST1 | 0x7d0, arg, arg1, arg2);
return; return;
case TCG_TYPE_V128: case TCG_TYPE_V128:
/* regs 2; size 8; align 16 */ /* See tcg_out_ld re alignment: regs 2; size 8; align 8 */
tcg_out_vldst(s, INSN_VST1 | 0xae0, arg, arg1, arg2); tcg_out_vldst(s, INSN_VST1 | 0xad0, arg, arg1, arg2);
return; return;
default: default:
g_assert_not_reached(); g_assert_not_reached();

View File

@ -2860,6 +2860,13 @@ static inline void plugin_gen_mem_callbacks(TCGv vaddr, uint16_t info)
#endif #endif
} }
//// --- Begin LibAFL code ---
void libafl_gen_read(TCGv addr, MemOp ot);
void libafl_gen_write(TCGv addr, MemOp ot);
//// --- End LibAFL code ---
void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop) void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)
{ {
MemOp orig_memop; MemOp orig_memop;
@ -2879,6 +2886,13 @@ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)
} }
addr = plugin_prep_mem_callbacks(addr); addr = plugin_prep_mem_callbacks(addr);
//// --- Begin LibAFL code ---
libafl_gen_read(addr, memop);
//// --- End LibAFL code ---
gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx); gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
plugin_gen_mem_callbacks(addr, info); plugin_gen_mem_callbacks(addr, info);
@ -2924,6 +2938,13 @@ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)
} }
addr = plugin_prep_mem_callbacks(addr); addr = plugin_prep_mem_callbacks(addr);
//// --- Begin LibAFL code ---
libafl_gen_write(addr, memop);
//// --- End LibAFL code ---
if (TCG_TARGET_HAS_qemu_st8_i32 && (memop & MO_SIZE) == MO_8) { if (TCG_TARGET_HAS_qemu_st8_i32 && (memop & MO_SIZE) == MO_8) {
gen_ldst_i32(INDEX_op_qemu_st8_i32, val, addr, memop, idx); gen_ldst_i32(INDEX_op_qemu_st8_i32, val, addr, memop, idx);
} else { } else {
@ -2966,6 +2987,13 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop)
} }
addr = plugin_prep_mem_callbacks(addr); addr = plugin_prep_mem_callbacks(addr);
//// --- Begin LibAFL code ---
libafl_gen_read(addr, memop);
//// --- End LibAFL code ---
gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx); gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
plugin_gen_mem_callbacks(addr, info); plugin_gen_mem_callbacks(addr, info);
@ -3024,6 +3052,13 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop)
} }
addr = plugin_prep_mem_callbacks(addr); addr = plugin_prep_mem_callbacks(addr);
//// --- Begin LibAFL code ---
libafl_gen_write(addr, memop);
//// --- End LibAFL code ---
gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx); gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
plugin_gen_mem_callbacks(addr, info); plugin_gen_mem_callbacks(addr, info);

View File

@ -566,6 +566,16 @@ static void process_op_defs(TCGContext *s);
static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
TCGReg reg, const char *name); TCGReg reg, const char *name);
//// --- Begin LibAFL code ---
void libafl_helper_table_add(TCGHelperInfo* info);
void libafl_helper_table_add(TCGHelperInfo* info) {
g_hash_table_insert(helper_table, (gpointer)info->func,
(gpointer)info);
}
//// --- End LibAFL code ---
static void tcg_context_init(unsigned max_cpus) static void tcg_context_init(unsigned max_cpus)
{ {
TCGContext *s = &tcg_init_ctx; TCGContext *s = &tcg_init_ctx;
@ -3060,7 +3070,13 @@ static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
g_assert_not_reached(); g_assert_not_reached();
} }
assert(align <= TCG_TARGET_STACK_ALIGN); /*
* Assume the stack is sufficiently aligned.
* This affects e.g. ARM NEON, where we have 8 byte stack alignment
* and do not require 16 byte vector alignment. This seems slightly
* easier than fully parameterizing the above switch statement.
*/
align = MIN(TCG_TARGET_STACK_ALIGN, align);
off = ROUND_UP(s->current_frame_offset, align); off = ROUND_UP(s->current_frame_offset, align);
/* If we've exhausted the stack frame, restart with a smaller TB. */ /* If we've exhausted the stack frame, restart with a smaller TB. */

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -859,6 +859,23 @@ static void test_acpi_q35_tcg_bridge(void)
free_test_data(&data); free_test_data(&data);
} }
static void test_acpi_q35_multif_bridge(void)
{
test_data data = {
.machine = MACHINE_Q35,
.variant = ".multi-bridge",
};
test_acpi_one("-device pcie-root-port,id=pcie-root-port-0,"
"multifunction=on,"
"port=0x0,chassis=1,addr=0x2,bus=pcie.0 "
"-device pcie-root-port,id=pcie-root-port-1,"
"port=0x1,chassis=2,addr=0x3.0x1,bus=pcie.0 "
"-device virtio-balloon,id=balloon0,"
"bus=pcie.0,addr=0x4.0x2",
&data);
free_test_data(&data);
}
static void test_acpi_q35_tcg_mmio64(void) static void test_acpi_q35_tcg_mmio64(void)
{ {
test_data data = { test_data data = {
@ -1528,6 +1545,7 @@ int main(int argc, char *argv[])
test_acpi_piix4_no_acpi_pci_hotplug); test_acpi_piix4_no_acpi_pci_hotplug);
qtest_add_func("acpi/q35", test_acpi_q35_tcg); qtest_add_func("acpi/q35", test_acpi_q35_tcg);
qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge); qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge);
qtest_add_func("acpi/q35/multif-bridge", test_acpi_q35_multif_bridge);
qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64); qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64);
qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi); qtest_add_func("acpi/piix4/ipmi", test_acpi_piix4_tcg_ipmi);
qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi); qtest_add_func("acpi/q35/ipmi", test_acpi_q35_tcg_ipmi);

View File

@ -32,6 +32,9 @@
/* TODO actually test the results and get rid of this */ /* TODO actually test the results and get rid of this */
#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__)) #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
#define DRIVE_FLOPPY_BLANK \
"-drive if=floppy,file=null-co://,file.read-zeroes=on,format=raw,size=1440k"
#define TEST_IMAGE_SIZE 1440 * 1024 #define TEST_IMAGE_SIZE 1440 * 1024
#define FLOPPY_BASE 0x3f0 #define FLOPPY_BASE 0x3f0
@ -546,6 +549,40 @@ static void fuzz_registers(void)
} }
} }
static bool qtest_check_clang_sanitizer(void)
{
#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
return true;
#else
g_test_skip("QEMU not configured using --enable-sanitizers");
return false;
#endif
}
static void test_cve_2021_20196(void)
{
QTestState *s;
if (!qtest_check_clang_sanitizer()) {
return;
}
s = qtest_initf("-nographic -m 32M -nodefaults " DRIVE_FLOPPY_BLANK);
qtest_outw(s, 0x3f4, 0x0500);
qtest_outb(s, 0x3f5, 0x00);
qtest_outb(s, 0x3f5, 0x00);
qtest_outw(s, 0x3f4, 0x0000);
qtest_outb(s, 0x3f5, 0x00);
qtest_outw(s, 0x3f1, 0x0400);
qtest_outw(s, 0x3f4, 0x0000);
qtest_outw(s, 0x3f4, 0x0000);
qtest_outb(s, 0x3f5, 0x00);
qtest_outb(s, 0x3f5, 0x01);
qtest_outw(s, 0x3f1, 0x0500);
qtest_outb(s, 0x3f5, 0x00);
qtest_quit(s);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int fd; int fd;
@ -576,6 +613,7 @@ int main(int argc, char **argv)
qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18); qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18);
qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19); qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19);
qtest_add_func("/fdc/fuzz-registers", fuzz_registers); qtest_add_func("/fdc/fuzz-registers", fuzz_registers);
qtest_add_func("/fdc/fuzz/cve_2021_20196", test_cve_2021_20196);
ret = g_test_run(); ret = g_test_run();

View File

@ -16,7 +16,10 @@ SECTIONS {
*(.rodata) *(.rodata)
} :text } :text
/* Keep build ID and PVH notes in same section */ /DISCARD/ : {
*(.note.gnu*)
}
.notes : { .notes : {
*(.note.*) *(.note.*)
} :note } :note

View File

@ -1345,25 +1345,22 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa,
SocketAddress *addr; SocketAddress *addr;
struct sockaddr_un *su = (struct sockaddr_un *)sa; struct sockaddr_un *su = (struct sockaddr_un *)sa;
assert(salen >= sizeof(su->sun_family) + 1 &&
salen <= sizeof(struct sockaddr_un));
addr = g_new0(SocketAddress, 1); addr = g_new0(SocketAddress, 1);
addr->type = SOCKET_ADDRESS_TYPE_UNIX; addr->type = SOCKET_ADDRESS_TYPE_UNIX;
salen -= offsetof(struct sockaddr_un, sun_path);
#ifdef CONFIG_LINUX #ifdef CONFIG_LINUX
if (!su->sun_path[0]) { if (salen > 0 && !su->sun_path[0]) {
/* Linux abstract socket */ /* Linux abstract socket */
addr->u.q_unix.path = g_strndup(su->sun_path + 1, addr->u.q_unix.path = g_strndup(su->sun_path + 1, salen - 1);
salen - sizeof(su->sun_family) - 1);
addr->u.q_unix.has_abstract = true; addr->u.q_unix.has_abstract = true;
addr->u.q_unix.abstract = true; addr->u.q_unix.abstract = true;
addr->u.q_unix.has_tight = true; addr->u.q_unix.has_tight = true;
addr->u.q_unix.tight = salen < sizeof(*su); addr->u.q_unix.tight = salen < sizeof(su->sun_path);
return addr; return addr;
} }
#endif #endif
addr->u.q_unix.path = g_strndup(su->sun_path, sizeof(su->sun_path)); addr->u.q_unix.path = g_strndup(su->sun_path, salen);
return addr; return addr;
} }
#endif /* WIN32 */ #endif /* WIN32 */

View File

@ -46,6 +46,7 @@
unsigned long rcu_gp_ctr = RCU_GP_LOCKED; unsigned long rcu_gp_ctr = RCU_GP_LOCKED;
QemuEvent rcu_gp_event; QemuEvent rcu_gp_event;
static int in_drain_call_rcu;
static QemuMutex rcu_registry_lock; static QemuMutex rcu_registry_lock;
static QemuMutex rcu_sync_lock; static QemuMutex rcu_sync_lock;
@ -107,6 +108,8 @@ static void wait_for_readers(void)
* get some extra futex wakeups. * get some extra futex wakeups.
*/ */
qatomic_set(&index->waiting, false); qatomic_set(&index->waiting, false);
} else if (qatomic_read(&in_drain_call_rcu)) {
notifier_list_notify(&index->force_rcu, NULL);
} }
} }
@ -339,8 +342,10 @@ void drain_call_rcu(void)
* assumed. * assumed.
*/ */
qatomic_inc(&in_drain_call_rcu);
call_rcu1(&rcu_drain.rcu, drain_rcu_callback); call_rcu1(&rcu_drain.rcu, drain_rcu_callback);
qemu_event_wait(&rcu_drain.drain_complete_event); qemu_event_wait(&rcu_drain.drain_complete_event);
qatomic_dec(&in_drain_call_rcu);
if (locked) { if (locked) {
qemu_mutex_lock_iothread(); qemu_mutex_lock_iothread();
@ -363,6 +368,20 @@ void rcu_unregister_thread(void)
qemu_mutex_unlock(&rcu_registry_lock); qemu_mutex_unlock(&rcu_registry_lock);
} }
void rcu_add_force_rcu_notifier(Notifier *n)
{
qemu_mutex_lock(&rcu_registry_lock);
notifier_list_add(&rcu_reader.force_rcu, n);
qemu_mutex_unlock(&rcu_registry_lock);
}
void rcu_remove_force_rcu_notifier(Notifier *n)
{
qemu_mutex_lock(&rcu_registry_lock);
notifier_remove(n);
qemu_mutex_unlock(&rcu_registry_lock);
}
static void rcu_init_complete(void) static void rcu_init_complete(void)
{ {
QemuThread thread; QemuThread thread;