Skip to content

Commit

Permalink
blktrace: fix unlocked access to init/start-stop/teardown
Browse files Browse the repository at this point in the history
sg.c calls into the blktrace functions without holding the proper queue
mutex for doing setup, start/stop, or teardown.

Add internal unlocked variants, and export the ones that do the proper
locking.

Fixes: 6da127a ("blktrace: Add blktrace ioctls to SCSI generic devices")
Tested-by: Dmitry Vyukov <[email protected]>
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
axboe committed Nov 11, 2017
1 parent bf9fc98 commit 1f2cac1
Showing 1 changed file with 48 additions and 10 deletions.
58 changes: 48 additions & 10 deletions kernel/trace/blktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ static void blk_trace_cleanup(struct blk_trace *bt)
blk_unregister_tracepoints();
}

int blk_trace_remove(struct request_queue *q)
static int __blk_trace_remove(struct request_queue *q)
{
struct blk_trace *bt;

Expand All @@ -349,6 +349,17 @@ int blk_trace_remove(struct request_queue *q)

return 0;
}

int blk_trace_remove(struct request_queue *q)
{
int ret;

mutex_lock(&q->blk_trace_mutex);
ret = __blk_trace_remove(q);
mutex_unlock(&q->blk_trace_mutex);

return ret;
}
EXPORT_SYMBOL_GPL(blk_trace_remove);

static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
Expand Down Expand Up @@ -550,9 +561,8 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
return ret;
}

int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
struct block_device *bdev,
char __user *arg)
static int __blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
struct block_device *bdev, char __user *arg)
{
struct blk_user_trace_setup buts;
int ret;
Expand All @@ -571,6 +581,19 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
}
return 0;
}

int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
struct block_device *bdev,
char __user *arg)
{
int ret;

mutex_lock(&q->blk_trace_mutex);
ret = __blk_trace_setup(q, name, dev, bdev, arg);
mutex_unlock(&q->blk_trace_mutex);

return ret;
}
EXPORT_SYMBOL_GPL(blk_trace_setup);

#if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
Expand Down Expand Up @@ -607,7 +630,7 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
}
#endif

int blk_trace_startstop(struct request_queue *q, int start)
static int __blk_trace_startstop(struct request_queue *q, int start)
{
int ret;
struct blk_trace *bt = q->blk_trace;
Expand Down Expand Up @@ -646,6 +669,17 @@ int blk_trace_startstop(struct request_queue *q, int start)

return ret;
}

int blk_trace_startstop(struct request_queue *q, int start)
{
int ret;

mutex_lock(&q->blk_trace_mutex);
ret = __blk_trace_startstop(q, start);
mutex_unlock(&q->blk_trace_mutex);

return ret;
}
EXPORT_SYMBOL_GPL(blk_trace_startstop);

/*
Expand Down Expand Up @@ -676,7 +710,7 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
switch (cmd) {
case BLKTRACESETUP:
bdevname(bdev, b);
ret = blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
ret = __blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
break;
#if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
case BLKTRACESETUP32:
Expand All @@ -687,10 +721,10 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
case BLKTRACESTART:
start = 1;
case BLKTRACESTOP:
ret = blk_trace_startstop(q, start);
ret = __blk_trace_startstop(q, start);
break;
case BLKTRACETEARDOWN:
ret = blk_trace_remove(q);
ret = __blk_trace_remove(q);
break;
default:
ret = -ENOTTY;
Expand All @@ -708,10 +742,14 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
**/
void blk_trace_shutdown(struct request_queue *q)
{
mutex_lock(&q->blk_trace_mutex);

if (q->blk_trace) {
blk_trace_startstop(q, 0);
blk_trace_remove(q);
__blk_trace_startstop(q, 0);
__blk_trace_remove(q);
}

mutex_unlock(&q->blk_trace_mutex);
}

#ifdef CONFIG_BLK_CGROUP
Expand Down

0 comments on commit 1f2cac1

Please sign in to comment.