forked from mirrors/linux
		
	xfrm: Fix replay notification for esn.
We may miscalculate the sequence number difference from the last time we send a notification if a sequence number wrap occured in the meantime. We fix this by adding a separate replay notify function for esn. Here we take the high bits of the sequence number into account to calculate the difference. Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
		
							parent
							
								
									85dfb745ee
								
							
						
					
					
						commit
						0017c0b575
					
				
					 1 changed files with 67 additions and 1 deletions
				
			
		| 
						 | 
					@ -334,6 +334,72 @@ static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
 | 
				
			||||||
		x->xflags &= ~XFRM_TIME_DEFER;
 | 
							x->xflags &= ~XFRM_TIME_DEFER;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void xfrm_replay_notify_esn(struct xfrm_state *x, int event)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 seq_diff, oseq_diff;
 | 
				
			||||||
 | 
						struct km_event c;
 | 
				
			||||||
 | 
						struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
 | 
				
			||||||
 | 
						struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* we send notify messages in case
 | 
				
			||||||
 | 
						 *  1. we updated on of the sequence numbers, and the seqno difference
 | 
				
			||||||
 | 
						 *     is at least x->replay_maxdiff, in this case we also update the
 | 
				
			||||||
 | 
						 *     timeout of our timer function
 | 
				
			||||||
 | 
						 *  2. if x->replay_maxage has elapsed since last update,
 | 
				
			||||||
 | 
						 *     and there were changes
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *  The state structure must be locked!
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (event) {
 | 
				
			||||||
 | 
						case XFRM_REPLAY_UPDATE:
 | 
				
			||||||
 | 
							if (!x->replay_maxdiff)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (replay_esn->seq_hi == preplay_esn->seq_hi)
 | 
				
			||||||
 | 
								seq_diff = replay_esn->seq - preplay_esn->seq;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								seq_diff = UINT_MAX - preplay_esn->seq
 | 
				
			||||||
 | 
									   + replay_esn->seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
 | 
				
			||||||
 | 
								oseq_diff = replay_esn->oseq - preplay_esn->oseq;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								oseq_diff = UINT_MAX - preplay_esn->oseq
 | 
				
			||||||
 | 
									    + replay_esn->oseq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (seq_diff < x->replay_maxdiff &&
 | 
				
			||||||
 | 
							    oseq_diff < x->replay_maxdiff) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (x->xflags & XFRM_TIME_DEFER)
 | 
				
			||||||
 | 
									event = XFRM_REPLAY_TIMEOUT;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case XFRM_REPLAY_TIMEOUT:
 | 
				
			||||||
 | 
							if (memcmp(x->replay_esn, x->preplay_esn,
 | 
				
			||||||
 | 
								   xfrm_replay_state_esn_len(replay_esn)) == 0) {
 | 
				
			||||||
 | 
								x->xflags |= XFRM_TIME_DEFER;
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(x->preplay_esn, x->replay_esn,
 | 
				
			||||||
 | 
						       xfrm_replay_state_esn_len(replay_esn));
 | 
				
			||||||
 | 
						c.event = XFRM_MSG_NEWAE;
 | 
				
			||||||
 | 
						c.data.aevent = event;
 | 
				
			||||||
 | 
						km_state_notify(x, &c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (x->replay_maxage &&
 | 
				
			||||||
 | 
						    !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
 | 
				
			||||||
 | 
							x->xflags &= ~XFRM_TIME_DEFER;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
 | 
					static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
| 
						 | 
					@ -510,7 +576,7 @@ static struct xfrm_replay xfrm_replay_esn = {
 | 
				
			||||||
	.advance	= xfrm_replay_advance_esn,
 | 
						.advance	= xfrm_replay_advance_esn,
 | 
				
			||||||
	.check		= xfrm_replay_check_esn,
 | 
						.check		= xfrm_replay_check_esn,
 | 
				
			||||||
	.recheck	= xfrm_replay_recheck_esn,
 | 
						.recheck	= xfrm_replay_recheck_esn,
 | 
				
			||||||
	.notify		= xfrm_replay_notify_bmp,
 | 
						.notify		= xfrm_replay_notify_esn,
 | 
				
			||||||
	.overflow	= xfrm_replay_overflow_esn,
 | 
						.overflow	= xfrm_replay_overflow_esn,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue