(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
analyzer/
attr-malloc-CVE-2019-19078-usb-leak.c
       1  /* Adapted from linux 5.3.11: drivers/net/wireless/ath/ath10k/usb.c
       2     Reduced reproducer for CVE-2019-19078 (leak of struct urb).  */
       3  
       4  typedef unsigned char u8;
       5  typedef unsigned short u16;
       6  typedef _Bool bool;
       7  
       8  #define	ENOMEM		12
       9  #define	EINVAL		22
      10  
      11  /* The original file has this licence header.  */
      12  
      13  // SPDX-License-Identifier: ISC
      14  /*
      15   * Copyright (c) 2007-2011 Atheros Communications Inc.
      16   * Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc.
      17   * Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com>
      18   */
      19  
      20  /* Adapted from include/linux/compiler_attributes.h.  */
      21  #define __aligned(x)                    __attribute__((__aligned__(x)))
      22  #define __printf(a, b)                  __attribute__((__format__(printf, a, b)))
      23  
      24  /* Possible macro for the new attribute.  */
      25  #define __malloc(f)      __attribute__((malloc(f)));
      26  
      27  /* From include/linux/types.h.  */
      28  
      29  typedef unsigned int gfp_t;
      30  
      31  /* Not the real value, which is in include/linux/gfp.h.  */
      32  #define GFP_ATOMIC	32
      33  
      34  /* From include/linux/usb.h.  */
      35  
      36  struct urb;
      37  extern void usb_free_urb(struct urb *urb);
      38  extern struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
      39    __malloc(usb_free_urb);
      40  /* attribute added as part of testcase */
      41  
      42  extern int usb_submit_urb(/*struct urb *urb, */gfp_t mem_flags);
      43  extern void usb_unanchor_urb(struct urb *urb);
      44  
      45  /* From drivers/net/wireless/ath/ath10k/core.h.  */
      46  
      47  struct ath10k;
      48  
      49  struct ath10k {
      50  	/* [...many other fields removed...]  */
      51  
      52  	/* must be last */
      53  	u8 drv_priv[0] __aligned(sizeof(void *));
      54  };
      55  
      56  /* From drivers/net/wireless/ath/ath10k/debug.h.  */
      57  
      58  enum ath10k_debug_mask {
      59  	/* [...other values removed...]  */
      60  	ATH10K_DBG_USB_BULK	= 0x00080000,
      61  };
      62  
      63  extern unsigned int ath10k_debug_mask;
      64  
      65  __printf(3, 4) void __ath10k_dbg(struct ath10k *ar,
      66  				 enum ath10k_debug_mask mask,
      67  				 const char *fmt, ...);
      68  
      69  /* Simplified for now, to avoid pulling in tracepoint code.  */
      70  static inline
      71  bool trace_ath10k_log_dbg_enabled(void) { return 0; }
      72  
      73  #define ath10k_dbg(ar, dbg_mask, fmt, ...)			\
      74  do {								\
      75  	if ((ath10k_debug_mask & dbg_mask) ||			\
      76  	    trace_ath10k_log_dbg_enabled())			\
      77  		__ath10k_dbg(ar, dbg_mask, fmt, ##__VA_ARGS__); \
      78  } while (0)
      79  
      80  /* From drivers/net/wireless/ath/ath10k/hif.h.  */
      81  
      82  struct ath10k_hif_sg_item {
      83  	/* [...other fields removed...]  */
      84  	void *transfer_context; /* NULL = tx completion callback not called */
      85  };
      86  
      87  struct ath10k_hif_ops {
      88  	/* send a scatter-gather list to the target */
      89  	int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
      90  		     struct ath10k_hif_sg_item *items, int n_items);
      91  	/* [...other fields removed...]  */
      92  };
      93  
      94  /* From drivers/net/wireless/ath/ath10k/usb.h.  */
      95  
      96  /* tx/rx pipes for usb */
      97  enum ath10k_usb_pipe_id {
      98  	/* [...other values removed...]  */
      99  	ATH10K_USB_PIPE_MAX = 8
     100  };
     101  
     102  struct ath10k_usb_pipe {
     103  	/* [...all fields removed...]  */
     104  };
     105  
     106  /* usb device object */
     107  struct ath10k_usb {
     108  	/* [...other fields removed...]  */
     109  	struct ath10k_usb_pipe pipes[ATH10K_USB_PIPE_MAX];
     110  };
     111  
     112  /* usb urb object */
     113  struct ath10k_urb_context {
     114  	/* [...other fields removed...]  */
     115  	struct ath10k_usb_pipe *pipe;
     116  	struct sk_buff *skb;
     117  };
     118  
     119  static inline struct ath10k_usb *ath10k_usb_priv(struct ath10k *ar)
     120  {
     121  	return (struct ath10k_usb *)ar->drv_priv;
     122  }
     123  
     124  /* The source file.  */
     125  
     126  static void ath10k_usb_post_recv_transfers(struct ath10k *ar,
     127  					   struct ath10k_usb_pipe *recv_pipe);
     128  
     129  struct ath10k_urb_context *
     130  ath10k_usb_alloc_urb_from_pipe(struct ath10k_usb_pipe *pipe);
     131  
     132  void ath10k_usb_free_urb_to_pipe(struct ath10k_usb_pipe *pipe,
     133  				 struct ath10k_urb_context *urb_context);
     134  
     135  static int ath10k_usb_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
     136  				struct ath10k_hif_sg_item *items, int n_items)
     137  {
     138  	struct ath10k_usb *ar_usb = ath10k_usb_priv(ar);
     139  	struct ath10k_usb_pipe *pipe = &ar_usb->pipes[pipe_id];
     140  	struct ath10k_urb_context *urb_context;
     141  	struct sk_buff *skb;
     142  	struct urb *urb;
     143  	int ret, i;
     144  
     145  	for (i = 0; i < n_items; i++) {
     146  		urb_context = ath10k_usb_alloc_urb_from_pipe(pipe);
     147  		if (!urb_context) {
     148  			ret = -ENOMEM;
     149  			goto err;
     150  		}
     151  
     152  		skb = items[i].transfer_context;
     153  		urb_context->skb = skb;
     154  
     155  		urb = usb_alloc_urb(0, GFP_ATOMIC); /* { dg-message "allocated here" } */
     156  		if (!urb) {
     157  			ret = -ENOMEM;
     158  			goto err_free_urb_to_pipe;
     159  		}
     160  
     161  		/* TODO: these are disabled, otherwise we conservatively
     162  		   assume that they could free urb.  */
     163  #if 0
     164  		usb_fill_bulk_urb(urb,
     165  				  ar_usb->udev,
     166  				  pipe->usb_pipe_handle,
     167  				  skb->data,
     168  				  skb->len,
     169  				  ath10k_usb_transmit_complete, urb_context);
     170  		if (!(skb->len % pipe->max_packet_size)) {
     171  			/* hit a max packet boundary on this pipe */
     172  			urb->transfer_flags |= URB_ZERO_PACKET;
     173  		}
     174  
     175  		usb_anchor_urb(urb, &pipe->urb_submitted);
     176  #endif
     177  		/* TODO: initial argument disabled, otherwise we conservatively
     178  		   assume that it could free urb.  */
     179  		ret = usb_submit_urb(/*urb, */GFP_ATOMIC);
     180  		if (ret) { /* TODO: why doesn't it show this condition at default verbosity?  */
     181  			ath10k_dbg(ar, ATH10K_DBG_USB_BULK,
     182  				   "usb bulk transmit failed: %d\n", ret);
     183  
     184  			/* TODO: this is disabled, otherwise we conservatively
     185  			   assume that it could free urb.  */
     186  #if 0
     187  			usb_unanchor_urb(urb);
     188  #endif
     189  
     190  			ret = -EINVAL;
     191  			/* Leak of urb happens here.  */
     192  			goto err_free_urb_to_pipe;
     193  		}
     194  
     195  		usb_free_urb(urb); /* { dg-bogus "double-'usb_free_urb' of 'urb'" } */
     196  	}
     197  
     198  	return 0;
     199  
     200  err_free_urb_to_pipe:
     201  	ath10k_usb_free_urb_to_pipe(urb_context->pipe, urb_context);
     202  err:
     203  	return ret; /* { dg-warning "leak of 'urb'" } */
     204  }
     205  
     206  static const struct ath10k_hif_ops ath10k_usb_hif_ops = {
     207  	.tx_sg			= ath10k_usb_hif_tx_sg,
     208  };
     209  
     210  /* Simulate code to register the callback.  */
     211  extern void callback_registration (const void *);
     212  int ath10k_usb_probe(void)
     213  {
     214    callback_registration(&ath10k_usb_hif_ops);
     215  }
     216  
     217  
     218  /* The original source file ends with:
     219  MODULE_AUTHOR("Atheros Communications, Inc.");
     220  MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN USB devices");
     221  MODULE_LICENSE("Dual BSD/GPL");
     222  */