mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	packet: handle too big packets for PACKET_V3
af_packet can currently overwrite kernel memory by out of bound
accesses, because it assumed a [new] block can always hold one frame.
This is not generally the case, even if most existing tools do it right.
This patch clamps too long frames as API permits, and issue a one time
error on syslog.
[  394.357639] tpacket_rcv: packet too big, clamped from 5042 to 3966. macoff=82
In this example, packet header tp_snaplen was set to 3966,
and tp_len was set to 5042 (skb->len)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Fixes: f6fb8f100b ("af-packet: TPACKET_V3 flexible buffer implementation.")
Acked-by: Daniel Borkmann <dborkman@redhat.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									564ee3606f
								
							
						
					
					
						commit
						dc808110bb
					
				
					 2 changed files with 18 additions and 0 deletions
				
			
		| 
						 | 
					@ -632,6 +632,7 @@ static void init_prb_bdqc(struct packet_sock *po,
 | 
				
			||||||
	p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov);
 | 
						p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov);
 | 
				
			||||||
	p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv;
 | 
						p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p1->max_frame_len = p1->kblk_size - BLK_PLUS_PRIV(p1->blk_sizeof_priv);
 | 
				
			||||||
	prb_init_ft_ops(p1, req_u);
 | 
						prb_init_ft_ops(p1, req_u);
 | 
				
			||||||
	prb_setup_retire_blk_timer(po, tx_ring);
 | 
						prb_setup_retire_blk_timer(po, tx_ring);
 | 
				
			||||||
	prb_open_block(p1, pbd);
 | 
						prb_open_block(p1, pbd);
 | 
				
			||||||
| 
						 | 
					@ -1942,6 +1943,18 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
 | 
				
			||||||
			if ((int)snaplen < 0)
 | 
								if ((int)snaplen < 0)
 | 
				
			||||||
				snaplen = 0;
 | 
									snaplen = 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else if (unlikely(macoff + snaplen >
 | 
				
			||||||
 | 
								    GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) {
 | 
				
			||||||
 | 
							u32 nval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							nval = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len - macoff;
 | 
				
			||||||
 | 
							pr_err_once("tpacket_rcv: packet too big, clamped from %u to %u. macoff=%u\n",
 | 
				
			||||||
 | 
								    snaplen, nval, macoff);
 | 
				
			||||||
 | 
							snaplen = nval;
 | 
				
			||||||
 | 
							if (unlikely((int)snaplen < 0)) {
 | 
				
			||||||
 | 
								snaplen = 0;
 | 
				
			||||||
 | 
								macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spin_lock(&sk->sk_receive_queue.lock);
 | 
						spin_lock(&sk->sk_receive_queue.lock);
 | 
				
			||||||
	h.raw = packet_current_rx_frame(po, skb,
 | 
						h.raw = packet_current_rx_frame(po, skb,
 | 
				
			||||||
| 
						 | 
					@ -3783,6 +3796,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
 | 
							if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
							if (po->tp_version >= TPACKET_V3 &&
 | 
				
			||||||
 | 
							    (int)(req->tp_block_size -
 | 
				
			||||||
 | 
								  BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0)
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
		if (unlikely(req->tp_frame_size < po->tp_hdrlen +
 | 
							if (unlikely(req->tp_frame_size < po->tp_hdrlen +
 | 
				
			||||||
					po->tp_reserve))
 | 
										po->tp_reserve))
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@ struct tpacket_kbdq_core {
 | 
				
			||||||
	char		*pkblk_start;
 | 
						char		*pkblk_start;
 | 
				
			||||||
	char		*pkblk_end;
 | 
						char		*pkblk_end;
 | 
				
			||||||
	int		kblk_size;
 | 
						int		kblk_size;
 | 
				
			||||||
 | 
						unsigned int	max_frame_len;
 | 
				
			||||||
	unsigned int	knum_blocks;
 | 
						unsigned int	knum_blocks;
 | 
				
			||||||
	uint64_t	knxt_seq_num;
 | 
						uint64_t	knxt_seq_num;
 | 
				
			||||||
	char		*prev;
 | 
						char		*prev;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue