Skip to content

Commit 1e5185c

Browse files
hartkoppmarckleinebudde
authored andcommitted
can: raw: add locking for raw flags bitfield
With commit 890e519 ("can: raw: use bitfields to store flags in struct raw_sock") the formerly separate integer values have been integrated into a single bitfield. This led to a read-modify-write operation when changing a flag in raw_setsockopt() which now needs a locking to prevent concurrent access. Instead of adding a lock/unlock hell in each of the flag manipulations this patch introduces a wrapper for a new raw_setsockopt_locked() function analogue to the isotp_setsockopt[_locked]() approach in net/can/isotp.c Fixes: 890e519 ("can: raw: use bitfields to store flags in struct raw_sock") Reported-by: Eulgyu Kim <eulgyukim@snu.ac.kr> Closes: https://lore.kernel.org/linux-can/20260503112200.22727-1-eulgyukim@snu.ac.kr/ Tested-by: Eulgyu Kim <eulgyukim@snu.ac.kr> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Reviewed-by: Vincent Mailhol <mailhol@kernel.org> Tested-by: Vincent Mailhol <mailhol@kernel.org> Link: https://patch.msgid.link/20260504111928.41856-1-socketcan@hartkopp.net [mkl: use Closes tag instead of Link] Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
1 parent c43122f commit 1e5185c

1 file changed

Lines changed: 30 additions & 36 deletions

File tree

net/can/raw.c

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,8 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr,
562562
return RAW_MIN_NAMELEN;
563563
}
564564

565-
static int raw_setsockopt(struct socket *sock, int level, int optname,
566-
sockptr_t optval, unsigned int optlen)
565+
static int raw_setsockopt_locked(struct socket *sock, int optname,
566+
sockptr_t optval, unsigned int optlen)
567567
{
568568
struct sock *sk = sock->sk;
569569
struct raw_sock *ro = raw_sk(sk);
@@ -575,9 +575,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
575575
int flag;
576576
int err = 0;
577577

578-
if (level != SOL_CAN_RAW)
579-
return -EINVAL;
580-
581578
switch (optname) {
582579
case CAN_RAW_FILTER:
583580
if (optlen % sizeof(struct can_filter) != 0)
@@ -598,17 +595,11 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
598595
return -EFAULT;
599596
}
600597

601-
rtnl_lock();
602-
lock_sock(sk);
603-
604598
dev = ro->dev;
605-
if (ro->bound && dev) {
606-
if (dev->reg_state != NETREG_REGISTERED) {
607-
if (count > 1)
608-
kfree(filter);
609-
err = -ENODEV;
610-
goto out_fil;
611-
}
599+
if (ro->bound && dev && dev->reg_state != NETREG_REGISTERED) {
600+
if (count > 1)
601+
kfree(filter);
602+
return -ENODEV;
612603
}
613604

614605
if (ro->bound) {
@@ -622,7 +613,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
622613
if (err) {
623614
if (count > 1)
624615
kfree(filter);
625-
goto out_fil;
616+
return err;
626617
}
627618

628619
/* remove old filter registrations */
@@ -642,11 +633,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
642633
}
643634
ro->filter = filter;
644635
ro->count = count;
645-
646-
out_fil:
647-
release_sock(sk);
648-
rtnl_unlock();
649-
650636
break;
651637

652638
case CAN_RAW_ERR_FILTER:
@@ -658,16 +644,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
658644

659645
err_mask &= CAN_ERR_MASK;
660646

661-
rtnl_lock();
662-
lock_sock(sk);
663-
664647
dev = ro->dev;
665-
if (ro->bound && dev) {
666-
if (dev->reg_state != NETREG_REGISTERED) {
667-
err = -ENODEV;
668-
goto out_err;
669-
}
670-
}
648+
if (ro->bound && dev && dev->reg_state != NETREG_REGISTERED)
649+
return -ENODEV;
671650

672651
/* remove current error mask */
673652
if (ro->bound) {
@@ -676,7 +655,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
676655
err_mask);
677656

678657
if (err)
679-
goto out_err;
658+
return err;
680659

681660
/* remove old err_mask registration */
682661
raw_disable_errfilter(sock_net(sk), dev, sk,
@@ -685,11 +664,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
685664

686665
/* link new err_mask to the socket */
687666
ro->err_mask = err_mask;
688-
689-
out_err:
690-
release_sock(sk);
691-
rtnl_unlock();
692-
693667
break;
694668

695669
case CAN_RAW_LOOPBACK:
@@ -769,6 +743,26 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
769743
return err;
770744
}
771745

746+
static int raw_setsockopt(struct socket *sock, int level, int optname,
747+
sockptr_t optval, unsigned int optlen)
748+
{
749+
struct sock *sk = sock->sk;
750+
int err;
751+
752+
if (level != SOL_CAN_RAW)
753+
return -EINVAL;
754+
755+
rtnl_lock();
756+
lock_sock(sk);
757+
758+
err = raw_setsockopt_locked(sock, optname, optval, optlen);
759+
760+
release_sock(sk);
761+
rtnl_unlock();
762+
763+
return err;
764+
}
765+
772766
static int raw_getsockopt(struct socket *sock, int level, int optname,
773767
sockopt_t *opt)
774768
{

0 commit comments

Comments
 (0)