aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-10-14 02:37:30 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-10-14 03:36:33 -0400
commit1572ca2a842a839b78780d9074d2f140b31907cc (patch)
tree1628fd4699c8bd685cef8d47906af7eee05efc7a
parent94dfb0d6334a281a979fe5bee187a3698a4dc176 (diff)
Input: fix locking issue in /proc/bus/input/ handlers
input_devices_seq_start() uses mutex_lock_interruptible() to acquire the input_mutex, but doesn't properly handle the situation when the call fails (for example due to interrupt). Instead of returning NULL (which indicates that there is no more data) we should return ERR_PTR()-encoded error. We also need explicit flag indicating whether input_mutex was acquired since input_devices_seq_stop() is called whether input_devices_seq_start() was successful or not. The same applies to input_handlers_seq_start(). Reported-by: iceberg <strakh@ispras.ru> Reviewed-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/input.c65
1 files changed, 48 insertions, 17 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c
index b8ed4294fccd..60a4eaabb7d7 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -781,10 +781,29 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
781 return 0; 781 return 0;
782} 782}
783 783
784union input_seq_state {
785 struct {
786 unsigned short pos;
787 bool mutex_acquired;
788 };
789 void *p;
790};
791
784static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos) 792static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
785{ 793{
786 if (mutex_lock_interruptible(&input_mutex)) 794 union input_seq_state *state = (union input_seq_state *)&seq->private;
787 return NULL; 795 int error;
796
797 /* We need to fit into seq->private pointer */
798 BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
799
800 error = mutex_lock_interruptible(&input_mutex);
801 if (error) {
802 state->mutex_acquired = false;
803 return ERR_PTR(error);
804 }
805
806 state->mutex_acquired = true;
788 807
789 return seq_list_start(&input_dev_list, *pos); 808 return seq_list_start(&input_dev_list, *pos);
790} 809}
@@ -794,9 +813,12 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
794 return seq_list_next(v, &input_dev_list, pos); 813 return seq_list_next(v, &input_dev_list, pos);
795} 814}
796 815
797static void input_devices_seq_stop(struct seq_file *seq, void *v) 816static void input_seq_stop(struct seq_file *seq, void *v)
798{ 817{
799 mutex_unlock(&input_mutex); 818 union input_seq_state *state = (union input_seq_state *)&seq->private;
819
820 if (state->mutex_acquired)
821 mutex_unlock(&input_mutex);
800} 822}
801 823
802static void input_seq_print_bitmap(struct seq_file *seq, const char *name, 824static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
@@ -860,7 +882,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
860static const struct seq_operations input_devices_seq_ops = { 882static const struct seq_operations input_devices_seq_ops = {
861 .start = input_devices_seq_start, 883 .start = input_devices_seq_start,
862 .next = input_devices_seq_next, 884 .next = input_devices_seq_next,
863 .stop = input_devices_seq_stop, 885 .stop = input_seq_stop,
864 .show = input_devices_seq_show, 886 .show = input_devices_seq_show,
865}; 887};
866 888
@@ -880,40 +902,49 @@ static const struct file_operations input_devices_fileops = {
880 902
881static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos) 903static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
882{ 904{
883 if (mutex_lock_interruptible(&input_mutex)) 905 union input_seq_state *state = (union input_seq_state *)&seq->private;
884 return NULL; 906 int error;
907
908 /* We need to fit into seq->private pointer */
909 BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
910
911 error = mutex_lock_interruptible(&input_mutex);
912 if (error) {
913 state->mutex_acquired = false;
914 return ERR_PTR(error);
915 }
916
917 state->mutex_acquired = true;
918 state->pos = *pos;
885 919
886 seq->private = (void *)(unsigned long)*pos;
887 return seq_list_start(&input_handler_list, *pos); 920 return seq_list_start(&input_handler_list, *pos);
888} 921}
889 922
890static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos) 923static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
891{ 924{
892 seq->private = (void *)(unsigned long)(*pos + 1); 925 union input_seq_state *state = (union input_seq_state *)&seq->private;
893 return seq_list_next(v, &input_handler_list, pos);
894}
895 926
896static void input_handlers_seq_stop(struct seq_file *seq, void *v) 927 state->pos = *pos + 1;
897{ 928 return seq_list_next(v, &input_handler_list, pos);
898 mutex_unlock(&input_mutex);
899} 929}
900 930
901static int input_handlers_seq_show(struct seq_file *seq, void *v) 931static int input_handlers_seq_show(struct seq_file *seq, void *v)
902{ 932{
903 struct input_handler *handler = container_of(v, struct input_handler, node); 933 struct input_handler *handler = container_of(v, struct input_handler, node);
934 union input_seq_state *state = (union input_seq_state *)&seq->private;
904 935
905 seq_printf(seq, "N: Number=%ld Name=%s", 936 seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
906 (unsigned long)seq->private, handler->name);
907 if (handler->fops) 937 if (handler->fops)
908 seq_printf(seq, " Minor=%d", handler->minor); 938 seq_printf(seq, " Minor=%d", handler->minor);
909 seq_putc(seq, '\n'); 939 seq_putc(seq, '\n');
910 940
911 return 0; 941 return 0;
912} 942}
943
913static const struct seq_operations input_handlers_seq_ops = { 944static const struct seq_operations input_handlers_seq_ops = {
914 .start = input_handlers_seq_start, 945 .start = input_handlers_seq_start,
915 .next = input_handlers_seq_next, 946 .next = input_handlers_seq_next,
916 .stop = input_handlers_seq_stop, 947 .stop = input_seq_stop,
917 .show = input_handlers_seq_show, 948 .show = input_handlers_seq_show,
918}; 949};
919 950