Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Mar 2000 07:16:38 -0800 (PST)
From:      steved@WhiteBarn.com
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/17393: kldload syscall allows the same kernel module to be loaded multiple times.
Message-ID:  <200003151516.HAA39382@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         17393
>Category:       kern
>Synopsis:       kldload syscall allows the same kernel module to be loaded multiple times.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Mar 15 07:20:01 PST 2000
>Closed-Date:
>Last-Modified:
>Originator:     Steve Dickson
>Release:        3.2-RELEASE
>Organization:
Consultant for Sitara Networks
>Environment:
FreeBSD peking.sitaranetworks.com 3.2-RELEASE FreeBSD 3.2-RELEASE #11
>Description:
When two daemons (using the kldload() syscall) try and dynamically
load the same kernel module, at the same time, they both succeed.
Which means the same kernel module is loaded twice (which can't be
good).

>How-To-Repeat:
Create two daemons that load the same kernel module and
Start them at the same time.

>Fix:
The problem (as I see it) lies in the kernel routine
linker_load_file(). The files (or linker_files in 3.3)
list is never checked under an exclusive lock.

In linker_load_file(), the linker_find_file_by_name() routine
is used to check to see if the filename has already been
loaded. linker_find_file_by_name() takes out a LK_SHARED
lock to check the linker_files list to see of there is
a entry for the filename.

After this check, the linker_files list is never again check
under an exclusive lock. Which means it very easily for two
threads to be in the lc->ops->load_file() code at the same time.
For example (on a non-SMP machine):
    thread1 -> calls linker_find_file_by_name()
               which return a NULL lf.
    thread1 -> calls malloc and sleeps OR
               calls lc->ops->load_file and sleeps
               before the file is added to the linker_files list.

    thread2 -> calls linker_find_file_by_name()
               which return a NULL lf (since thread1 has not
               added the filename to the linker_files list.
    thread2-> calls lc->ops->load_file.
At this point, both thread1 and thread2 will load the filename.

I fixed the problem by taking out an exclusive to: 
    1) recheck to linker_files list (w/ a non-locking version of
       linker_find_file_by_name) and increment the lf->refs when
       the filename exists (similar to when linker_find_file_by_name()
       returns a non-null lf).

    2) only allow one thread to be in the lc->ops->load_file code.

Basically, the lock is held from after the sprintf(koname, "%s.ko", filename)
call to the out: label.

I agree this is the big hammer approach, but it works with
very little code change and the extra latency caused by this
lock will probably never be be noticed (at least not by my apps)

If you want the actually kern_linker.c file please let me know.



>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200003151516.HAA39382>