Re: [PATCH ovpn net v5 1/6] ovpn: fix NULL dereference when killing missing key

Ralf Lici <[email protected]>
Newsgroups gmane.network.openvpn.devel
Message-ID <[email protected]>
On Tue, 07 Jul 2026 12:18:08 +0200, Sabrina Dubroca <[email protected]> wrote:
> Hi Ralf,
>
> Sorry, I'm slowly catching up with the recent activity here.
>

Hi Sabrina,

No worries, thanks for your time!

> 2026-07-06, 13:33:59 +0200, Ralf Lici wrote:
> > ovpn_crypto_kill_key assumes both crypto slots are populated and
> > dereferences each slot before checking it. That is not guaranteed: a
> > peer can have only one installed key, and the kill path may be asked to
> > remove a key that is not present.
> > 
> > Read each slot once while holding the crypto state lock, check for NULL
> > before looking at key_id, and only replace the slot that actually
> > matches.
> > 
> > Fixes: 89d3c0e4612a ("ovpn: kill key and notify userspace in case of IV exhaustion")
> > Signed-off-by: Ralf Lici <[email protected]>
> > ---
> > Changes since v4 of this series https://lore.kernel.org/openvpn-devel/981d2ea51cca45138210aa52c6e5a0e55c0da7a0.1783099626.git.ralf@mandelbit.com/
> > - Add this previously posted standalone fix to the series so the whole
> >   set can be picked in order.
> > - No changes since v2 of the original single patch
> >   https://lore.kernel.org/openvpn-devel/19318904cf077d067cd4ec628a22bab03ed7dd29.1782993857.git.ralf@mandelbit.com/
> > 
> > Changes since v1 of the original single patch https://lore.kernel.org/openvpn-devel/9fc33e6f9fae10b9e372a3e06934d697edf5b024.1782829171.git.ralf@mandelbit.com/
> > - Remove unnecessary braces around single-statement if/else branches.
> > 
> >  drivers/net/ovpn/crypto.c | 10 +++++++---
> >  1 file changed, 7 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c
> > index 90580e32052f..8cb7078a1d93 100644
> > --- a/drivers/net/ovpn/crypto.c
> > +++ b/drivers/net/ovpn/crypto.c
> > @@ -58,15 +58,19 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state *cs)
> >  bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id)
> >  {
> >  	struct ovpn_crypto_key_slot *ks = NULL;
> > +	struct ovpn_crypto_key_slot *tmp;
> >  
> >  	spin_lock_bh(&cs->lock);
> > -	if (rcu_access_pointer(cs->slots[0])->key_id == key_id) {
> > +	tmp = rcu_access_pointer(cs->slots[0]);
> > +	if (tmp && tmp->key_id == key_id)
> >  		ks = rcu_replace_pointer(cs->slots[0], NULL,
> >  					 lockdep_is_held(&cs->lock));
> > -	} else if (rcu_access_pointer(cs->slots[1])->key_id == key_id) {
> > +	else
> > +		tmp = rcu_access_pointer(cs->slots[1]);
> > +
> > +	if (!ks && tmp && tmp->key_id == key_id)
> >  		ks = rcu_replace_pointer(cs->slots[1], NULL,
> >  					 lockdep_is_held(&cs->lock));
> > -	}
>
> I find the "!ks && tmp" logic really confusing. Maybe something like
> this (untested) would be more readable?
>
>
> 	int slot;
>
> 	spin_lock_bh(&cs->lock);
> 	slot = 0;
> 	tmp = rcu_access_pointer(cs->slots[slot]);
> 	if (!tmp || tmp->key_id != key_id) {
> 		slot = 1;
> 		tmp = rcu_access_pointer(cs->slots[slot]);
> 	}
>
> 	if (tmp && tmp->key_id == key_id)
> 		ks = rcu_replace_pointer(cs->slots[slot], NULL,
> 					 lockdep_is_held(&cs->lock));
> 	spin_unlock_bh(&cs->lock);
> [...]
>

Agreed, this is cleaner. I'll adopt this shape for the next version.

-- 
Ralf Lici
Mandelbit Srl
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.