Commit f41ced8f108cc80f16509b907cd7ac93944459bc
Committed by
Linus Torvalds
1 parent
bdbeed75b2
Exists in
master
and in
7 other branches
Check fops_get() return value
Several subsystem open handlers dereference the fops_get() return value without checking it for nullness. This opens a race condition between the open handler and module unloading. A module can be marked as being unloaded (MODULE_STATE_GOING) before its exit function is called and gets the chance to unregister the driver. During that window open handlers can still be called, and fops_get() will fail in try_module_get() and return a NULL pointer. This change checks the fops_get() return value and returns -ENODEV if NULL. Reported-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk> Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be> Acked-by: Takashi Iwai <tiwai@suse.de> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Dave Airlie <airlied@linux.ie> Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 13 additions and 0 deletions Side-by-side Diff
drivers/gpu/drm/drm_fops.c
... | ... | @@ -183,6 +183,10 @@ |
183 | 183 | |
184 | 184 | old_fops = filp->f_op; |
185 | 185 | filp->f_op = fops_get(&dev->driver->fops); |
186 | + if (filp->f_op == NULL) { | |
187 | + filp->f_op = old_fops; | |
188 | + goto out; | |
189 | + } | |
186 | 190 | if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { |
187 | 191 | fops_put(filp->f_op); |
188 | 192 | filp->f_op = fops_get(old_fops); |
drivers/media/dvb/dvb-core/dvbdev.c
... | ... | @@ -79,6 +79,10 @@ |
79 | 79 | file->private_data = dvbdev; |
80 | 80 | old_fops = file->f_op; |
81 | 81 | file->f_op = fops_get(dvbdev->fops); |
82 | + if (file->f_op == NULL) { | |
83 | + file->f_op = old_fops; | |
84 | + goto fail; | |
85 | + } | |
82 | 86 | if(file->f_op->open) |
83 | 87 | err = file->f_op->open(inode,file); |
84 | 88 | if (err) { |
... | ... | @@ -90,6 +94,7 @@ |
90 | 94 | unlock_kernel(); |
91 | 95 | return err; |
92 | 96 | } |
97 | +fail: | |
93 | 98 | up_read(&minor_rwsem); |
94 | 99 | unlock_kernel(); |
95 | 100 | return -ENODEV; |
sound/core/sound.c