mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
Merge tag 'for-linus-7.2a-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen fixes from Juergen Gross: - rename function parameters and a comment related to xen_exchange_memory() (Jan Beulich) - replace __ASSEMBLY__ with __ASSEMBLER__ (Thomas Huth) - add some sanity checking to the Xen pvcalls frontend driver (Michael Bommarito) - fix error handling in the Xen gntdev driver (Wentao Liang) - fix several minor bugs in Xen related drivers (Yousef Alhouseen) * tag 'for-linus-7.2a-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: x86/Xen: correct commentary and parameter naming of xen_exchange_memory() xenbus: reject unterminated directory replies xen/gntalloc: validate grant count before allocation xen/gntalloc: make grant counters unsigned xen/front-pgdir-shbuf: free grant reference head on errors xen/gntdev: fix error handling in ioctl xen: Replace __ASSEMBLY__ with __ASSEMBLER__ in header files xen/pvcalls: bound backend response req_id before indexing rsp[]
This commit is contained in:
@@ -2291,18 +2291,19 @@ static void xen_remap_exchanged_ptes(unsigned long vaddr, int order,
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the hypercall to exchange a region of our pfns to point to
|
||||
* memory with the required contiguous alignment. Takes the pfns as
|
||||
* input, and populates mfns as output.
|
||||
* Perform the hypercall to exchange a region of our pages to point to memory
|
||||
* with the required contiguous alignment. Takes as input the mfns to trade
|
||||
* in (mfns_in) and the pfns where the new pages are to appear (fns_inout),
|
||||
* and populates mfns as output (fns_inout).
|
||||
*
|
||||
* Returns a success code indicating whether the hypervisor was able to
|
||||
* satisfy the request or not.
|
||||
*/
|
||||
static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in,
|
||||
unsigned long *pfns_in,
|
||||
unsigned long *mfns_in,
|
||||
unsigned long extents_out,
|
||||
unsigned int order_out,
|
||||
unsigned long *mfns_out,
|
||||
unsigned long *fns_inout,
|
||||
unsigned int address_bits)
|
||||
{
|
||||
long rc;
|
||||
@@ -2312,13 +2313,13 @@ static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in,
|
||||
.in = {
|
||||
.nr_extents = extents_in,
|
||||
.extent_order = order_in,
|
||||
.extent_start = pfns_in,
|
||||
.extent_start = mfns_in,
|
||||
.domid = DOMID_SELF
|
||||
},
|
||||
.out = {
|
||||
.nr_extents = extents_out,
|
||||
.extent_order = order_out,
|
||||
.extent_start = mfns_out,
|
||||
.extent_start = fns_inout,
|
||||
.address_bits = address_bits,
|
||||
.domid = DOMID_SELF
|
||||
}
|
||||
|
||||
@@ -70,14 +70,14 @@
|
||||
#include <xen/gntalloc.h>
|
||||
#include <xen/events.h>
|
||||
|
||||
static int limit = 1024;
|
||||
module_param(limit, int, 0644);
|
||||
static unsigned int limit = 1024;
|
||||
module_param(limit, uint, 0644);
|
||||
MODULE_PARM_DESC(limit, "Maximum number of grants that may be allocated by "
|
||||
"the gntalloc device");
|
||||
|
||||
static LIST_HEAD(gref_list);
|
||||
static DEFINE_MUTEX(gref_mutex);
|
||||
static int gref_size;
|
||||
static unsigned int gref_size;
|
||||
|
||||
struct notify_info {
|
||||
uint16_t pgoff:12; /* Bits 0-11: Offset of the byte to clear */
|
||||
@@ -272,6 +272,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
|
||||
int rc = 0;
|
||||
struct ioctl_gntalloc_alloc_gref op;
|
||||
uint32_t *gref_ids;
|
||||
unsigned int limit_snapshot;
|
||||
|
||||
pr_debug("%s: priv %p\n", __func__, priv);
|
||||
|
||||
@@ -280,6 +281,12 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
|
||||
goto out;
|
||||
}
|
||||
|
||||
limit_snapshot = READ_ONCE(limit);
|
||||
if (op.count > limit_snapshot) {
|
||||
rc = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_KERNEL);
|
||||
if (!gref_ids) {
|
||||
rc = -ENOMEM;
|
||||
@@ -292,14 +299,16 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
|
||||
* are about to enforce, removing them here is a good idea.
|
||||
*/
|
||||
do_cleanup();
|
||||
if (gref_size + op.count > limit) {
|
||||
limit_snapshot = READ_ONCE(limit);
|
||||
if (gref_size > limit_snapshot ||
|
||||
op.count > limit_snapshot - gref_size) {
|
||||
mutex_unlock(&gref_mutex);
|
||||
rc = -ENOSPC;
|
||||
goto out_free;
|
||||
}
|
||||
gref_size += op.count;
|
||||
op.index = priv->index;
|
||||
priv->index += op.count * PAGE_SIZE;
|
||||
priv->index += (uint64_t)op.count * PAGE_SIZE;
|
||||
mutex_unlock(&gref_mutex);
|
||||
|
||||
rc = add_grefs(&op, gref_ids, priv);
|
||||
|
||||
@@ -670,11 +670,15 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
|
||||
mutex_lock(&priv->lock);
|
||||
gntdev_add_map(priv, map);
|
||||
op.index = map->index << PAGE_SHIFT;
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
if (copy_to_user(u, &op, sizeof(op)) != 0)
|
||||
if (copy_to_user(u, &op, sizeof(op)) != 0) {
|
||||
list_del(&map->next);
|
||||
mutex_unlock(&priv->lock);
|
||||
gntdev_put_map(priv, map);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ struct pvcalls_bedata {
|
||||
struct xen_pvcalls_front_ring ring;
|
||||
grant_ref_t ref;
|
||||
int irq;
|
||||
bool disabled;
|
||||
|
||||
struct list_head socket_mappings;
|
||||
spinlock_t socket_lock;
|
||||
@@ -131,6 +132,20 @@ static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the backend's response to req_id, or for the frontend to be
|
||||
* disabled because the backend violated the wire protocol. Returns 0 once
|
||||
* the response has arrived, or -EIO if the frontend was disabled.
|
||||
*/
|
||||
static int pvcalls_front_wait_rsp(struct pvcalls_bedata *bedata, u32 req_id)
|
||||
{
|
||||
wait_event(bedata->inflight_req,
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
|
||||
READ_ONCE(bedata->disabled));
|
||||
|
||||
return READ_ONCE(bedata->disabled) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static bool pvcalls_front_write_todo(struct sock_mapping *map)
|
||||
{
|
||||
struct pvcalls_data_intf *intf = map->active.ring;
|
||||
@@ -168,7 +183,8 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
|
||||
struct pvcalls_bedata *bedata;
|
||||
struct xen_pvcalls_response *rsp;
|
||||
uint8_t *src, *dst;
|
||||
int req_id = 0, more = 0, done = 0;
|
||||
u32 req_id = 0;
|
||||
int more = 0, done = 0;
|
||||
|
||||
if (dev == NULL)
|
||||
return IRQ_HANDLED;
|
||||
@@ -179,12 +195,31 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
|
||||
pvcalls_exit();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
if (READ_ONCE(bedata->disabled)) {
|
||||
pvcalls_exit();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
again:
|
||||
while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) {
|
||||
rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons);
|
||||
|
||||
req_id = rsp->req_id;
|
||||
if (req_id >= PVCALLS_NR_RSP_PER_RING) {
|
||||
/*
|
||||
* The backend supplied a req_id that would index
|
||||
* bedata->rsp[] out of bounds: a protocol violation
|
||||
* from a malicious or buggy backend. Log once, stop
|
||||
* trusting this backend and disable the frontend rather
|
||||
* than silently dropping the response and continuing.
|
||||
*/
|
||||
pr_err_once("pvcalls: backend sent out-of-range req_id %u, disabling frontend\n",
|
||||
req_id);
|
||||
WRITE_ONCE(bedata->disabled, true);
|
||||
bedata->ring.rsp_cons++;
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
if (rsp->cmd == PVCALLS_POLL) {
|
||||
struct sock_mapping *map = (struct sock_mapping *)(uintptr_t)
|
||||
rsp->u.poll.id;
|
||||
@@ -217,7 +252,7 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more);
|
||||
if (more)
|
||||
if (more && !READ_ONCE(bedata->disabled))
|
||||
goto again;
|
||||
if (done)
|
||||
wake_up(&bedata->inflight_req);
|
||||
@@ -330,8 +365,11 @@ int pvcalls_front_socket(struct socket *sock)
|
||||
if (notify)
|
||||
notify_remote_via_irq(bedata->irq);
|
||||
|
||||
wait_event(bedata->inflight_req,
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
|
||||
ret = pvcalls_front_wait_rsp(bedata, req_id);
|
||||
if (ret) {
|
||||
pvcalls_exit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read req_id, then the content */
|
||||
smp_rmb();
|
||||
@@ -477,8 +515,11 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
|
||||
if (notify)
|
||||
notify_remote_via_irq(bedata->irq);
|
||||
|
||||
wait_event(bedata->inflight_req,
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
|
||||
ret = pvcalls_front_wait_rsp(bedata, req_id);
|
||||
if (ret) {
|
||||
pvcalls_exit_sock(sock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read req_id, then the content */
|
||||
smp_rmb();
|
||||
@@ -711,8 +752,11 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
|
||||
if (notify)
|
||||
notify_remote_via_irq(bedata->irq);
|
||||
|
||||
wait_event(bedata->inflight_req,
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
|
||||
ret = pvcalls_front_wait_rsp(bedata, req_id);
|
||||
if (ret) {
|
||||
pvcalls_exit_sock(sock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read req_id, then the content */
|
||||
smp_rmb();
|
||||
@@ -761,8 +805,11 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
|
||||
if (notify)
|
||||
notify_remote_via_irq(bedata->irq);
|
||||
|
||||
wait_event(bedata->inflight_req,
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
|
||||
ret = pvcalls_front_wait_rsp(bedata, req_id);
|
||||
if (ret) {
|
||||
pvcalls_exit_sock(sock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read req_id, then the content */
|
||||
smp_rmb();
|
||||
@@ -820,6 +867,14 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock,
|
||||
}
|
||||
}
|
||||
|
||||
if (READ_ONCE(bedata->disabled)) {
|
||||
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
||||
(void *)&map->passive.flags);
|
||||
wake_up(&map->passive.inflight_accept_req);
|
||||
pvcalls_exit_sock(sock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
map2 = kzalloc_obj(*map2);
|
||||
if (map2 == NULL) {
|
||||
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
||||
@@ -880,10 +935,18 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock,
|
||||
}
|
||||
|
||||
if (wait_event_interruptible(bedata->inflight_req,
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) {
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
|
||||
READ_ONCE(bedata->disabled))) {
|
||||
pvcalls_exit_sock(sock);
|
||||
return -EINTR;
|
||||
}
|
||||
if (READ_ONCE(bedata->disabled)) {
|
||||
clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
|
||||
(void *)&map->passive.flags);
|
||||
wake_up(&map->passive.inflight_accept_req);
|
||||
pvcalls_exit_sock(sock);
|
||||
return -EIO;
|
||||
}
|
||||
/* read req_id, then the content */
|
||||
smp_rmb();
|
||||
|
||||
@@ -1054,7 +1117,8 @@ int pvcalls_front_release(struct socket *sock)
|
||||
notify_remote_via_irq(bedata->irq);
|
||||
|
||||
wait_event(bedata->inflight_req,
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
|
||||
READ_ONCE(bedata->rsp[req_id].req_id) == req_id ||
|
||||
READ_ONCE(bedata->disabled));
|
||||
|
||||
if (map->active_socket) {
|
||||
/*
|
||||
|
||||
@@ -445,8 +445,10 @@ static int grant_references(struct xen_front_pgdir_shbuf *buf)
|
||||
unsigned long frame;
|
||||
|
||||
cur_ref = gnttab_claim_grant_reference(&priv_gref_head);
|
||||
if (cur_ref < 0)
|
||||
return cur_ref;
|
||||
if (cur_ref < 0) {
|
||||
ret = cur_ref;
|
||||
goto out_free_refs;
|
||||
}
|
||||
|
||||
frame = xen_page_to_gfn(virt_to_page(buf->directory +
|
||||
PAGE_SIZE * i));
|
||||
@@ -457,11 +459,13 @@ static int grant_references(struct xen_front_pgdir_shbuf *buf)
|
||||
if (buf->ops->grant_refs_for_buffer) {
|
||||
ret = buf->ops->grant_refs_for_buffer(buf, &priv_gref_head, j);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_free_refs;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out_free_refs:
|
||||
gnttab_free_grant_references(priv_gref_head);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -417,6 +417,12 @@ static char **split_strings(char *strings, unsigned int len, unsigned int *num)
|
||||
{
|
||||
char *p, **ret;
|
||||
|
||||
if (len && strings[len - 1]) {
|
||||
pr_err_once("malformed XS_DIRECTORY reply\n");
|
||||
kfree(strings);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
/* Count the strings. */
|
||||
*num = count_strings(strings, len);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
/* OUT: There was no machine check data to fetch. */
|
||||
#define XEN_MC_NODATA 0x2
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
/* vIRQ injected to Dom0 */
|
||||
#define VIRQ_MCA VIRQ_ARCH_0
|
||||
|
||||
@@ -388,5 +388,5 @@ struct xen_mce_log {
|
||||
#define MCE_GET_LOG_LEN _IOR('M', 2, int)
|
||||
#define MCE_GETCLEAR_FLAGS _IOR('M', 3, int)
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* __XEN_PUBLIC_ARCH_X86_MCA_H__ */
|
||||
|
||||
@@ -337,7 +337,7 @@
|
||||
#define MMUEXT_MARK_SUPER 19
|
||||
#define MMUEXT_UNMARK_SUPER 20
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
struct mmuext_op {
|
||||
unsigned int cmd;
|
||||
union {
|
||||
@@ -415,7 +415,7 @@ DEFINE_GUEST_HANDLE_STRUCT(mmuext_op);
|
||||
|
||||
#define MAX_VMASST_TYPE 5
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
typedef uint16_t domid_t;
|
||||
|
||||
@@ -760,11 +760,11 @@ struct tmem_op {
|
||||
|
||||
DEFINE_GUEST_HANDLE(u64);
|
||||
|
||||
#else /* __ASSEMBLY__ */
|
||||
#else /* __ASSEMBLER__ */
|
||||
|
||||
/* In assembly code we cannot use C numeric constant suffixes. */
|
||||
#define mk_unsigned_long(x) x
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
#endif /* __XEN_PUBLIC_XEN_H__ */
|
||||
|
||||
Reference in New Issue
Block a user