public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Michael Young <m.a.young@durham.ac.uk>
To: git-commits@fedoraproject.org
Subject: [rpms/xen] f44: 4 security issues
Date: Wed, 16 Sep 2026 20:55:43 GMT [thread overview]
Message-ID: <178959214374.1.18274883001572249853.rpms-xen-b62408c3d862@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : rpms/xen
Branch : f44
Commit : b62408c3d86241724480124bad102dcaf390aa41
Author : Michael Young <m.a.young@durham.ac.uk>
Date : 2026-09-16T21:53:07+01:00
Stats : +450/-1 in 6 file(s)
URL : https://src.fedoraproject.org/rpms/xen/c/b62408c3d86241724480124bad102dcaf390aa41?branch=f44
Log:
4 security issues
x86: DMs may cause mem leak by IRQ binding [XSA-509, CVE-2026-62437]
x86: improper handling of HVM emulation return codes
[XSA-510, CVE-2026-79602]
Unconditionally do TLB flushing ahead of page scrubbing [XSA-511,
CVE-2026-79603]
oxenstored: Unbounded accumulation of watches [XSA-512, CVE-2026-79604]
---
diff --git a/xen.spec b/xen.spec
index 27c1305..b5487e6 100644
--- a/xen.spec
+++ b/xen.spec
@@ -51,7 +51,7 @@
Summary: Xen is a virtual machine monitor
Name: xen
Version: 4.21.2
-Release: 1%{?dist}
+Release: 2%{?dist}
# Automatically converted from old format: GPLv2+ and LGPLv2+ and BSD - review is highly recommended.
License: GPL-2.0-or-later AND LicenseRef-Callaway-LGPLv2+ AND LicenseRef-Callaway-BSD
URL: http://xen.org/
@@ -78,6 +78,11 @@ Patch6: xen.gcc11.fixes.patch
Patch7: xen.gcc12.fixes.patch
Patch8: xen.efi.build.patch
Patch9: xen.python3.12.patch
+Patch10: xsa509.patch
+Patch11: xsa510.patch
+Patch12: xsa511-4.21.patch
+Patch13: xsa512-1.patch
+Patch14: xsa512-2.patch
# build using Fedora seabios and ipxe packages for roms
@@ -263,6 +268,11 @@ This package contains files used in testing the xen builds
%patch 7 -p1
%patch 8 -p1
%patch 9 -p1
+%patch 10 -p1
+%patch 11 -p1
+%patch 12 -p1
+%patch 13 -p1
+%patch 14 -p1
# stubdom sources
cp -v %{SOURCE10} %{SOURCE11} %{SOURCE12} %{SOURCE13} %{SOURCE14} %{SOURCE15} stubdom
@@ -818,6 +828,14 @@ fi
%{_libexecdir}/xen/tests/*
%changelog
+* Wed Sep 16 2026 Michael Young <m.a.young@durham.ac.uk> - 4.21.2-2
+- x86: DMs may cause mem leak by IRQ binding [XSA-509, CVE-2026-62437]
+ x86: improper handling of HVM emulation return codes
+ [XSA-510, CVE-2026-79602]
+ Unconditionally do TLB flushing ahead of page scrubbing [XSA-511,
+ CVE-2026-79603]
+ oxenstored: Unbounded accumulation of watches [XSA-512, CVE-2026-79604]
+
* Thu Jul 30 2026 Michael Young <m.a.young@durham.ac.uk> - 4.21.2-1
- update to xen 4.21.2
- includes security fixes
diff --git a/xsa509.patch b/xsa509.patch
new file mode 100644
index 0000000..51cae81
--- /dev/null
+++ b/xsa509.patch
@@ -0,0 +1,33 @@
+From: Jan Beulich <jbeulich@suse.com>
+Subject: x86/pass-through: disallow pt_irq_create_bind() on dying domains
+
+DMs may invoke XEN_DOMCTL_bind_pt_irq for domains already under
+destruction. When XEN_DOMCTL_bind_pt_irq is invoked after
+pci_release_devices() (invoked from underneath domain_kill()) had already
+completed, it would allocate hvm_domain_irq(d)->dpci anew, without that
+ever being freed during subsequent domain cleanup.
+
+Leverage evtchn_destroy()'s kind-of-spin-barrier, allowing to simply check
+->is_dying with the domain's event lock held.
+
+This is XSA-509 / CVE-2026-62437.
+
+Fixes: 7a26b541a202 ("vtd: Dynamically allocate IRQ-tracking structures, only for those")
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
+
+--- a/xen/drivers/passthrough/x86/hvm.c
++++ b/xen/drivers/passthrough/x86/hvm.c
+@@ -231,6 +231,12 @@ int pt_irq_create_bind(
+ restart:
+ write_lock(&d->event_lock);
+
++ if ( d->is_dying )
++ {
++ write_unlock(&d->event_lock);
++ return -ESRCH;
++ }
++
+ hvm_irq_dpci = domain_get_irq_dpci(d);
+ if ( !hvm_irq_dpci && !is_hardware_domain(d) )
+ {
diff --git a/xsa510.patch b/xsa510.patch
new file mode 100644
index 0000000..0ad3b49
--- /dev/null
+++ b/xsa510.patch
@@ -0,0 +1,39 @@
+From 796537311797d600c0c716d0c015531fc41abb92 Mon Sep 17 00:00:00 2001
+From: Roger Pau Monne <roger@xenproject.org>
+Date: Fri, 7 Aug 2026 11:03:48 +0200
+Subject: [PATCH] x86/emul: cope with internal handlers returning X86EMUL_RETRY
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+hvm_io_intercept() can return X86EMUL_RETRY, and as such it needs to be
+handled in the switch in hvmemul_do_io() to avoid triggering the BUG() from
+the default case.
+
+Reset the vCPU state to no in-flight IOREQ and return X86EMUL_RETRY so that
+the access is retried.
+
+This is XSA-510 / CVE-2026-79602.
+
+Reported-by: Jiqian Chen <Jiqian.Chen@amd.com>
+Signed-off-by: Roger Pau Monné <roger@xenproject.org>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+---
+ xen/arch/x86/hvm/emulate.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
+index 2efb1d4f0823..c09ea002ec62 100644
+--- a/xen/arch/x86/hvm/emulate.c
++++ b/xen/arch/x86/hvm/emulate.c
+@@ -308,6 +308,7 @@ static int hvmemul_do_io(
+ switch ( rc )
+ {
+ case X86EMUL_OKAY:
++ case X86EMUL_RETRY:
+ vio->req.state = STATE_IOREQ_NONE;
+ break;
+ case X86EMUL_UNHANDLEABLE:
+--
+2.53.0
+
diff --git a/xsa511-4.21.patch b/xsa511-4.21.patch
new file mode 100644
index 0000000..10ea1f5
--- /dev/null
+++ b/xsa511-4.21.patch
@@ -0,0 +1,201 @@
+From 70e281422ad1ee5e8f9cb2dbaad418db08dc5bda Mon Sep 17 00:00:00 2001
+From: Roger Pau Monne <roger@xenproject.org>
+Date: Tue, 4 Aug 2026 12:23:19 +0200
+Subject: [PATCH] xen/page_alloc: ensure TLB flush is done ahead of page
+ scrubbing
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The current way in which idle TLB flush and TLB flushing when allocating a
+page are done allows for the scrubbing to be done ahead of the TLB flush.
+A PV domain can still have a TLB entry for the page after scrubbing, and
+hence it may be able to modify it. Such unintended page accessing allows
+domains to possibly exchange information even when `xsm=silo scrub-domheap`
+are in effect.
+
+Remove the MEMF_no_tlbflush memory allocation flag, and reorder the
+flushing so it's always done ahead of the scrubbing in
+alloc_{,color_}heap_pages(). The sole user of MEMF_no_tlbflush is
+populate_physmap(), and given the constrains above it's no longer safe
+to defer the flush, hence the flag removal and the folding of the flush in
+the allocator function itself.
+
+This is XSA-511 / CVE-2026-79603.
+
+Fixes: 24f1a58d1954 ("mm: option to _always_ scrub freed domheap pages")
+Signed-off-by: Roger Pau Monné <roger@xenproject.org>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+---
+ xen/common/memory.c | 21 ---------------------
+ xen/common/page_alloc.c | 34 +++++++++++++++++++---------------
+ xen/include/xen/mm.h | 2 --
+ 3 files changed, 19 insertions(+), 38 deletions(-)
+
+diff --git a/xen/common/memory.c b/xen/common/memory.c
+index 76a1bf1b1159..6c1ea6aae273 100644
+--- a/xen/common/memory.c
++++ b/xen/common/memory.c
+@@ -165,8 +165,6 @@ static void populate_physmap(struct memop_args *a)
+ unsigned int i, j;
+ xen_pfn_t gpfn;
+ struct domain *d = a->domain, *curr_d = current->domain;
+- bool need_tlbflush = false;
+- uint32_t tlbflush_timestamp = 0;
+
+ if ( !guest_handle_subrange_okay(a->extent_list, a->nr_done,
+ a->nr_extents-1) )
+@@ -178,15 +176,6 @@ static void populate_physmap(struct memop_args *a)
+
+ if ( unlikely(!d->creation_finished) )
+ {
+- /*
+- * With MEMF_no_tlbflush set, alloc_heap_pages() will ignore
+- * TLB-flushes. After VM creation, this is a security issue (it can
+- * make pages accessible to guest B, when guest A may still have a
+- * cached mapping to them). So we do this only during domain creation,
+- * when the domain itself has not yet been unpaused for the first
+- * time.
+- */
+- a->memflags |= MEMF_no_tlbflush;
+ /*
+ * With MEMF_no_icache_flush, alloc_heap_pages() will skip
+ * performing icache flushes. We do it only before domain
+@@ -286,13 +275,6 @@ static void populate_physmap(struct memop_args *a)
+ goto out;
+ }
+
+- if ( unlikely(a->memflags & MEMF_no_tlbflush) )
+- {
+- for ( j = 0; j < (1U << a->extent_order); j++ )
+- accumulate_tlbflush(&need_tlbflush, &page[j],
+- &tlbflush_timestamp);
+- }
+-
+ mfn = page_to_mfn(page);
+ }
+
+@@ -307,9 +289,6 @@ static void populate_physmap(struct memop_args *a)
+ }
+
+ out:
+- if ( need_tlbflush )
+- filtered_flush_tlb_mask(tlbflush_timestamp);
+-
+ if ( a->memflags & MEMF_no_icache_flush )
+ invalidate_icache();
+
+diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
+index a7b3b04a4d01..c4a8f8bc767e 100644
+--- a/xen/common/page_alloc.c
++++ b/xen/common/page_alloc.c
+@@ -1096,15 +1096,17 @@ static struct page_info *alloc_heap_pages(
+ /* Preserve PGC_need_scrub so we can check it after lock is dropped. */
+ pg[i].count_info = PGC_state_inuse | (pg[i].count_info & PGC_need_scrub);
+
+- if ( !(memflags & MEMF_no_tlbflush) )
+- accumulate_tlbflush(&need_tlbflush, &pg[i],
+- &tlbflush_timestamp);
++ accumulate_tlbflush(&need_tlbflush, &pg[i], &tlbflush_timestamp);
+
+ init_free_page_fields(&pg[i]);
+ }
+
+ spin_unlock(&heap_lock);
+
++ /* Flush ahead of scrubbing: ensure no PV domain has a stale TLB entry. */
++ if ( need_tlbflush )
++ filtered_flush_tlb_mask(tlbflush_timestamp);
++
+ if ( first_dirty != INVALID_DIRTY_IDX ||
+ (scrub_debug && !(memflags & MEMF_no_scrub)) )
+ {
+@@ -1131,9 +1133,6 @@ static struct page_info *alloc_heap_pages(
+ }
+ }
+
+- if ( need_tlbflush )
+- filtered_flush_tlb_mask(tlbflush_timestamp);
+-
+ /*
+ * Ensure cache and RAM are consistent for platforms where the guest
+ * can control its own visibility of/through the cache.
+@@ -1387,6 +1386,13 @@ bool scrub_free_pages(void)
+ {
+ if ( test_bit(_PGC_need_scrub, &pg[i].count_info) )
+ {
++ bool need_tlbflush = false;
++ uint32_t tlbflush_ts = 0;
++
++ accumulate_tlbflush(&need_tlbflush, &pg[i], &tlbflush_ts);
++ if ( need_tlbflush )
++ filtered_flush_tlb_mask(tlbflush_ts);
++
+ scrub_one_page(&pg[i], true);
+ /*
+ * We can modify count_info without holding heap
+@@ -2054,7 +2060,7 @@ static struct page_info *alloc_color_heap_page(unsigned int memflags,
+ uint32_t tlbflush_timestamp = 0;
+ bool need_scrub;
+
+- if ( memflags & ~(MEMF_no_refcount | MEMF_no_owner | MEMF_no_tlbflush |
++ if ( memflags & ~(MEMF_no_refcount | MEMF_no_owner |
+ MEMF_no_icache_flush | MEMF_no_scrub) )
+ return NULL;
+
+@@ -2083,13 +2089,16 @@ static struct page_info *alloc_color_heap_page(unsigned int memflags,
+ free_colored_pages[color]--;
+ page_list_del(pg, color_heap(color));
+
+- if ( !(memflags & MEMF_no_tlbflush) )
+- accumulate_tlbflush(&need_tlbflush, pg, &tlbflush_timestamp);
++ accumulate_tlbflush(&need_tlbflush, pg, &tlbflush_timestamp);
+
+ init_free_page_fields(pg);
+
+ spin_unlock(&heap_lock);
+
++ /* Flush ahead of scrubbing: ensure no PV domain has a stale TLB entry. */
++ if ( need_tlbflush )
++ filtered_flush_tlb_mask(tlbflush_timestamp);
++
+ if ( !(memflags & MEMF_no_scrub) )
+ {
+ if ( need_scrub )
+@@ -2098,9 +2107,6 @@ static struct page_info *alloc_color_heap_page(unsigned int memflags,
+ check_one_page(pg);
+ }
+
+- if ( need_tlbflush )
+- filtered_flush_tlb_mask(tlbflush_timestamp);
+-
+ flush_page_to_ram(mfn_x(page_to_mfn(pg)),
+ !(memflags & MEMF_no_icache_flush));
+
+@@ -3006,9 +3012,7 @@ static bool prepare_staticmem_pages(struct page_info *pg, unsigned long nr_mfns,
+ goto out_err;
+ }
+
+- if ( !(memflags & MEMF_no_tlbflush) )
+- accumulate_tlbflush(&need_tlbflush, &pg[i],
+- &tlbflush_timestamp);
++ accumulate_tlbflush(&need_tlbflush, &pg[i], &tlbflush_timestamp);
+
+ /*
+ * Preserve flag PGC_static and change page state
+diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
+index b968f47b87e0..58410a367a39 100644
+--- a/xen/include/xen/mm.h
++++ b/xen/include/xen/mm.h
+@@ -204,8 +204,6 @@ struct npfec {
+ #define MEMF_exact_node (1U<<_MEMF_exact_node)
+ #define _MEMF_no_owner 5
+ #define MEMF_no_owner (1U<<_MEMF_no_owner)
+-#define _MEMF_no_tlbflush 6
+-#define MEMF_no_tlbflush (1U<<_MEMF_no_tlbflush)
+ #define _MEMF_no_icache_flush 7
+ #define MEMF_no_icache_flush (1U<<_MEMF_no_icache_flush)
+ #define _MEMF_no_scrub 8
+--
+2.53.0
+
diff --git a/xsa512-1.patch b/xsa512-1.patch
new file mode 100644
index 0000000..9d0256e
--- /dev/null
+++ b/xsa512-1.patch
@@ -0,0 +1,80 @@
+From 5332a2c46db4f96e5d5a57100c55076fe5610beb Mon Sep 17 00:00:00 2001
+From: Andrii Sultanov <andriy.sultanov@vates.tech>
+Date: Thu, 20 Aug 2026 16:00:02 +0100
+Subject: oxenstored: Factor out Process.do_reconnect()
+
+The logic flow here is complicated. In preparation to fix a bug, factor out
+reconnecting a xenbus connection, and fold History.reconnect into it's single
+caller.
+
+No functional change.
+
+This is part of XSA-512 / CVE-2026-79604.
+
+Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
+Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
+Reviewed-by: Andrii Sultanov <andriy.sultanov@vates.tech>
+
+diff --git a/tools/ocaml/xenstored/history.ml b/tools/ocaml/xenstored/history.ml
+index f03fb1832923..3474a62da230 100644
+--- a/tools/ocaml/xenstored/history.ml
++++ b/tools/ocaml/xenstored/history.ml
+@@ -39,10 +39,6 @@ let end_transaction txn con tid commit =
+ trim ~txn ();
+ success
+
+-let reconnect con =
+- trim ();
+- Connection.do_reconnect con
+-
+ let push (x: history_record) =
+ let dom = x.con.Connection.dom in
+ match dom with
+diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
+index 0c9c460a9915..bc68c54c9aba 100644
+--- a/tools/ocaml/xenstored/process.ml
++++ b/tools/ocaml/xenstored/process.ml
+@@ -350,6 +350,13 @@ let do_reset_watches con _t _domains cons _data =
+ Connections.del_watches cons con;
+ Connection.del_transactions con
+
++let do_reconnect cons con =
++ let domstr = Connection.get_domstr con in
++ info "%s requests a reconnect" domstr;
++ History.trim ();
++ Connection.do_reconnect con;
++ info "%s reconnection complete" domstr
++
+ (* only in >= xen3.3 *)
+ let do_set_target con _t _domains cons data =
+ if not (Connection.is_dom0 con)
+@@ -735,9 +742,7 @@ let do_input store cons doms con =
+ if Connection.can_input con then Connection.do_input con
+ else None
+ with Xenbus.Xb.Reconnect ->
+- info "%s requests a reconnect" (Connection.get_domstr con);
+- History.reconnect con;
+- info "%s reconnection complete" (Connection.get_domstr con);
++ do_reconnect cons con;
+ None
+ | Invalid_argument exp | Failure exp ->
+ error "caught exception %s" exp;
+@@ -760,7 +765,7 @@ let do_input store cons doms con =
+ write_access_log ~ty ~tid ~con:(Connection.get_domstr con) ~data;
+ Connection.incr_ops con
+
+-let do_output _store _cons _doms con =
++let do_output _store cons _doms con =
+ Connection.source_flush_watchevents con;
+ if Connection.has_output con then (
+ if Connection.has_new_output con then (
+@@ -775,8 +780,6 @@ let do_output _store _cons _doms con =
+ try
+ ignore (Connection.do_output con)
+ with Xenbus.Xb.Reconnect ->
+- info "%s requests a reconnect" (Connection.get_domstr con);
+- History.reconnect con;
+- info "%s reconnection complete" (Connection.get_domstr con)
++ do_reconnect cons con
+ )
+
diff --git a/xsa512-2.patch b/xsa512-2.patch
new file mode 100644
index 0000000..42252e8
--- /dev/null
+++ b/xsa512-2.patch
@@ -0,0 +1,78 @@
+From 8dc4ca50e62f2587a0213b078fc908fdfb54828b Mon Sep 17 00:00:00 2001
+From: Andrii Sultanov <andriy.sultanov@vates.tech>
+Date: Thu, 20 Aug 2026 15:00:02 +0000
+Subject: oxenstored: Reset the watches trie on domain reconnect
+
+oxenstored maintains two datastructures about watches; one global trie, and
+one hashtable tracked per domain. Both need keeping in sync, and right now
+the global trie is not emptied when a xenbus reconnect is requested.
+
+This is basically the same bug as XSA-330, commit 491a077ed4c5
+("tools/ocaml/xenstored: delete watch from trie too when resetting watches"),
+just tickled via another path.
+
+Arrange for both Process.do_reset_watches() and Process.do_reconnect() to
+share a common codepath for the resetting of watches and transactions.
+Notably, this means that the latter now calls Connections.del_watches() which
+clears the global trie too.
+
+Connections.del_watches() already calls Connection.del_watches() so remove the
+re-clearing of the state from Connection.do_reconnect().
+
+Move History.trim() into reset_watches_and_transactions() so it's on the
+common path, and place it after removing the transactions rather than before.
+
+This is part of XSA-512 / CVE-2026-79604.
+
+Reported-by: David Korczynski <David@Adalogics.com>
+Fixes: 674ad2be409d ("xenstore: extend the xenstore ring with a 'closing' signal")
+Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
+Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
+Reviewed-by: Andrii Sultanov <andriy.sultanov@vates.tech>
+
+diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
+index d11011e16439..37eb2444b936 100644
+--- a/tools/ocaml/xenstored/connection.ml
++++ b/tools/ocaml/xenstored/connection.ml
+@@ -148,13 +148,11 @@ let mark_as_bad con =
+ let initial_next_tid = 1
+
+ let do_reconnect con =
++ (* transactions and watches handled by caller *)
+ Xenbus.Xb.reconnect con.xb;
+ (* dom is the same *)
+- Hashtbl.clear con.transactions;
+ con.next_tid <- initial_next_tid;
+- Hashtbl.clear con.watches;
+ (* anonid is the same *)
+- con.nb_watches <- 0;
+ con.stat_nb_ops <- 0;
+ (* perm is the same *)
+ ()
+diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
+index bc68c54c9aba..fc2558ac3d9b 100644
+--- a/tools/ocaml/xenstored/process.ml
++++ b/tools/ocaml/xenstored/process.ml
+@@ -345,15 +345,18 @@ let do_isintroduced con _t domains _cons data =
+ in
+ if domid = Define.domid_self || Domains.exist domains domid then "T\000" else "F\000"
+
+-(* only in xen >= 4.2 *)
+-let do_reset_watches con _t _domains cons _data =
++let reset_watches_and_transactions cons con =
+ Connections.del_watches cons con;
+- Connection.del_transactions con
++ Connection.del_transactions con;
++ History.trim ()
++
++let do_reset_watches con _t _domains cons _data =
++ reset_watches_and_transactions cons con
+
+ let do_reconnect cons con =
+ let domstr = Connection.get_domstr con in
+ info "%s requests a reconnect" domstr;
+- History.trim ();
++ reset_watches_and_transactions cons con;
+ Connection.do_reconnect con;
+ info "%s reconnection complete" domstr
+
reply other threads:[~2026-09-16 20:55 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178959214374.1.18274883001572249853.rpms-xen-b62408c3d862@fedoraproject.org \
--to=m.a.young@durham.ac.uk \
--cc=git-commits@fedoraproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox