Download raw body.
interface ioctl loopback flags
ok mvs
> On 11 Apr 2024, at 17:27, Alexander Bluhm <bluhm@openbsd.org> wrote:
>
> Hi,
>
> syzkaller has found a crash in igmp_leavegroup.
>
> https://syzkaller.appspot.com/bug?extid=2f24ed6c8ddb2d6bb22c
>
> uvm_fault(0xfffffd80074a6158, 0x4, 0, 1) -> e
> kernel: page fault trap, code=0
> Stopped at igmp_leavegroup+0xaf: movl 0x4(%rax),%r12d
> TID PID UID PRFLAGS PFLAGS CPU COMMAND
> igmp_leavegroup(ffff800000dcbe00,ffff8000006ab000) at igmp_leavegroup+0xaf sys/netinet/igmp.c:512
> in_delmulti(ffff800000dcbe00) at in_delmulti+0xd3 sys/netinet/in.c:908
> ip_freemoptions(ffff8000006ba790) at ip_freemoptions+0x5d sys/netinet/ip_output.c:1737
> in_pcbdetach(fffffd806ed65168) at in_pcbdetach+0x97 sys/netinet/in_pcb.c:606
> udp_detach(fffffd806e5f4948) at udp_detach+0x3f sys/netinet/udp_usrreq.c:1139
> soclose(fffffd806e5f4948,0) at soclose+0x80 pru_detach sys/sys/protosw.h:283 [inline]
> soclose(fffffd806e5f4948,0) at soclose+0x80 sys/kern/uipc_socket.c:411
> soo_close(fffffd807251a350,ffff80002a5d71f8) at soo_close+0x44
> fdrop(fffffd807251a350,ffff80002a5d71f8) at fdrop+0xd5 sys/kern/kern_descrip.c:1274
> closef(fffffd807251a350,ffff80002a5d71f8) at closef+0x11b sys/kern/kern_descrip.c:1258
> fdfree(ffff80002a5d71f8) at fdfree+0xe3 sys/kern/kern_descrip.c:1190
> exit1(ffff80002a5d71f8,0,0,1) at exit1+0x371 sys/kern/kern_exit.c:199
> sys_exit(ffff80002a5d71f8,ffff80002a6650e0,ffff80002a665030) at sys_exit+0x1a sys/kern/kern_exit.c:89
> syscall(ffff80002a6650e0) at syscall+0x72a sys/arch/amd64/amd64/trap.c:577
> Xsyscall() at Xsyscall+0x128
>
> It crashes here as inm->inm_rti is NULL.
>
> void
> igmp_leavegroup(struct in_multi *inm, struct ifnet *ifp)
> {
> switch (inm->inm_state) {
> case IGMP_DELAYING_MEMBER:
> case IGMP_IDLE_MEMBER:
> if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
> (ifp->if_flags & IFF_LOOPBACK) == 0)
> * if (inm->inm_rti->rti_type != IGMP_v1_ROUTER)
> igmp_sendpkt(ifp, inm,
> IGMP_HOST_LEAVE_MESSAGE,
> INADDR_ALLROUTERS_GROUP);
> break;
> case IGMP_LAZY_MEMBER:
> case IGMP_AWAKENING_MEMBER:
> case IGMP_SLEEPING_MEMBER:
> break;
> }
> }
>
> The inm->inm_rti should be set in igmp_joingroup() which calls rti_fill().
>
> void
> igmp_joingroup(struct in_multi *inm, struct ifnet *ifp)
> {
> int i;
>
> inm->inm_state = IGMP_IDLE_MEMBER;
>
> if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
> (ifp->if_flags & IFF_LOOPBACK) == 0) {
> * i = rti_fill(inm);
> igmp_sendpkt(ifp, inm, i, 0);
> inm->inm_state = IGMP_DELAYING_MEMBER;
> inm->inm_timer = IGMP_RANDOM_DELAY(
> IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
> igmp_timers_are_running = 1;
> } else
> inm->inm_timer = 0;
> }
>
> Note that both places have the condition (ifp->if_flags & IFF_LOOPBACK).
> ddb in igmp_leavegroup() shows that ifp is lo0 without IFF_LOOPBACK.
>
> As lo0 is a loopback interface, the rti_fill() is skipped and
> inm->inm_rti is kept as NULL. Then syzkaller clears the IFF_LOOPBACK
> flag with SIOCSIFFLAGS ioctl. Finally igmp_leavegroup() expects
> that inm->inm_rti exists for non loopback interface.
>
> Is there any usecase that userland can modify the IFF_LOOPBACK flag?
> If I add IFF_LOOPBACK to the unchangeable flags, kernel does not crash.
>
> ok?
>
> bluhm
>
> Index: net/if.h
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/if.h,v
> diff -u -p -r1.215 if.h
> --- net/if.h 11 Nov 2023 14:24:03 -0000 1.215
> +++ net/if.h 11 Apr 2024 13:58:22 -0000
> @@ -219,7 +219,7 @@ struct if_status_description {
>
> /* flags set internally only: */
> #define IFF_CANTCHANGE \
> - (IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\
> + (IFF_BROADCAST|IFF_LOOPBACK|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\
> IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI)
>
> #define IFXF_MPSAFE 0x1 /* [I] if_start is mpsafe */
>
interface ioctl loopback flags