Skip to content

Commit dea6e19

Browse files
Girish Moodalbaildavem330
authored andcommitted
tap: reference to KVA of an unloaded module causes kernel panic
The commit 9a393b5 ("tap: tap as an independent module") created a separate tap module that implements tap functionality and exports interfaces that will be used by macvtap and ipvtap modules to create create respective tap devices. However, that patch introduced a regression wherein the modules macvtap and ipvtap can be removed (through modprobe -r) while there are applications using the respective /dev/tapX devices. These applications cause kernel to hold reference to /dev/tapX through 'struct cdev macvtap_cdev' and 'struct cdev ipvtap_dev' defined in macvtap and ipvtap modules respectively. So, when the application is later closed the kernel panics because we are referencing KVA that is present in the unloaded modules. ----------8<------- Example ----------8<---------- $ sudo ip li add name mv0 link enp7s0 type macvtap $ sudo ip li show mv0 |grep mv0| awk -e '{print $1 $2}' 14:mv0@enp7s0: $ cat /dev/tap14 & $ lsmod |egrep -i 'tap|vlan' macvtap 16384 0 macvlan 24576 1 macvtap tap 24576 3 macvtap $ sudo modprobe -r macvtap $ fg cat /dev/tap14 ^C <...system panics...> BUG: unable to handle kernel paging request at ffffffffa038c500 IP: cdev_put+0xf/0x30 ----------8<-----------------8<---------- The fix is to set cdev.owner to the module that creates the tap device (either macvtap or ipvtap). With this set, the operations (in fs/char_dev.c) on char device holds and releases the module through cdev_get() and cdev_put() and will not allow the module to unload prematurely. Fixes: 9a393b5 (tap: tap as an independent module) Signed-off-by: Girish Moodalbail <girish.moodalbail@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent ee1836a commit dea6e19

4 files changed

Lines changed: 9 additions & 8 deletions

File tree

drivers/net/ipvlan/ipvtap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ static int ipvtap_init(void)
197197
{
198198
int err;
199199

200-
err = tap_create_cdev(&ipvtap_cdev, &ipvtap_major, "ipvtap");
201-
200+
err = tap_create_cdev(&ipvtap_cdev, &ipvtap_major, "ipvtap",
201+
THIS_MODULE);
202202
if (err)
203203
goto out1;
204204

drivers/net/macvtap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ static int macvtap_init(void)
204204
{
205205
int err;
206206

207-
err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap");
208-
207+
err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap",
208+
THIS_MODULE);
209209
if (err)
210210
goto out1;
211211

drivers/net/tap.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,8 +1249,8 @@ static int tap_list_add(dev_t major, const char *device_name)
12491249
return 0;
12501250
}
12511251

1252-
int tap_create_cdev(struct cdev *tap_cdev,
1253-
dev_t *tap_major, const char *device_name)
1252+
int tap_create_cdev(struct cdev *tap_cdev, dev_t *tap_major,
1253+
const char *device_name, struct module *module)
12541254
{
12551255
int err;
12561256

@@ -1259,6 +1259,7 @@ int tap_create_cdev(struct cdev *tap_cdev,
12591259
goto out1;
12601260

12611261
cdev_init(tap_cdev, &tap_fops);
1262+
tap_cdev->owner = module;
12621263
err = cdev_add(tap_cdev, *tap_major, TAP_NUM_DEVS);
12631264
if (err)
12641265
goto out2;

include/linux/if_tap.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ void tap_del_queues(struct tap_dev *tap);
7373
int tap_get_minor(dev_t major, struct tap_dev *tap);
7474
void tap_free_minor(dev_t major, struct tap_dev *tap);
7575
int tap_queue_resize(struct tap_dev *tap);
76-
int tap_create_cdev(struct cdev *tap_cdev,
77-
dev_t *tap_major, const char *device_name);
76+
int tap_create_cdev(struct cdev *tap_cdev, dev_t *tap_major,
77+
const char *device_name, struct module *module);
7878
void tap_destroy_cdev(dev_t major, struct cdev *tap_cdev);
7979

8080
#endif /*_LINUX_IF_TAP_H_*/

0 commit comments

Comments
 (0)