Linux Input/HID development
 help / color / mirror / Atom feed
From: iceberg <iceberg@ispras.ru>
To: Jiri Kosina <jkosina@suse.cz>,
	linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [BUG] hidraw.c: double mutex_lock
Date: Mon, 12 Oct 2009 13:11:49 +0000	[thread overview]
Message-ID: <1255353109.13239.0@pamir> (raw)

	KERNEL_VERSION: 2.6.31
	DESCRIBE:
	In driver ./drivers/hid/hidraw.c in function hidraw_read may be 
double mutex_lock:

Path:
1. line 50: begin first iteration of "while(ret==0)"
2. line 52: first call to mutex_lock
3. inner loop "while (list->head == list->tail)" does not change state 
of mutex, because mutex_lock immediatelly follows mutex_unlock
4. if we go to the second iteration of "while(ret == 0)" in 
line 50 then there are second call to mutex_lock in line 52 (mutex 
aquired twice).

Second iteration of loop "while(ret==0)" is possible if local variable 
ret is not changed at line 94: ret+=len - i.e. len==0;
Variable len may be zero if hidraw_read is called with count==0 or 
list->buffer[list->tail].len == 0.

static ssize_t hidraw_read(struct file *file, char __user *buffer, 
size_t count, loff_t *ppos)
  44{
  45        struct hidraw_list *list = file->private_data;
  46        int ret = 0, len;
  47        char *report;
  48        DECLARE_WAITQUEUE(wait, current);
  49
  50        while (ret == 0) {
  51
  52                mutex_lock(&list->read_mutex);
  53
  54                if (list->head == list->tail) {
  55                        add_wait_queue(&list->hidraw->wait, &wait);
  56                        set_current_state(TASK_INTERRUPTIBLE);
  57
  58                        while (list->head == list->tail) {
  59                                if (file->f_flags & O_NONBLOCK) {
  60                                        ret = -EAGAIN;
  61                                        break;
  62                                }
  63                                if (signal_pending(current)) {
  64                                        ret = -ERESTARTSYS;
  65                                        break;
  66                                }
  67                                if (!list->hidraw->exist) {
  68                                        ret = -EIO;
  69                                        break;
  70                                }
  71
  72                                /* allow O_NONBLOCK to work well 
from other threads */
  73                                mutex_unlock(&list->read_mutex);
  74                                schedule();
  75                                mutex_lock(&list->read_mutex);
  76                                set_current_state
(TASK_INTERRUPTIBLE);
  77                        }
  78
  79                        set_current_state(TASK_RUNNING);
  80                        remove_wait_queue(&list->hidraw->wait, 
&wait);
  81                }
  82
  83                if (ret)
  84                        goto out;
  85
  86                report = list->buffer[list->tail].value;
  87                len = list->buffer[list->tail].len > count ?
  88                        count : list->buffer[list->tail].len;
  89
  90                if (copy_to_user(buffer, list->buffer[list-
>tail].value, len)) {
  91                        ret = -EFAULT;
  92                        goto out;
  93                }
  94                ret += len;
  95
  96                kfree(list->buffer[list->tail].value);
  97                list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE 
- 1);
  98        }
  99out:
 100        mutex_unlock(&list->read_mutex);
 101        return ret;
 102}




             reply	other threads:[~2009-10-12  9:09 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-12 13:11 iceberg [this message]
2009-10-12  9:25 ` [BUG] hidraw.c: double mutex_lock Jiri Kosina

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1255353109.13239.0@pamir \
    --to=iceberg@ispras.ru \
    --cc=jkosina@suse.cz \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox