[Bug 2002] New: ioctl recursive perimeter lock driver deadlock vulnerability
bugzilla-daemon at rtems.org
bugzilla-daemon at rtems.org
Tue Jan 31 15:29:37 UTC 2012
https://www.rtems.org/bugzilla/show_bug.cgi?id=2002
Summary: ioctl recursive perimeter lock driver deadlock
vulnerability
Product: RTEMS
Version: HEAD
Platform: All
OS/Version: RTEMS
Status: NEW
Severity: normal
Priority: P3
Component: networking
AssignedTo: norume at aps.anl.gov
ReportedBy: jeffreyhill at att.net
In summary, a generalized deadlock potential exists any time rtems_bsdnet_ioctl
calls rtems_bsdnet_ifconfig which calls the driver, and the driver tries to
release the bsd networking semaphore, but the lock count doesn't decrement to
zero, so the lock is never released.
What happened to me (when writing an Altera Triple Speed Ethernet Driver for
NIOS2) was as follows (names here are slightly different than reality). Of
course other scenarios are possible.
user calls
rtems_bsdnet_ioctl which takes bsd stack lock, it calls
rtems_bsdnet_ifconfig which locks bsd stack recursively, it calls
driver_ioctl function when setting IF_UP flag to true, it calls
driver_begin_communicating and it discovers it is already communicating, it
calls
driver_stop_communicating which iscovers that tx/rx threads are running, it
calls
bsd_locking_semaphore_release while waiting for the tx/rx threads to shutdown
rip
I fixed this of by changing to a noop if they set IF_UP flag and the driver is
already up and running, but sometimes that might be less than robust because we
are not forcing a restart of the auxiliary threads. Furthermore, if the user
sets the UP flag to false then we cant avoid this issue; we will definitely
need to release the lock when the driver threads are forced to exit?
POTENTIAL FIX:
Usually what is done is to make a rtems_bsdnet_ifconfig_nolock_private function
and then call it form both rtems_bsdnet_ioctl and rtems_bsdnet_ifconfig;
presumably the perimeter functions must lock only once on the way in, or in any
case thats a common convention with multi-threaded code.
On Jan 30, 2012, at 12:30 PM, Hill, Jeffrey O wrote:
>
>> -----Original Message-----
>> From: Eric Norum
>> Sent: Monday, January 30, 2012 11:21 AM
>> To: Hill, Jeffrey O
>> Cc: Till Straumann
>> Subject: Re: rtems bsd network deadlock potential
>>
>> The network mutex is to be taken whenever making the transition from
>> 'user' code from 'kernel' code. I did this because the BSD kernel from
>> which the networking code was lifted was, like many (all?) old UNIXes,
>> non-reentrant. It's possible that over the years some code has been
>> added to the IOCTL support that ends up calling a 'user' level routine
>> from 'kernel' level which then calls some 'kernel' code again. This
>> should be fixed. kernel code should never call user code -- just to avoid
>> the nested mutex problem that Jeff is reporting. Perhaps some IOCTL
>> routine need to be split up with a user-level wrapper that takes the mutex
>> then calls the kernel level routine -- and that kernel level routine
>> should be what any other kernel level code invokes.
>>
>> I'm afraid that I don't have time to look at this now.
>>
>> On Jan 30, 2012, at 9:30 AM, Hill, Jeffrey O wrote:
>>
>>>> It could well be that the intention is that rtems_bsdnet_ioctl()
>> executes
>>>> atomically w/o the driver temporarily releasing the lock and doing
>>>> communication. That could alter internal state in unintended ways.
>>>
>>> Ok, maybe this is just part of the design, but I am left with some
>> doubts if this type of (taking the lock twice to prevent the state from
>> changing while in the driver) enforcement policy is applied uniformly. It
>> might even be that this is in place purely because of accidental
>> inconsistencies in the way the lock is acquired on the way in.
>>>
>>> Considering this further, isn't it quite routine and normal for the
>> driver to shutdown auxiliary threads (which take the lock) when inside the
>> driver ioctl function if the user sets the UP flag to false? Presumably
>> this can't be done reliably w/o releasing the lock in the driver?
>>>
>>> Of course the RTEMS designers, who know all of the consequences will
>> need to decide. I am only identifying what appear to be issues when I see
>> them.
>>>
>>> Jeff
>>>
>>>> -----Original Message-----
>>>> From: Till Straumann
>>>> Sent: Monday, January 30, 2012 10:07 AM
>>>> To: Hill, Jeffrey O
>>>> Cc: Eric Norum
>>>> Subject: Re: rtems bsd network deadlock potential
>>>>
>>>> I see. However, I'm not sure if that is not a programming error in the
>>>> driver.
>>>> It could well be that the intention is that rtems_bsdnet_ioctl()
>> executes
>>>> atomically w/o the driver temporarily releasing the lock and doing
>>>> communication.
>>>> That could alter internal state in unintended ways.
>>>>
>>>> T.
>>>>
>>>>
>>>> On 01/30/2012 10:58 AM, Hill, Jeffrey O wrote:
>>>>> Hi Till,
>>>>>
>>>>> What happened to me was as follows (names are slightly different than
>>>> reality), but of course other scenarios are possible.
>>>>>
>>>>> rtems_bsdnet_ioctl calls (it locks), it calls
>>>>> rtems_bsdnet_ifconfig calls (it locks recursively), it calls
>>>>> driver_ioctl function (because IF_UP flag is being set to true), it
>>>> calls
>>>>> driver_begin_communicating (which discovers that it is already
>>>> communicating), it calls
>>>>> driver_stop_communicating (which discovers that tx/rx threads are
>>>> running), it calls
>>>>> bsd_locking_semaphore_release (while waiting for the tx/rx threads to
>>>> shutdown)
>>>>> rip
>>>>>
>>>>> I fixed this of course by changing to a noop if they set IF_UP flag
>> and
>>>> the driver is already up and running, but sometimes that might be less
>>>> robust because we are not forcing a restart of the auxiliary threads.
>>>>>
>>>>> In summary, a generalized deadlock potential exists any time
>>>> rtems_bsdnet_ioctl calls rtems_bsdnet_ifconfig which calls the driver,
>> and
>>>> the driver tries to release the semaphore, but the lock count doesn't
>>>> decrement to zero, so the lock is never released.
>>>>>
>>>>> Usually what is done is to make a rtems_bsdnet_ifconfig_nolock_private
>>>> and then call it form both rtems_bsdnet_ioctl and
>> rtems_bsdnet_ifconfig;
>>>> the perimeter functions must lock only once on the way in.
>>>>>
>>>>> Jeff
>>>>>
>>>>>> -----Original Message-----
>>>>>> From: Till Straumann
>>>>>> Sent: Friday, January 27, 2012 3:36 PM
>>>>>> To: Hill, Jeffrey O
>>>>>> Cc: Eric Norum
>>>>>> Subject: Re: rtems bsd network deadlock potential
>>>>>>
>>>>>> Maybe I'm missing something but AFAIK the networking semaphore is
>>>>>> basically
>>>>>> a mutex which you can take multiple times from the same thread.
>>>>>>
>>>>>> Could you please explain in more detail?
>>>>>>
>>>>>> T.
>>>>>>
>>>>>> On 01/27/2012 04:28 PM, Hill, Jeffrey O wrote:
>>>>>>> Hi Eric, Till,
>>>>>>>
>>>>>>> FWIW, I noticed today that there is a situation where
>>>> rtems_bsdnet_ioctl
>>>>>> calls rtems_bsdnet_ifconfig, but both functions take the bsd
>> networking
>>>>>> semaphore resulting in a recursive reference counted lock. Therefore
>> if
>>>>>> the driver's implementation of ioctl calls rtems_bsdnet_event_receive
>>>>>> there will be a deadlock (because the internal attempt to unlock is
>>>>>> silently unsuccessful). I will no-doubt try to come up with a
>>>> workaround
>>>>>> but perhaps the situation is somewhat precarious.
>>>>>>> Is this serious enough that I should report a bug to the RTEMS bug
>>>>>> tracking system?
>>>>>>> #0 ( rtems_bsdnet_event_receive(event_in=8, option_set=0, ticks=0,
>>>>>> event_out=0xa7a9f4) (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /cpukit/libnetworking/rtems/rtems_glue.c:687)
>>>>>>> #1 0x5f34 alt_tse_soft_tx_stop(pSoftSgdmaTx=0xb24084)
>>>> (/home/hill/nios2-
>>>>>> rtems/rtems/rtems-4.11.0-
>>>>>> /c/src/lib/libbsp/nios2/neek/network/if_alttse.c:206)
>>>>>>> #2 0x5fa8 alt_tse_soft_tx_destroy(pSoftSgdmaTx=0xb24084)
>>>>>> (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /c/src/lib/libbsp/nios2/neek/network/if_alttse.c:216)
>>>>>>> #3 0x8808 alt_tse_stop_comm(ifp=0xb23c3c) (/home/hill/nios2-
>>>>>> rtems/rtems/rtems-4.11.0-
>>>>>> /c/src/lib/libbsp/nios2/neek/network/if_alttse.c:1554)
>>>>>>> #4 0x88a8 alt_tse_start_comm(pParm=0xb23c3c) (/home/hill/nios2-
>>>>>> rtems/rtems/rtems-4.11.0-
>>>>>> /c/src/lib/libbsp/nios2/neek/network/if_alttse.c:1576)
>>>>>>> #5 0x8a90 alt_tse_start_comm_no_status(pParm=0xb23c3c)
>>>>>> (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /c/src/lib/libbsp/nios2/neek/network/if_alttse.c:1651)
>>>>>>> #6 0xe5a8 ether_ioctl(ifp=0xb23c3c, command=1, data=<value
>>>> optimized
>>>>>> out>) (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /cpukit/libnetworking/net/if_ethersubr.c:838)
>>>>>>> #7 0x8bc0 alt_tse_ioctl(ifp=0xb23c3c, cmmd=2149607692,
>>>> data=0xb24648
>>>>>> "\210F\262") (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /c/src/lib/libbsp/nios2/neek/network/if_alttse.c:1680)
>>>>>>> #8 0x3272c in_ifinit(ifp=0xb23c3c, ia=0xb24648, sin=<value
>>>> optimized
>>>>>> out>, scrub=1) (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /cpukit/libnetworking/netinet/in.c:480)
>>>>>>> #9 0x331a0 in_control(so=<value optimized out>, cmd=2149607692,
>>>>>> data=0xa7aba0 "tse0", ifp=0xb23c3c) (/home/hill/nios2-
>>>> rtems/rtems/rtems-
>>>>>> 4.11.0-/cpukit/libnetworking/netinet/in.c:312)
>>>>>>> #10 0x2632c old_control(so=0x0, cmd=10987900, data=0xa7a9f4
>>>>>> "\034\252\247", ifp=<value optimized out>) (/home/hill/nios2-
>>>>>> rtems/rtems/rtems-4.11.0-
>> /cpukit/libnetworking/kern/uipc_socket2.c:801)
>>>>>>> #11 0xfcc8 ifioctl(so=0xb23e08, cmd=1, data=0xa7aba0 "tse0",
>>>> p=<value
>>>>>> optimized out>) (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /cpukit/libnetworking/net/if.c:605)
>>>>>>> #12 0x1c3e8 so_ioctl(iop=0xaf2544, command=1, buffer=<value
>>>>>> optimized out>) (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /cpukit/libnetworking/rtems/rtems_syscall.c:713)
>>>>>>> #13 ( rtems_bsdnet_ioctl(iop=0xaf2544, command=1, buffer=<value
>>>>>> optimized out>) (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /cpukit/libnetworking/rtems/rtems_syscall.c:731)
>>>>>>> #14 0x3093c ioctl(fd=<value optimized out>, command=1)
>>>>>> (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /cpukit/libcsupport/src/ioctl.c:50)
>>>>>>> #15 0x194b8 rtems_bsdnet_ifconfig(ifname=0x4afb4 "tse0",
>>>>>> cmd=2149607692, param=0xa7abe0) (/home/hill/nios2-rtems/rtems/rtems-
>>>>>> 4.11.0-/cpukit/libnetworking/rtems/rtems_glue.c:1114)
>>>>>>> #16 0x19718 rtems_bsdnet_setup_interface(name=0x4afb4 "tse0",
>>>>>> ip_address=0x4afbc "128.165.34.102", ip_netmask=0x4afcc
>>>> "255.255.255.0")
>>>>>> (/home/hill/nios2-rtems/rtems/rtems-4.11.0-
>>>>>> /cpukit/libnetworking/rtems/rtems_glue.c:879)
>>>>>>> #17 0x19d88 rtems_bsdnet_setup() (/home/hill/nios2-
>>>>>> rtems/rtems/rtems-4.11.0-
>> /cpukit/libnetworking/rtems/rtems_glue.c:959)
>>>>>>> #18 ( rtems_bsdnet_initialize_network() (/home/hill/nios2-
>>>>>> rtems/rtems/rtems-4.11.0-
>> /cpukit/libnetworking/rtems/rtems_glue.c:1018)
>>>>>>> #19 0x360 Init(ignored=336840) (init.c:51)
>>>>>>> #20 0x3a268 _Thread_Handler() (/home/hill/nios2-rtems/rtems/rtems-
>>>>>> 4.11.0-/cpukit/score/src/threadhandler.c:157)
>>>>>>> #21 0x132c boot_card(cmdline=0xa74338 "DD\247") (/home/hill/nios2-
>>>>>> rtems/rtems/rtems-4.11.0-
>>>>>> /c/src/lib/libbsp/nios2/neek/../../shared/bootcard.c:268)
>>>>>>> #22 ( 0x00000000 in ??() (??:??)
>>>>>>>
>>>>>>> Jeff
>>>
>>
>> --
>> Eric Norum
>
--
Eric Norum
--
Configure bugmail: https://www.rtems.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are watching all bug changes.
More information about the bugs
mailing list