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