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>
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  /**