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

Commit 30f3deee authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds
Browse files

knfsd: use a spinlock to protect sk_info_authunix



sk_info_authunix is not being protected properly so the object that it
points to can be cache_put twice, leading to corruption.

We borrow svsk->sk_defer_lock to provide the protection.  We should
probably rename that lock to have a more generic name - later.

Thanks to Gabriel for reporting this.

Cc: Greg Banks <gnb@melbourne.sgi.com>
Cc: Gabriel Barazer <gabriel@oxeva.fr>
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Cc: <stable@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 94256dd6
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -383,7 +383,10 @@ void svcauth_unix_purge(void)
static inline struct ip_map *
ip_map_cached_get(struct svc_rqst *rqstp)
{
	struct ip_map *ipm = rqstp->rq_sock->sk_info_authunix;
	struct ip_map *ipm;
	struct svc_sock *svsk = rqstp->rq_sock;
	spin_lock_bh(&svsk->sk_defer_lock);
	ipm = svsk->sk_info_authunix;
	if (ipm != NULL) {
		if (!cache_valid(&ipm->h)) {
			/*
@@ -391,12 +394,14 @@ ip_map_cached_get(struct svc_rqst *rqstp)
			 * remembered, e.g. by a second mount from the
			 * same IP address.
			 */
			rqstp->rq_sock->sk_info_authunix = NULL;
			svsk->sk_info_authunix = NULL;
			spin_unlock_bh(&svsk->sk_defer_lock);
			cache_put(&ipm->h, &ip_map_cache);
			return NULL;
		}
		cache_get(&ipm->h);
	}
	spin_unlock_bh(&svsk->sk_defer_lock);
	return ipm;
}

@@ -405,9 +410,15 @@ ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
{
	struct svc_sock *svsk = rqstp->rq_sock;

	if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL)
		svsk->sk_info_authunix = ipm;	/* newly cached, keep the reference */
	else
	spin_lock_bh(&svsk->sk_defer_lock);
	if (svsk->sk_sock->type == SOCK_STREAM &&
	    svsk->sk_info_authunix == NULL) {
		/* newly cached, keep the reference */
		svsk->sk_info_authunix = ipm;
		ipm = NULL;
	}
	spin_unlock_bh(&svsk->sk_defer_lock);
	if (ipm)
		cache_put(&ipm->h, &ip_map_cache);
}