1
0
Fork 0

dn_getsockoptdecnet: move nf_{get/set}sockopt outside sock lock

commit dfec091439 upstream.

After commit 3f34cfae12 ("netfilter: on sockopt() acquire sock lock
only in the required scope"), the caller of nf_{get/set}sockopt() must
not hold any lock, but, in such changeset, I forgot to cope with DECnet.

This commit addresses the issue moving the nf call outside the lock,
in the dn_{get,set}sockopt() with the same schema currently used by
ipv4 and ipv6. Also moves the unhandled sockopts of the end of the main
switch statements, to improve code readability.

Reported-by: Petr Vandrovec <petr@vandrovec.name>
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=198791#c2
Fixes: 3f34cfae12 ("netfilter: on sockopt() acquire sock lock only in the required scope")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
pull/10/head
Paolo Abeni 2018-02-15 16:59:49 +01:00 committed by Greg Kroah-Hartman
parent 80b1c636a7
commit f6b581e3db
1 changed files with 33 additions and 29 deletions

View File

@ -1339,6 +1339,12 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use
lock_sock(sk);
err = __dn_setsockopt(sock, level, optname, optval, optlen, 0);
release_sock(sk);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != DSO_LINKINFO &&
optname != DSO_STREAM && optname != DSO_SEQPACKET)
err = nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
#endif
return err;
}
@ -1446,15 +1452,6 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
break;
default:
#ifdef CONFIG_NETFILTER
return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
#endif
case DSO_LINKINFO:
case DSO_STREAM:
case DSO_SEQPACKET:
return -ENOPROTOOPT;
case DSO_MAXWINDOW:
if (optlen != sizeof(unsigned long))
return -EINVAL;
@ -1502,6 +1499,12 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
return -EINVAL;
scp->info_loc = u.info;
break;
case DSO_LINKINFO:
case DSO_STREAM:
case DSO_SEQPACKET:
default:
return -ENOPROTOOPT;
}
return 0;
@ -1515,6 +1518,20 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char __use
lock_sock(sk);
err = __dn_getsockopt(sock, level, optname, optval, optlen, 0);
release_sock(sk);
#ifdef CONFIG_NETFILTER
if (err == -ENOPROTOOPT && optname != DSO_STREAM &&
optname != DSO_SEQPACKET && optname != DSO_CONACCEPT &&
optname != DSO_CONREJECT) {
int len;
if (get_user(len, optlen))
return -EFAULT;
err = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
if (err >= 0)
err = put_user(len, optlen);
}
#endif
return err;
}
@ -1580,26 +1597,6 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
r_data = &link;
break;
default:
#ifdef CONFIG_NETFILTER
{
int ret, len;
if (get_user(len, optlen))
return -EFAULT;
ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
if (ret >= 0)
ret = put_user(len, optlen);
return ret;
}
#endif
case DSO_STREAM:
case DSO_SEQPACKET:
case DSO_CONACCEPT:
case DSO_CONREJECT:
return -ENOPROTOOPT;
case DSO_MAXWINDOW:
if (r_len > sizeof(unsigned long))
r_len = sizeof(unsigned long);
@ -1631,6 +1628,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
r_len = sizeof(unsigned char);
r_data = &scp->info_rem;
break;
case DSO_STREAM:
case DSO_SEQPACKET:
case DSO_CONACCEPT:
case DSO_CONREJECT:
default:
return -ENOPROTOOPT;
}
if (r_data) {