debuggers.hg
changeset 21197:94cae4dfa25b
xentrace: Bounds checking and error handling
Check tbuf_size to make sure that it will fit on the t_info struct
allocated at boot. Also deal with allocation failures more
gracefully.
Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com>
Check tbuf_size to make sure that it will fit on the t_info struct
allocated at boot. Also deal with allocation failures more
gracefully.
Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Mon Apr 12 17:54:48 2010 +0100 (2010-04-12) |
parents | 78488a63bbc2 |
children | 9471200daee4 |
files | xen/common/trace.c |
line diff
1.1 --- a/xen/common/trace.c Mon Apr 12 17:51:56 2010 +0100 1.2 +++ b/xen/common/trace.c Mon Apr 12 17:54:48 2010 +0100 1.3 @@ -48,6 +48,9 @@ integer_param("tbuf_size", opt_tbuf_size 1.4 /* Pointers to the meta-data objects for all system trace buffers */ 1.5 static struct t_info *t_info; 1.6 #define T_INFO_PAGES 2 /* Size fixed at 2 pages for now. */ 1.7 +#define T_INFO_SIZE ((T_INFO_PAGES)*(PAGE_SIZE)) 1.8 +/* t_info.tbuf_size + list of mfn offsets + 1 to round up / sizeof uint32_t */ 1.9 +#define T_INFO_FIRST_OFFSET ((sizeof(int16_t) + NR_CPUS * sizeof(int16_t) + 1) / sizeof(uint32_t)) 1.10 static DEFINE_PER_CPU_READ_MOSTLY(struct t_buf *, t_bufs); 1.11 static DEFINE_PER_CPU_READ_MOSTLY(unsigned char *, t_data); 1.12 static DEFINE_PER_CPU_READ_MOSTLY(spinlock_t, t_lock); 1.13 @@ -72,6 +75,15 @@ static cpumask_t tb_cpu_mask = CPU_MASK_ 1.14 static u32 tb_event_mask = TRC_ALL; 1.15 1.16 /** 1.17 + * check_tbuf_size - check to make sure that the proposed size will fit 1.18 + * in the currently sized struct t_info. 1.19 + */ 1.20 +static inline int check_tbuf_size(int size) 1.21 +{ 1.22 + return (num_online_cpus() * size + T_INFO_FIRST_OFFSET) > (T_INFO_SIZE / sizeof(uint32_t)); 1.23 +} 1.24 + 1.25 +/** 1.26 * alloc_trace_bufs - performs initialization of the per-cpu trace buffers. 1.27 * 1.28 * This function is called at start of day in order to initialize the per-cpu 1.29 @@ -87,7 +99,9 @@ static int alloc_trace_bufs(void) 1.30 unsigned long nr_pages; 1.31 /* Start after a fixed-size array of NR_CPUS */ 1.32 uint32_t *t_info_mfn_list = (uint32_t *)t_info; 1.33 - int offset = (NR_CPUS * 2 + 1 + 1) / 4; 1.34 + int offset = T_INFO_FIRST_OFFSET; 1.35 + 1.36 + BUG_ON(check_tbuf_size(opt_tbuf_size)); 1.37 1.38 if ( opt_tbuf_size == 0 ) 1.39 return -EINVAL; 1.40 @@ -180,7 +194,8 @@ out_dealloc: 1.41 } 1.42 spin_unlock_irqrestore(&per_cpu(t_lock, cpu), flags); 1.43 } 1.44 - return -EINVAL; 1.45 + 1.46 + return -ENOMEM; 1.47 } 1.48 1.49 1.50 @@ -197,19 +212,35 @@ static int tb_set_size(int size) 1.51 * boot time or via control tools, but not by both. Once buffers 1.52 * are created they cannot be destroyed. 1.53 */ 1.54 - if ( (opt_tbuf_size != 0) || (size <= 0) ) 1.55 + int ret = 0; 1.56 + 1.57 + 1.58 + 1.59 + if ( (opt_tbuf_size != 0) ) 1.60 { 1.61 - gdprintk(XENLOG_INFO, "tb_set_size from %d to %d not implemented\n", 1.62 - opt_tbuf_size, size); 1.63 + if ( size != opt_tbuf_size ) 1.64 + gdprintk(XENLOG_INFO, "tb_set_size from %d to %d not implemented\n", 1.65 + opt_tbuf_size, size); 1.66 + return -EINVAL; 1.67 + } 1.68 + 1.69 + if ( size <= 0 ) 1.70 + return -EINVAL; 1.71 + 1.72 + if ( check_tbuf_size(size) ) 1.73 + { 1.74 + gdprintk(XENLOG_INFO, "tb size %d too large\n", size); 1.75 return -EINVAL; 1.76 } 1.77 1.78 opt_tbuf_size = size; 1.79 - if ( alloc_trace_bufs() != 0 ) 1.80 - return -EINVAL; 1.81 1.82 - printk("Xen trace buffers: initialized\n"); 1.83 - return 0; 1.84 + if ( (ret = alloc_trace_bufs()) == 0 ) 1.85 + printk("Xen trace buffers: initialized\n"); 1.86 + else 1.87 + opt_tbuf_size = 0; 1.88 + 1.89 + return ret; 1.90 } 1.91 1.92 int trace_will_trace_event(u32 event) 1.93 @@ -265,13 +296,18 @@ void __init init_trace_bufs(void) 1.94 share_xen_page_with_privileged_guests( 1.95 virt_to_page(t_info) + i, XENSHARE_writable); 1.96 1.97 - 1.98 - 1.99 if ( opt_tbuf_size == 0 ) 1.100 { 1.101 printk("Xen trace buffers: disabled\n"); 1.102 return; 1.103 } 1.104 + else if ( check_tbuf_size(opt_tbuf_size) ) 1.105 + { 1.106 + gdprintk(XENLOG_INFO, "Xen trace buffers: " 1.107 + "tb size %d too large, disabling\n", 1.108 + opt_tbuf_size); 1.109 + opt_tbuf_size = 0; 1.110 + } 1.111 1.112 if ( alloc_trace_bufs() == 0 ) 1.113 { 1.114 @@ -279,6 +315,13 @@ void __init init_trace_bufs(void) 1.115 wmb(); /* above must be visible before tb_init_done flag set */ 1.116 tb_init_done = 1; 1.117 } 1.118 + else 1.119 + { 1.120 + gdprintk(XENLOG_INFO, "Xen trace buffers: " 1.121 + "allocation size %d failed, disabling\n", 1.122 + opt_tbuf_size); 1.123 + opt_tbuf_size = 0; 1.124 + } 1.125 } 1.126 1.127 /**