Commit 222229974824a4f30b417531cdc9b5b869d6a6b7

Authored by Daniel Borkmann
Committed by David S. Miller
1 parent 1e55817463

net: sctp: add build check for sctp_sf_eat_sack_6_2/jsctp_sf_eat_sack

In order to avoid any future surprises of kernel panics due to jprobes
function mismatches (as e.g. fixed in 4cb9d6eaf85ecd: sctp: jsctp_sf_eat_sack:
fix jprobes function signature mismatch), we should check both function
types during build and scream loudly if they do not match. __same_type
resolves to __builtin_types_compatible_p, which is 1 in case both types
are the same and 0 otherwise, qualifiers are ignored. Tested by myself.

Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 7 additions and 0 deletions Inline Diff

1 /* 1 /*
2 * sctp_probe - Observe the SCTP flow with kprobes. 2 * sctp_probe - Observe the SCTP flow with kprobes.
3 * 3 *
4 * The idea for this came from Werner Almesberger's umlsim 4 * The idea for this came from Werner Almesberger's umlsim
5 * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org> 5 * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
6 * 6 *
7 * Modified for SCTP from Stephen Hemminger's code 7 * Modified for SCTP from Stephen Hemminger's code
8 * Copyright (C) 2010, Wei Yongjun <yjwei@cn.fujitsu.com> 8 * Copyright (C) 2010, Wei Yongjun <yjwei@cn.fujitsu.com>
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or 12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. 13 * (at your option) any later version.
14 * 14 *
15 * This program is distributed in the hope that it will be useful, 15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details. 18 * GNU General Public License for more details.
19 * 19 *
20 * You should have received a copy of the GNU General Public License 20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software 21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */ 23 */
24 24
25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26 26
27 #include <linux/kernel.h> 27 #include <linux/kernel.h>
28 #include <linux/kprobes.h> 28 #include <linux/kprobes.h>
29 #include <linux/socket.h> 29 #include <linux/socket.h>
30 #include <linux/sctp.h> 30 #include <linux/sctp.h>
31 #include <linux/proc_fs.h> 31 #include <linux/proc_fs.h>
32 #include <linux/vmalloc.h> 32 #include <linux/vmalloc.h>
33 #include <linux/module.h> 33 #include <linux/module.h>
34 #include <linux/kfifo.h> 34 #include <linux/kfifo.h>
35 #include <linux/time.h> 35 #include <linux/time.h>
36 #include <net/net_namespace.h> 36 #include <net/net_namespace.h>
37 37
38 #include <net/sctp/sctp.h> 38 #include <net/sctp/sctp.h>
39 #include <net/sctp/sm.h> 39 #include <net/sctp/sm.h>
40 40
41 MODULE_AUTHOR("Wei Yongjun <yjwei@cn.fujitsu.com>"); 41 MODULE_AUTHOR("Wei Yongjun <yjwei@cn.fujitsu.com>");
42 MODULE_DESCRIPTION("SCTP snooper"); 42 MODULE_DESCRIPTION("SCTP snooper");
43 MODULE_LICENSE("GPL"); 43 MODULE_LICENSE("GPL");
44 44
45 static int port __read_mostly = 0; 45 static int port __read_mostly = 0;
46 MODULE_PARM_DESC(port, "Port to match (0=all)"); 46 MODULE_PARM_DESC(port, "Port to match (0=all)");
47 module_param(port, int, 0); 47 module_param(port, int, 0);
48 48
49 static int bufsize __read_mostly = 64 * 1024; 49 static int bufsize __read_mostly = 64 * 1024;
50 MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)"); 50 MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
51 module_param(bufsize, int, 0); 51 module_param(bufsize, int, 0);
52 52
53 static int full __read_mostly = 1; 53 static int full __read_mostly = 1;
54 MODULE_PARM_DESC(full, "Full log (1=every ack packet received, 0=only cwnd changes)"); 54 MODULE_PARM_DESC(full, "Full log (1=every ack packet received, 0=only cwnd changes)");
55 module_param(full, int, 0); 55 module_param(full, int, 0);
56 56
57 static const char procname[] = "sctpprobe"; 57 static const char procname[] = "sctpprobe";
58 58
59 static struct { 59 static struct {
60 struct kfifo fifo; 60 struct kfifo fifo;
61 spinlock_t lock; 61 spinlock_t lock;
62 wait_queue_head_t wait; 62 wait_queue_head_t wait;
63 struct timespec tstart; 63 struct timespec tstart;
64 } sctpw; 64 } sctpw;
65 65
66 static void printl(const char *fmt, ...) 66 static void printl(const char *fmt, ...)
67 { 67 {
68 va_list args; 68 va_list args;
69 int len; 69 int len;
70 char tbuf[256]; 70 char tbuf[256];
71 71
72 va_start(args, fmt); 72 va_start(args, fmt);
73 len = vscnprintf(tbuf, sizeof(tbuf), fmt, args); 73 len = vscnprintf(tbuf, sizeof(tbuf), fmt, args);
74 va_end(args); 74 va_end(args);
75 75
76 kfifo_in_locked(&sctpw.fifo, tbuf, len, &sctpw.lock); 76 kfifo_in_locked(&sctpw.fifo, tbuf, len, &sctpw.lock);
77 wake_up(&sctpw.wait); 77 wake_up(&sctpw.wait);
78 } 78 }
79 79
80 static int sctpprobe_open(struct inode *inode, struct file *file) 80 static int sctpprobe_open(struct inode *inode, struct file *file)
81 { 81 {
82 kfifo_reset(&sctpw.fifo); 82 kfifo_reset(&sctpw.fifo);
83 getnstimeofday(&sctpw.tstart); 83 getnstimeofday(&sctpw.tstart);
84 84
85 return 0; 85 return 0;
86 } 86 }
87 87
88 static ssize_t sctpprobe_read(struct file *file, char __user *buf, 88 static ssize_t sctpprobe_read(struct file *file, char __user *buf,
89 size_t len, loff_t *ppos) 89 size_t len, loff_t *ppos)
90 { 90 {
91 int error = 0, cnt = 0; 91 int error = 0, cnt = 0;
92 unsigned char *tbuf; 92 unsigned char *tbuf;
93 93
94 if (!buf) 94 if (!buf)
95 return -EINVAL; 95 return -EINVAL;
96 96
97 if (len == 0) 97 if (len == 0)
98 return 0; 98 return 0;
99 99
100 tbuf = vmalloc(len); 100 tbuf = vmalloc(len);
101 if (!tbuf) 101 if (!tbuf)
102 return -ENOMEM; 102 return -ENOMEM;
103 103
104 error = wait_event_interruptible(sctpw.wait, 104 error = wait_event_interruptible(sctpw.wait,
105 kfifo_len(&sctpw.fifo) != 0); 105 kfifo_len(&sctpw.fifo) != 0);
106 if (error) 106 if (error)
107 goto out_free; 107 goto out_free;
108 108
109 cnt = kfifo_out_locked(&sctpw.fifo, tbuf, len, &sctpw.lock); 109 cnt = kfifo_out_locked(&sctpw.fifo, tbuf, len, &sctpw.lock);
110 error = copy_to_user(buf, tbuf, cnt) ? -EFAULT : 0; 110 error = copy_to_user(buf, tbuf, cnt) ? -EFAULT : 0;
111 111
112 out_free: 112 out_free:
113 vfree(tbuf); 113 vfree(tbuf);
114 114
115 return error ? error : cnt; 115 return error ? error : cnt;
116 } 116 }
117 117
118 static const struct file_operations sctpprobe_fops = { 118 static const struct file_operations sctpprobe_fops = {
119 .owner = THIS_MODULE, 119 .owner = THIS_MODULE,
120 .open = sctpprobe_open, 120 .open = sctpprobe_open,
121 .read = sctpprobe_read, 121 .read = sctpprobe_read,
122 .llseek = noop_llseek, 122 .llseek = noop_llseek,
123 }; 123 };
124 124
125 static sctp_disposition_t jsctp_sf_eat_sack(struct net *net, 125 static sctp_disposition_t jsctp_sf_eat_sack(struct net *net,
126 const struct sctp_endpoint *ep, 126 const struct sctp_endpoint *ep,
127 const struct sctp_association *asoc, 127 const struct sctp_association *asoc,
128 const sctp_subtype_t type, 128 const sctp_subtype_t type,
129 void *arg, 129 void *arg,
130 sctp_cmd_seq_t *commands) 130 sctp_cmd_seq_t *commands)
131 { 131 {
132 struct sctp_transport *sp; 132 struct sctp_transport *sp;
133 static __u32 lcwnd = 0; 133 static __u32 lcwnd = 0;
134 struct timespec now; 134 struct timespec now;
135 135
136 sp = asoc->peer.primary_path; 136 sp = asoc->peer.primary_path;
137 137
138 if ((full || sp->cwnd != lcwnd) && 138 if ((full || sp->cwnd != lcwnd) &&
139 (!port || asoc->peer.port == port || 139 (!port || asoc->peer.port == port ||
140 ep->base.bind_addr.port == port)) { 140 ep->base.bind_addr.port == port)) {
141 lcwnd = sp->cwnd; 141 lcwnd = sp->cwnd;
142 142
143 getnstimeofday(&now); 143 getnstimeofday(&now);
144 now = timespec_sub(now, sctpw.tstart); 144 now = timespec_sub(now, sctpw.tstart);
145 145
146 printl("%lu.%06lu ", (unsigned long) now.tv_sec, 146 printl("%lu.%06lu ", (unsigned long) now.tv_sec,
147 (unsigned long) now.tv_nsec / NSEC_PER_USEC); 147 (unsigned long) now.tv_nsec / NSEC_PER_USEC);
148 148
149 printl("%p %5d %5d %5d %8d %5d ", asoc, 149 printl("%p %5d %5d %5d %8d %5d ", asoc,
150 ep->base.bind_addr.port, asoc->peer.port, 150 ep->base.bind_addr.port, asoc->peer.port,
151 asoc->pathmtu, asoc->peer.rwnd, asoc->unack_data); 151 asoc->pathmtu, asoc->peer.rwnd, asoc->unack_data);
152 152
153 list_for_each_entry(sp, &asoc->peer.transport_addr_list, 153 list_for_each_entry(sp, &asoc->peer.transport_addr_list,
154 transports) { 154 transports) {
155 if (sp == asoc->peer.primary_path) 155 if (sp == asoc->peer.primary_path)
156 printl("*"); 156 printl("*");
157 157
158 if (sp->ipaddr.sa.sa_family == AF_INET) 158 if (sp->ipaddr.sa.sa_family == AF_INET)
159 printl("%pI4 ", &sp->ipaddr.v4.sin_addr); 159 printl("%pI4 ", &sp->ipaddr.v4.sin_addr);
160 else 160 else
161 printl("%pI6 ", &sp->ipaddr.v6.sin6_addr); 161 printl("%pI6 ", &sp->ipaddr.v6.sin6_addr);
162 162
163 printl("%2u %8u %8u %8u %8u %8u ", 163 printl("%2u %8u %8u %8u %8u %8u ",
164 sp->state, sp->cwnd, sp->ssthresh, 164 sp->state, sp->cwnd, sp->ssthresh,
165 sp->flight_size, sp->partial_bytes_acked, 165 sp->flight_size, sp->partial_bytes_acked,
166 sp->pathmtu); 166 sp->pathmtu);
167 } 167 }
168 printl("\n"); 168 printl("\n");
169 } 169 }
170 170
171 jprobe_return(); 171 jprobe_return();
172 return 0; 172 return 0;
173 } 173 }
174 174
175 static struct jprobe sctp_recv_probe = { 175 static struct jprobe sctp_recv_probe = {
176 .kp = { 176 .kp = {
177 .symbol_name = "sctp_sf_eat_sack_6_2", 177 .symbol_name = "sctp_sf_eat_sack_6_2",
178 }, 178 },
179 .entry = jsctp_sf_eat_sack, 179 .entry = jsctp_sf_eat_sack,
180 }; 180 };
181 181
182 static __init int sctpprobe_init(void) 182 static __init int sctpprobe_init(void)
183 { 183 {
184 int ret = -ENOMEM; 184 int ret = -ENOMEM;
185 185
186 /* Warning: if the function signature of sctp_sf_eat_sack_6_2,
187 * has been changed, you also have to change the signature of
188 * jsctp_sf_eat_sack, otherwise you end up right here!
189 */
190 BUILD_BUG_ON(__same_type(sctp_sf_eat_sack_6_2,
191 jsctp_sf_eat_sack) == 0);
192
186 init_waitqueue_head(&sctpw.wait); 193 init_waitqueue_head(&sctpw.wait);
187 spin_lock_init(&sctpw.lock); 194 spin_lock_init(&sctpw.lock);
188 if (kfifo_alloc(&sctpw.fifo, bufsize, GFP_KERNEL)) 195 if (kfifo_alloc(&sctpw.fifo, bufsize, GFP_KERNEL))
189 return ret; 196 return ret;
190 197
191 if (!proc_net_fops_create(&init_net, procname, S_IRUSR, 198 if (!proc_net_fops_create(&init_net, procname, S_IRUSR,
192 &sctpprobe_fops)) 199 &sctpprobe_fops))
193 goto free_kfifo; 200 goto free_kfifo;
194 201
195 ret = register_jprobe(&sctp_recv_probe); 202 ret = register_jprobe(&sctp_recv_probe);
196 if (ret) 203 if (ret)
197 goto remove_proc; 204 goto remove_proc;
198 205
199 pr_info("probe registered (port=%d)\n", port); 206 pr_info("probe registered (port=%d)\n", port);
200 207
201 return 0; 208 return 0;
202 209
203 remove_proc: 210 remove_proc:
204 proc_net_remove(&init_net, procname); 211 proc_net_remove(&init_net, procname);
205 free_kfifo: 212 free_kfifo:
206 kfifo_free(&sctpw.fifo); 213 kfifo_free(&sctpw.fifo);
207 return ret; 214 return ret;
208 } 215 }
209 216
210 static __exit void sctpprobe_exit(void) 217 static __exit void sctpprobe_exit(void)
211 { 218 {
212 kfifo_free(&sctpw.fifo); 219 kfifo_free(&sctpw.fifo);
213 proc_net_remove(&init_net, procname); 220 proc_net_remove(&init_net, procname);
214 unregister_jprobe(&sctp_recv_probe); 221 unregister_jprobe(&sctp_recv_probe);
215 } 222 }
216 223
217 module_init(sctpprobe_init); 224 module_init(sctpprobe_init);
218 module_exit(sctpprobe_exit); 225 module_exit(sctpprobe_exit);
219 226