WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
Xen

xen-devel

[Top] [All Lists]

[Xen-devel] [PATCH] xenoprof fixes: active_domains races & cleanup

To: Keir Fraser <Keir.Fraser@xxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH] xenoprof fixes: active_domains races & cleanup
From: Markus Armbruster <armbru@xxxxxxxxxx>
Date: 2006年5月16日 13:48:37 +0200
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: 2006年5月16日 04:49:01 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <fbc913458dbed5f4e8eff549b6957d3f@xxxxxxxxxxxx> (Keir Fraser's message of "2006年5月16日 10:48:03 +0100")
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <87hd3r2qst.fsf@xxxxxxxxxxxxxxxxx> <878xp32qqf.fsf@xxxxxxxxxxxxxxxxx> <87ac9j19b1.fsf@xxxxxxxxxxxxxxxxx> <dce0de02687f69be8fac12d6bcabbfbc@xxxxxxxxxxxx> <87y7x2xpwk.fsf@xxxxxxxxxxxxxxxxx> <fbc913458dbed5f4e8eff549b6957d3f@xxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.4 (gnu/linux)
The active_domains code has race conditions:
* oprofile_set_active() calls set_active() method without holding
 start_sem. This is clearly wrong, as xenoprof_set_active() makes
 several hypercalls. oprofile_start(), for instance, could run in
 the middle of xenoprof_set_active().
* adomain_write(), adomain_read() and xenoprof_set_active() access
 global active_domains[] and adomains without synchronization. I
 went for a simple, obvious fix and created another mutex. Instead,
 one could move the shared data into oprof.c and protect it with
 start_sem, but that's more invasive.
Also clean up the code dealing with /dev/oprofile/active_domains:
* Use parameters instead of global variables to pass domain ids
 around. Give those globals internal linkage.
* Allocate buffers dynamically to conserve stack space.
* Treat writes with size zero exactly like a write containing no
 domain id. Before, zero-sized write was ignored, which is not the
 same.
* Parse domain ids as unsigned numbers. Before, the first one was
 parsed as signed number.
 Because ispunct()-punctuation is ignored between domain ids, signs
 are still silently ignored except for the first number. Hmm.
* Make parser accept whitespace as domain separator, because that's
 what you get when reading the file.
* EINVAL on domain ids overflowing domid_t. Before, they were
 silently truncated.
* EINVAL on too many domain ids. Before, the excess ones were
 silently ignored.
* Reset active domains on failure halfway through setting them.
* Fix potential buffer overflow in adomain_read(). Couldn't really
 happen because buffer was sufficient for current value of
 MAX_OPROF_DOMAINS.
Signed-off-by: Markus Armbruster <armbru@xxxxxxxxxx>
diff -x '*~' -rup linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c 
linux-2.6.16.13-xen.patched-4/arch/i386/oprofile/xenoprof.c
--- linux-2.6.16.13-xen.patched-1/arch/i386/oprofile/xenoprof.c 2006年05月15日 
10:30:49.000000000 +0200
+++ linux-2.6.16.13-xen.patched-4/arch/i386/oprofile/xenoprof.c 2006年05月15日 
10:31:23.000000000 +0200
@@ -289,9 +289,13 @@ static int xenoprof_set_active(int * act
 
 for (i=0; i<adomains; i++) {
 domid = active_domains[i];
+ if (domid != active_domains[i]) {
+ ret = -EINVAL;
+ goto out;
+ }
 ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
 if (ret)
- return (ret);
+ goto out;
 if (active_domains[i] == 0)
 set_dom0 = 1;
 }
@@ -300,8 +304,11 @@ static int xenoprof_set_active(int * act
 domid = 0;
 ret = HYPERVISOR_xenoprof_op(XENOPROF_set_active, &domid);
 }
- 
- active_defined = 1;
+
+out:
+ if (ret)
+ HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
+ active_defined = !ret;
 return ret;
 }
 
diff -x '*~' -rup linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.c 
linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprof.c
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.c 2006年05月15日 
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprof.c 2006年05月15日 
10:31:44.000000000 +0200
@@ -37,15 +37,17 @@ static DECLARE_MUTEX(start_sem);
 */
 static int timer = 0;
 
-extern unsigned int adomains;
-extern int active_domains[MAX_OPROF_DOMAINS];
-
-int oprofile_set_active(void)
+int oprofile_set_active(int active_domains[], unsigned int adomains)
 {
- if (oprofile_ops.set_active)
- return oprofile_ops.set_active(active_domains, adomains);
+ int err;
+
+ if (!oprofile_ops.set_active)
+ return -EINVAL;
 
- return -EINVAL;
+ down(&start_sem);
+ err = oprofile_ops.set_active(active_domains, adomains);
+ up(&start_sem);
+ return err;
 }
 
 int oprofile_setup(void)
diff -x '*~' -rup linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.h 
linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprof.h
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprof.h 2006年05月15日 
10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprof.h 2006年05月16日 
13:32:42.000000000 +0200
@@ -36,6 +36,6 @@ void oprofile_timer_init(struct oprofile
 
 int oprofile_set_backtrace(unsigned long depth);
 
-int oprofile_set_active(void);
+int oprofile_set_active(int active_domains[], unsigned int adomains);
 
 #endif /* OPROF_H */
diff -x '*~' -rup 
linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c 
linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprofile_files.c
--- linux-2.6.16.13-xen.patched-1/drivers/oprofile/oprofile_files.c 
2006年05月15日 10:28:11.000000000 +0200
+++ linux-2.6.16.13-xen.patched-4/drivers/oprofile/oprofile_files.c 
2006年05月16日 13:42:58.000000000 +0200
@@ -126,63 +126,92 @@ static struct file_operations dump_fops 
 
 #define TMPBUFSIZE 512
 
-unsigned int adomains = 0;
-long active_domains[MAX_OPROF_DOMAINS];
+static unsigned int adomains = 0;
+static int active_domains[MAX_OPROF_DOMAINS + 1];
+static DEFINE_MUTEX(adom_mutex);
 
 static ssize_t adomain_write(struct file * file, char const __user * buf, 
 size_t count, loff_t * offset)
 {
- char tmpbuf[TMPBUFSIZE];
- char * startp = tmpbuf;
- char * endp = tmpbuf;
+ char *tmpbuf;
+ char *startp, *endp;
 int i;
 unsigned long val;
+ ssize_t retval = count;
 
 if (*offset)
 return -EINVAL; 
- if (!count)
- return 0;
 if (count > TMPBUFSIZE - 1)
 return -EINVAL;
 
- memset(tmpbuf, 0x0, TMPBUFSIZE);
+ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
+ return -ENOMEM;
 
- if (copy_from_user(tmpbuf, buf, count))
+ if (copy_from_user(tmpbuf, buf, count)) {
+ kfree(tmpbuf);
 return -EFAULT;
- 
- for (i = 0; i < MAX_OPROF_DOMAINS; i++)
- active_domains[i] = -1;
- adomains = 0;
+ }
+ tmpbuf[count] = 0;
 
- while (1) {
- val = simple_strtol(startp, &endp, 0);
+ mutex_lock(&adom_mutex);
+
+ startp = tmpbuf;
+ /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
+ for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
+ val = simple_strtoul(startp, &endp, 0);
 if (endp == startp)
 break;
- while (ispunct(*endp))
+ while (ispunct(*endp) || isspace(*endp))
 endp++;
- active_domains[adomains++] = val;
- if (adomains >= MAX_OPROF_DOMAINS)
- break;
+ active_domains[i] = val;
+ if (active_domains[i] != val)
+ /* Overflow, force error below */
+ i = MAX_OPROF_DOMAINS + 1;
 startp = endp;
 }
- if (oprofile_set_active())
- return -EINVAL; 
- return count;
+ /* Force error on trailing junk */
+ adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
+
+ kfree(tmpbuf);
+
+ if (adomains > MAX_OPROF_DOMAINS
+ || oprofile_set_active(active_domains, adomains)) {
+ adomains = 0;
+ retval = -EINVAL;
+ }
+
+ mutex_unlock(&adom_mutex);
+ return retval;
 }
 
 static ssize_t adomain_read(struct file * file, char __user * buf, 
 size_t count, loff_t * offset)
 {
- char tmpbuf[TMPBUFSIZE];
- size_t len = 0;
+ char * tmpbuf;
+ size_t len;
 int i;
- /* This is all screwed up if we run out of space */
- for (i = 0; i < adomains; i++) 
- len += snprintf(tmpbuf + len, TMPBUFSIZE - len, 
- "%u ", (unsigned int)active_domains[i]);
- len += snprintf(tmpbuf + len, TMPBUFSIZE - len, "\n");
- return simple_read_from_buffer((void __user *)buf, count, 
- offset, tmpbuf, len);
+ ssize_t retval;
+
+ if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
+ return -ENOMEM;
+
+ mutex_lock(&adom_mutex);
+
+ len = 0;
+ for (i = 0; i < adomains; i++)
+ len += snprintf(tmpbuf + len,
+ len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
+ "%u ", active_domains[i]);
+ WARN_ON(len > TMPBUFSIZE);
+ if (len != 0 && len <= TMPBUFSIZE)
+ tmpbuf[len-1] = '\n';
+
+ mutex_unlock(&adom_mutex);
+
+ retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
+
+ kfree(tmpbuf);
+ return retval;
 }
 
 
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
<Prev in Thread] Current Thread [Next in Thread>
Previous by Date: Re: [Xen-devel] Re: [PATCH 2/3] xenoprof fixes: active_domains races , Markus Armbruster
Next by Date: Re: [Xen-devel] Re: [PATCH]: kexec: framework and i386 (Take VIII) , Keir Fraser
Previous by Thread: Re: [Xen-devel] Re: [PATCH 2/3] xenoprof fixes: active_domains races , Markus Armbruster
Next by Thread: Re: [Xen-devel] [PATCH 2/3] xenoprof fixes: active_domains races , Chris Wright
Indexes: [Date] [Thread] [Top] [All Lists]

Copyright ©, Citrix Systems Inc. All rights reserved. Legal and Privacy
Citrix This site is hosted by Citrix

AltStyle によって変換されたページ (->オリジナル) /