Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03b9feca authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[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: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 15db3470
Loading
Loading
Loading
Loading
+27 −30
Original line number Diff line number Diff line
@@ -148,14 +148,14 @@ pptp_outbound_pkt(struct sk_buff **pskb,
{
	struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
	struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;

	u_int16_t msg, *cid = NULL, new_callid;
	u_int16_t msg, new_callid;
	unsigned int cid_off;

	new_callid = htons(ct_pptp_info->pns_call_id);
	
	switch (msg = ntohs(ctlh->messageType)) {
		case PPTP_OUT_CALL_REQUEST:
			cid = &pptpReq->ocreq.callID;
			cid_off = offsetof(union pptp_ctrl_union, ocreq.callID);
			/* FIXME: ideally we would want to reserve a call ID
			 * here.  current netfilter NAT core is not able to do
			 * this :( For now we use TCP source port. This breaks
@@ -172,10 +172,10 @@ pptp_outbound_pkt(struct sk_buff **pskb,
			ct_pptp_info->pns_call_id = ntohs(new_callid);
			break;
		case PPTP_IN_CALL_REPLY:
			cid = &pptpReq->icreq.callID;
			cid_off = offsetof(union pptp_ctrl_union, icreq.callID);
			break;
		case PPTP_CALL_CLEAR_REQUEST:
			cid = &pptpReq->clrreq.callID;
			cid_off = offsetof(union pptp_ctrl_union, clrreq.callID);
			break;
		default:
			DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
@@ -197,17 +197,14 @@ pptp_outbound_pkt(struct sk_buff **pskb,

	/* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass
	 * down to here */

	IP_NF_ASSERT(cid);

	DEBUGP("altering call id from 0x%04x to 0x%04x\n",
		ntohs(*cid), ntohs(new_callid));
		ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_callid));

	/* mangle packet */
	if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
		(void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)),
				 	sizeof(new_callid), 
					(char *)&new_callid,
	                             cid_off + sizeof(struct pptp_pkt_hdr) +
	                             sizeof(struct PptpControlHeader),
	                             sizeof(new_callid), (char *)&new_callid,
	                             sizeof(new_callid)) == 0)
		return NF_DROP;

@@ -299,7 +296,8 @@ pptp_inbound_pkt(struct sk_buff **pskb,
		 union pptp_ctrl_union *pptpReq)
{
	struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
	u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
	u_int16_t msg, new_cid = 0, new_pcid;
	unsigned int pcid_off, cid_off = 0;

	int ret = NF_ACCEPT, rv;

@@ -307,23 +305,23 @@ pptp_inbound_pkt(struct sk_buff **pskb,

	switch (msg = ntohs(ctlh->messageType)) {
	case PPTP_OUT_CALL_REPLY:
		pcid = &pptpReq->ocack.peersCallID;	
		cid = &pptpReq->ocack.callID;
		pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID);
		cid_off = offsetof(union pptp_ctrl_union, ocack.callID);
		break;
	case PPTP_IN_CALL_CONNECT:
		pcid = &pptpReq->iccon.peersCallID;
		pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID);
		break;
	case PPTP_IN_CALL_REQUEST:
		/* only need to nat in case PAC is behind NAT box */
		return NF_ACCEPT;
	case PPTP_WAN_ERROR_NOTIFY:
		pcid = &pptpReq->wanerr.peersCallID;
		pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID);
		break;
	case PPTP_CALL_DISCONNECT_NOTIFY:
		pcid = &pptpReq->disc.callID;
		pcid_off = offsetof(union pptp_ctrl_union, disc.callID);
		break;
	case PPTP_SET_LINK_INFO:
		pcid = &pptpReq->setlink.peersCallID;
		pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID);
		break;

	default:
@@ -345,25 +343,24 @@ pptp_inbound_pkt(struct sk_buff **pskb,
	 * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */

	/* mangle packet */
	IP_NF_ASSERT(pcid);
	DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
		ntohs(*pcid), ntohs(new_pcid));
		ntohs(*(u_int16_t *)pptpReq + pcid_off), ntohs(new_pcid));
	
	rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
				      (void *)pcid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)),
	                              pcid_off + sizeof(struct pptp_pkt_hdr) +
				      sizeof(struct PptpControlHeader),
				      sizeof(new_pcid), (char *)&new_pcid, 
				      sizeof(new_pcid));
	if (rv != NF_ACCEPT) 
		return rv;

	if (new_cid) {
		IP_NF_ASSERT(cid);
		DEBUGP("altering call id from 0x%04x to 0x%04x\n",
			ntohs(*cid), ntohs(new_cid));
			ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_cid));
		rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
					      (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), 
					      sizeof(new_cid),
					      (char *)&new_cid, 
		                              cid_off + sizeof(struct pptp_pkt_hdr) +
					      sizeof(struct PptpControlHeader),
					      sizeof(new_cid), (char *)&new_cid, 
					      sizeof(new_cid));
		if (rv != NF_ACCEPT)
			return rv;