[NETFILTER]: Fix another crash in ip_nat_pptp

The PPTP NAT helper calculates the offset at which the packet needs
to be mangled as difference between two pointers to the header. With
non-linear skbs however the pointers may point to two seperate buffers
on the stack and the calculation results in a wrong offset beeing
used.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Patrick McHardy and committed by
David S. Miller
03b9feca 15db3470

+27 -30
+27 -30
net/ipv4/netfilter/ip_nat_helper_pptp.c
··· 148 148 { 149 149 struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; 150 150 struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; 151 - 152 - u_int16_t msg, *cid = NULL, new_callid; 151 + u_int16_t msg, new_callid; 152 + unsigned int cid_off; 153 153 154 154 new_callid = htons(ct_pptp_info->pns_call_id); 155 155 156 156 switch (msg = ntohs(ctlh->messageType)) { 157 157 case PPTP_OUT_CALL_REQUEST: 158 - cid = &pptpReq->ocreq.callID; 158 + cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); 159 159 /* FIXME: ideally we would want to reserve a call ID 160 160 * here. current netfilter NAT core is not able to do 161 161 * this :( For now we use TCP source port. This breaks ··· 172 172 ct_pptp_info->pns_call_id = ntohs(new_callid); 173 173 break; 174 174 case PPTP_IN_CALL_REPLY: 175 - cid = &pptpReq->icreq.callID; 175 + cid_off = offsetof(union pptp_ctrl_union, icreq.callID); 176 176 break; 177 177 case PPTP_CALL_CLEAR_REQUEST: 178 - cid = &pptpReq->clrreq.callID; 178 + cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); 179 179 break; 180 180 default: 181 181 DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, ··· 197 197 198 198 /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass 199 199 * down to here */ 200 - 201 - IP_NF_ASSERT(cid); 202 - 203 200 DEBUGP("altering call id from 0x%04x to 0x%04x\n", 204 - ntohs(*cid), ntohs(new_callid)); 201 + ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_callid)); 205 202 206 203 /* mangle packet */ 207 204 if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 208 - (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 209 - sizeof(new_callid), 210 - (char *)&new_callid, 211 - sizeof(new_callid)) == 0) 205 + cid_off + sizeof(struct pptp_pkt_hdr) + 206 + sizeof(struct PptpControlHeader), 207 + sizeof(new_callid), (char *)&new_callid, 208 + sizeof(new_callid)) == 0) 212 209 return NF_DROP; 213 210 214 211 return NF_ACCEPT; ··· 296 299 union pptp_ctrl_union *pptpReq) 297 300 { 298 301 struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; 299 - u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; 302 + u_int16_t msg, new_cid = 0, new_pcid; 303 + unsigned int pcid_off, cid_off = 0; 300 304 301 305 int ret = NF_ACCEPT, rv; 302 306 ··· 305 307 306 308 switch (msg = ntohs(ctlh->messageType)) { 307 309 case PPTP_OUT_CALL_REPLY: 308 - pcid = &pptpReq->ocack.peersCallID; 309 - cid = &pptpReq->ocack.callID; 310 + pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); 311 + cid_off = offsetof(union pptp_ctrl_union, ocack.callID); 310 312 break; 311 313 case PPTP_IN_CALL_CONNECT: 312 - pcid = &pptpReq->iccon.peersCallID; 314 + pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); 313 315 break; 314 316 case PPTP_IN_CALL_REQUEST: 315 317 /* only need to nat in case PAC is behind NAT box */ 316 318 return NF_ACCEPT; 317 319 case PPTP_WAN_ERROR_NOTIFY: 318 - pcid = &pptpReq->wanerr.peersCallID; 320 + pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID); 319 321 break; 320 322 case PPTP_CALL_DISCONNECT_NOTIFY: 321 - pcid = &pptpReq->disc.callID; 323 + pcid_off = offsetof(union pptp_ctrl_union, disc.callID); 322 324 break; 323 325 case PPTP_SET_LINK_INFO: 324 - pcid = &pptpReq->setlink.peersCallID; 326 + pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID); 325 327 break; 326 328 327 329 default: ··· 343 345 * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ 344 346 345 347 /* mangle packet */ 346 - IP_NF_ASSERT(pcid); 347 348 DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", 348 - ntohs(*pcid), ntohs(new_pcid)); 349 + ntohs(*(u_int16_t *)pptpReq + pcid_off), ntohs(new_pcid)); 349 350 350 - rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 351 - (void *)pcid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 351 + rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 352 + pcid_off + sizeof(struct pptp_pkt_hdr) + 353 + sizeof(struct PptpControlHeader), 352 354 sizeof(new_pcid), (char *)&new_pcid, 353 355 sizeof(new_pcid)); 354 356 if (rv != NF_ACCEPT) 355 357 return rv; 356 358 357 359 if (new_cid) { 358 - IP_NF_ASSERT(cid); 359 360 DEBUGP("altering call id from 0x%04x to 0x%04x\n", 360 - ntohs(*cid), ntohs(new_cid)); 361 - rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 362 - (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 363 - sizeof(new_cid), 364 - (char *)&new_cid, 361 + ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_cid)); 362 + rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 363 + cid_off + sizeof(struct pptp_pkt_hdr) + 364 + sizeof(struct PptpControlHeader), 365 + sizeof(new_cid), (char *)&new_cid, 365 366 sizeof(new_cid)); 366 367 if (rv != NF_ACCEPT) 367 368 return rv;