fc71df9
From: Jan Beulich <jbeulich@suse.com>
fc71df9
Subject: xenoprof: limit consumption of shared buffer data
fc71df9
fc71df9
Since a shared buffer can be written to by the guest, we may only read
fc71df9
the head and tail pointers from there (all other fields should only ever
fc71df9
be written to). Furthermore, for any particular operation the two values
fc71df9
must be read exactly once, with both checks and consumption happening
fc71df9
with the thus read values. (The backtrace related xenoprof_buf_space()
fc71df9
use in xenoprof_log_event() is an exception: The values used there get
fc71df9
re-checked by every subsequent xenoprof_add_sample().)
fc71df9
fc71df9
Since that code needed touching, also fix the double increment of the
fc71df9
lost samples count in case the backtrace related xenoprof_add_sample()
fc71df9
invocation in xenoprof_log_event() fails.
fc71df9
fc71df9
Where code is being touched anyway, add const as appropriate, but take
fc71df9
the opportunity to entirely drop the now unused domain parameter of
fc71df9
xenoprof_buf_space().
fc71df9
fc71df9
This is part of XSA-313.
fc71df9
fc71df9
Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
fc71df9
Signed-off-by: Jan Beulich <jbeulich@suse.com>
fc71df9
Reviewed-by: George Dunlap <george.dunlap@citrix.com>
fc71df9
Reviewed-by: Wei Liu <wl@xen.org>
fc71df9
fc71df9
--- a/xen/common/xenoprof.c
fc71df9
+++ b/xen/common/xenoprof.c
fc71df9
@@ -479,25 +479,22 @@ static int add_passive_list(XEN_GUEST_HA
fc71df9
 
fc71df9
 
fc71df9
 /* Get space in the buffer */
fc71df9
-static int xenoprof_buf_space(struct domain *d, xenoprof_buf_t * buf, int size)
fc71df9
+static int xenoprof_buf_space(int head, int tail, int size)
fc71df9
 {
fc71df9
-    int head, tail;
fc71df9
-
fc71df9
-    head = xenoprof_buf(d, buf, event_head);
fc71df9
-    tail = xenoprof_buf(d, buf, event_tail);
fc71df9
-
fc71df9
     return ((tail > head) ? 0 : size) + tail - head - 1;
fc71df9
 }
fc71df9
 
fc71df9
 /* Check for space and add a sample. Return 1 if successful, 0 otherwise. */
fc71df9
-static int xenoprof_add_sample(struct domain *d, xenoprof_buf_t *buf,
fc71df9
+static int xenoprof_add_sample(const struct domain *d,
fc71df9
+                               const struct xenoprof_vcpu *v,
fc71df9
                                uint64_t eip, int mode, int event)
fc71df9
 {
fc71df9
+    xenoprof_buf_t *buf = v->buffer;
fc71df9
     int head, tail, size;
fc71df9
 
fc71df9
     head = xenoprof_buf(d, buf, event_head);
fc71df9
     tail = xenoprof_buf(d, buf, event_tail);
fc71df9
-    size = xenoprof_buf(d, buf, event_size);
fc71df9
+    size = v->event_size;
fc71df9
     
fc71df9
     /* make sure indexes in shared buffer are sane */
fc71df9
     if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) )
fc71df9
@@ -506,7 +503,7 @@ static int xenoprof_add_sample(struct do
fc71df9
         return 0;
fc71df9
     }
fc71df9
 
fc71df9
-    if ( xenoprof_buf_space(d, buf, size) > 0 )
fc71df9
+    if ( xenoprof_buf_space(head, tail, size) > 0 )
fc71df9
     {
fc71df9
         xenoprof_buf(d, buf, event_log[head].eip) = eip;
fc71df9
         xenoprof_buf(d, buf, event_log[head].mode) = mode;
fc71df9
@@ -530,7 +527,6 @@ static int xenoprof_add_sample(struct do
fc71df9
 int xenoprof_add_trace(struct vcpu *vcpu, uint64_t pc, int mode)
fc71df9
 {
fc71df9
     struct domain *d = vcpu->domain;
fc71df9
-    xenoprof_buf_t *buf = d->xenoprof->vcpu[vcpu->vcpu_id].buffer;
fc71df9
 
fc71df9
     /* Do not accidentally write an escape code due to a broken frame. */
fc71df9
     if ( pc == XENOPROF_ESCAPE_CODE )
fc71df9
@@ -539,7 +535,8 @@ int xenoprof_add_trace(struct vcpu *vcpu
fc71df9
         return 0;
fc71df9
     }
fc71df9
 
fc71df9
-    return xenoprof_add_sample(d, buf, pc, mode, 0);
fc71df9
+    return xenoprof_add_sample(d, &d->xenoprof->vcpu[vcpu->vcpu_id],
fc71df9
+                               pc, mode, 0);
fc71df9
 }
fc71df9
 
fc71df9
 void xenoprof_log_event(struct vcpu *vcpu, const struct cpu_user_regs *regs,
fc71df9
@@ -570,17 +567,22 @@ void xenoprof_log_event(struct vcpu *vcp
fc71df9
     /* Provide backtrace if requested. */
fc71df9
     if ( backtrace_depth > 0 )
fc71df9
     {
fc71df9
-        if ( (xenoprof_buf_space(d, buf, v->event_size) < 2) ||
fc71df9
-             !xenoprof_add_sample(d, buf, XENOPROF_ESCAPE_CODE, mode, 
fc71df9
-                                  XENOPROF_TRACE_BEGIN) )
fc71df9
+        if ( xenoprof_buf_space(xenoprof_buf(d, buf, event_head),
fc71df9
+                                xenoprof_buf(d, buf, event_tail),
fc71df9
+                                v->event_size) < 2 )
fc71df9
         {
fc71df9
             xenoprof_buf(d, buf, lost_samples)++;
fc71df9
             lost_samples++;
fc71df9
             return;
fc71df9
         }
fc71df9
+
fc71df9
+        /* xenoprof_add_sample() will increment lost_samples on failure */
fc71df9
+        if ( !xenoprof_add_sample(d, v, XENOPROF_ESCAPE_CODE, mode,
fc71df9
+                                  XENOPROF_TRACE_BEGIN) )
fc71df9
+            return;
fc71df9
     }
fc71df9
 
fc71df9
-    if ( xenoprof_add_sample(d, buf, pc, mode, event) )
fc71df9
+    if ( xenoprof_add_sample(d, v, pc, mode, event) )
fc71df9
     {
fc71df9
         if ( is_active(vcpu->domain) )
fc71df9
             active_samples++;
fc71df9
--- a/xen/include/xen/xenoprof.h
fc71df9
+++ b/xen/include/xen/xenoprof.h
fc71df9
@@ -61,12 +61,12 @@ struct xenoprof {
fc71df9
 
fc71df9
 #ifndef CONFIG_COMPAT
fc71df9
 #define XENOPROF_COMPAT(x) 0
fc71df9
-#define xenoprof_buf(d, b, field) ((b)->field)
fc71df9
+#define xenoprof_buf(d, b, field) ACCESS_ONCE((b)->field)
fc71df9
 #else
fc71df9
 #define XENOPROF_COMPAT(x) ((x)->is_compat)
fc71df9
-#define xenoprof_buf(d, b, field) (*(!(d)->xenoprof->is_compat ? \
fc71df9
-                                       &(b)->native.field : \
fc71df9
-                                       &(b)->compat.field))
fc71df9
+#define xenoprof_buf(d, b, field) ACCESS_ONCE(*(!(d)->xenoprof->is_compat \
fc71df9
+                                                ? &(b)->native.field \
fc71df9
+                                                : &(b)->compat.field))
fc71df9
 #endif
fc71df9
 
fc71df9
 struct domain;