1  /* "The sco_sock_getsockopt_old function in net/bluetooth/sco.c in the
       2     Linux kernel before 2.6.39 does not initialize a certain structure,
       3     which allows local users to obtain potentially sensitive information
       4     from kernel stack memory via the SCO_CONNINFO option."
       5  
       6     Fixed e.g. by c4c896e1471aec3b004a693c689f60be3b17ac86 on linux-2.6.39.y
       7     in linux-stable.  */
       8  
       9  /* { dg-do compile } */
      10  /* { dg-options "-fanalyzer" } */
      11  /* { dg-require-effective-target analyzer } */
      12  /* { dg-skip-if "structure layout assumption not met" { default_packed } } */
      13  
      14  #include <string.h>
      15  
      16  typedef unsigned char __u8;
      17  typedef unsigned short __u16;
      18  
      19  #include "test-uaccess.h"
      20  
      21  /* Adapted from include/asm-generic/uaccess.h.  */
      22  
      23  #define get_user(x, ptr)					\
      24  ({								\
      25  	/* [...snip...] */					\
      26  	__get_user_fn(sizeof (*(ptr)), ptr, &(x));		\
      27  	/* [...snip...] */					\
      28  })
      29  
      30  static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
      31  {
      32  	size = copy_from_user(x, ptr, size);
      33  	return size ? -1 : size;
      34  }
      35  
      36  /* Adapted from include/linux/kernel.h.  */
      37  
      38  #define min_t(type, x, y) ({			\
      39  	type __min1 = (x);			\
      40  	type __min2 = (y);			\
      41  	__min1 < __min2 ? __min1: __min2; })
      42  
      43  /* Adapted from include/linux/net.h.  */
      44  
      45  struct socket {
      46  	/* [...snip...] */
      47  	struct sock		*sk;
      48  	/* [...snip...] */
      49  };
      50  
      51  /* Adapted from include/net/bluetooth/sco.h.  */
      52  
      53  struct sco_conninfo {
      54  	__u16 hci_handle;
      55  	__u8  dev_class[3]; /* { dg-message "padding after field 'dev_class' is uninitialized \\(1 byte\\)" } */
      56  };
      57  
      58  struct sco_conn {
      59  
      60  	struct hci_conn	*hcon;
      61  	/* [...snip...] */
      62  };
      63  
      64  #define sco_pi(sk) ((struct sco_pinfo *) sk)
      65  
      66  struct sco_pinfo {
      67  	/* [...snip...] */
      68  	struct sco_conn	*conn;
      69  };
      70  
      71  /* Adapted from include/net/bluetooth/hci_core.h.  */
      72  
      73  struct hci_conn {
      74  	/* [...snip...] */
      75  	__u16		handle;
      76  	/* [...snip...] */
      77  	__u8		dev_class[3];
      78  	/* [...snip...] */
      79  };
      80  
      81  /* Adapted from sco_sock_getsockopt_old in net/bluetooth/sco.c.  */
      82  
      83  static int sco_sock_getsockopt_old_broken(struct socket *sock, int optname, char __user *optval, int __user *optlen)
      84  {
      85  	struct sock *sk = sock->sk;
      86  	/* [...snip...] */
      87  	struct sco_conninfo cinfo; /* { dg-message "region created on stack here" "where" } */
      88  				   /* { dg-message "capacity: 6 bytes" "capacity" { target *-*-* } .-1 } */
      89  	/* Note: 40 bits of fields, padded to 48.  */
      90  
      91  	int len, err = 0;
      92  
      93  	/* [...snip...] */
      94  
      95  	if (get_user(len, optlen))
      96  		return -1;
      97  
      98  	/* [...snip...] */
      99  
     100  	/* case SCO_CONNINFO: */
     101  		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
     102  		memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
     103  
     104  		len = min_t(unsigned int, len, sizeof(cinfo));
     105  		if (copy_to_user(optval, (char *)&cinfo, len)) /* { dg-warning "potential exposure of sensitive information by copying uninitialized data from stack" "warning" { target *-*-* } } */
     106  			/* { dg-message "1 byte is uninitialized" "how much note" { target *-*-* } .-1 } */
     107  			err = -1;
     108  
     109  	/* [...snip...] */
     110  }
     111  
     112  static int sco_sock_getsockopt_fixed(struct socket *sock, int optname, char __user *optval, int __user *optlen)
     113  {
     114  	struct sock *sk = sock->sk;
     115  	/* [...snip...] */
     116  	struct sco_conninfo cinfo;
     117  	/* Note: 40 bits of fields, padded to 48.  */
     118  
     119  	int len, err = 0;
     120  
     121  	/* [...snip...] */
     122  
     123  	if (get_user(len, optlen))
     124  		return -1;
     125  
     126  	/* [...snip...] */
     127  
     128  	/* case SCO_CONNINFO: */
     129  		/* Infoleak fixed by this memset call.  */
     130  		memset(&cinfo, 0, sizeof(cinfo));
     131  		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
     132  		memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
     133  
     134  		len = min_t(unsigned int, len, sizeof(cinfo));
     135  		if (copy_to_user(optval, (char *)&cinfo, len)) /* { dg-bogus "exposure" } */
     136  			err = -1;
     137  
     138  	/* [...snip...] */
     139  }