]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.14/staging-comedi-ni_mio_common-fix-divide-by-zero-for-dio-cmdtest.patch
Linux 4.9.167
[thirdparty/kernel/stable-queue.git] / queue-4.14 / staging-comedi-ni_mio_common-fix-divide-by-zero-for-dio-cmdtest.patch
1 From bafd9c64056cd034a1174dcadb65cd3b294ff8f6 Mon Sep 17 00:00:00 2001
2 From: Ian Abbott <abbotti@mev.co.uk>
3 Date: Mon, 4 Mar 2019 14:33:54 +0000
4 Subject: staging: comedi: ni_mio_common: Fix divide-by-zero for DIO cmdtest
5
6 From: Ian Abbott <abbotti@mev.co.uk>
7
8 commit bafd9c64056cd034a1174dcadb65cd3b294ff8f6 upstream.
9
10 `ni_cdio_cmdtest()` validates Comedi asynchronous commands for the DIO
11 subdevice (subdevice 2) of supported National Instruments M-series
12 cards. It is called when handling the `COMEDI_CMD` and `COMEDI_CMDTEST`
13 ioctls for this subdevice. There are two causes for a possible
14 divide-by-zero error when validating that the `stop_arg` member of the
15 passed-in command is not too large.
16
17 The first cause for the divide-by-zero is that calls to
18 `comedi_bytes_per_scan()` are only valid once the command has been
19 copied to `s->async->cmd`, but that copy is only done for the
20 `COMEDI_CMD` ioctl. For the `COMEDI_CMDTEST` ioctl, it will use
21 whatever was left there by the previous `COMEDI_CMD` ioctl, if any.
22 (This is very likely, as it is usual for the application to use
23 `COMEDI_CMDTEST` before `COMEDI_CMD`.) If there has been no previous,
24 valid `COMEDI_CMD` for this subdevice, then `comedi_bytes_per_scan()`
25 will return 0, so the subsequent division in `ni_cdio_cmdtest()` of
26 `s->async->prealloc_bufsz / comedi_bytes_per_scan(s)` will be a
27 divide-by-zero error. To fix this error, call a new function
28 `comedi_bytes_per_scan_cmd(s, cmd)`, based on the existing
29 `comedi_bytes_per_scan(s)` but using a specified `struct comedi_cmd` for
30 its calculations. (Also refactor `comedi_bytes_per_scan()` to call the
31 new function.)
32
33 Once the first cause for the divide-by-zero has been fixed, the second
34 cause is that `comedi_bytes_per_scan_cmd()` can legitimately return 0 if
35 the `scan_end_arg` member of the `struct comedi_cmd` being tested is 0.
36 Fix it by only performing the division (and validating that `stop_arg`
37 is no more than the maximum value) if `comedi_bytes_per_scan_cmd()`
38 returns a non-zero value.
39
40 The problem was reported on the COMEDI mailing list here:
41 https://groups.google.com/forum/#!topic/comedi_list/4t9WlHzMhKM
42
43 Reported-by: Ivan Vasilyev <grabesstimme@gmail.com>
44 Tested-by: Ivan Vasilyev <grabesstimme@gmail.com>
45 Fixes: f164cbf98fa8 ("staging: comedi: ni_mio_common: add finite regeneration to dio output")
46 Cc: <stable@vger.kernel.org> # 4.6+
47 Cc: Spencer E. Olson <olsonse@umich.edu>
48 Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
49 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
50
51 ---
52 drivers/staging/comedi/comedidev.h | 2 +
53 drivers/staging/comedi/drivers.c | 33 +++++++++++++++++++++----
54 drivers/staging/comedi/drivers/ni_mio_common.c | 10 +++++--
55 3 files changed, 38 insertions(+), 7 deletions(-)
56
57 --- a/drivers/staging/comedi/comedidev.h
58 +++ b/drivers/staging/comedi/comedidev.h
59 @@ -992,6 +992,8 @@ int comedi_dio_insn_config(struct comedi
60 unsigned int mask);
61 unsigned int comedi_dio_update_state(struct comedi_subdevice *s,
62 unsigned int *data);
63 +unsigned int comedi_bytes_per_scan_cmd(struct comedi_subdevice *s,
64 + struct comedi_cmd *cmd);
65 unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s);
66 unsigned int comedi_nscans_left(struct comedi_subdevice *s,
67 unsigned int nscans);
68 --- a/drivers/staging/comedi/drivers.c
69 +++ b/drivers/staging/comedi/drivers.c
70 @@ -390,11 +390,13 @@ unsigned int comedi_dio_update_state(str
71 EXPORT_SYMBOL_GPL(comedi_dio_update_state);
72
73 /**
74 - * comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes
75 + * comedi_bytes_per_scan_cmd() - Get length of asynchronous command "scan" in
76 + * bytes
77 * @s: COMEDI subdevice.
78 + * @cmd: COMEDI command.
79 *
80 * Determines the overall scan length according to the subdevice type and the
81 - * number of channels in the scan.
82 + * number of channels in the scan for the specified command.
83 *
84 * For digital input, output or input/output subdevices, samples for
85 * multiple channels are assumed to be packed into one or more unsigned
86 @@ -404,9 +406,9 @@ EXPORT_SYMBOL_GPL(comedi_dio_update_stat
87 *
88 * Returns the overall scan length in bytes.
89 */
90 -unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
91 +unsigned int comedi_bytes_per_scan_cmd(struct comedi_subdevice *s,
92 + struct comedi_cmd *cmd)
93 {
94 - struct comedi_cmd *cmd = &s->async->cmd;
95 unsigned int num_samples;
96 unsigned int bits_per_sample;
97
98 @@ -423,6 +425,29 @@ unsigned int comedi_bytes_per_scan(struc
99 }
100 return comedi_samples_to_bytes(s, num_samples);
101 }
102 +EXPORT_SYMBOL_GPL(comedi_bytes_per_scan_cmd);
103 +
104 +/**
105 + * comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes
106 + * @s: COMEDI subdevice.
107 + *
108 + * Determines the overall scan length according to the subdevice type and the
109 + * number of channels in the scan for the current command.
110 + *
111 + * For digital input, output or input/output subdevices, samples for
112 + * multiple channels are assumed to be packed into one or more unsigned
113 + * short or unsigned int values according to the subdevice's %SDF_LSAMPL
114 + * flag. For other types of subdevice, samples are assumed to occupy a
115 + * whole unsigned short or unsigned int according to the %SDF_LSAMPL flag.
116 + *
117 + * Returns the overall scan length in bytes.
118 + */
119 +unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
120 +{
121 + struct comedi_cmd *cmd = &s->async->cmd;
122 +
123 + return comedi_bytes_per_scan_cmd(s, cmd);
124 +}
125 EXPORT_SYMBOL_GPL(comedi_bytes_per_scan);
126
127 static unsigned int __comedi_nscans_left(struct comedi_subdevice *s,
128 --- a/drivers/staging/comedi/drivers/ni_mio_common.c
129 +++ b/drivers/staging/comedi/drivers/ni_mio_common.c
130 @@ -3523,6 +3523,7 @@ static int ni_cdio_check_chanlist(struct
131 static int ni_cdio_cmdtest(struct comedi_device *dev,
132 struct comedi_subdevice *s, struct comedi_cmd *cmd)
133 {
134 + unsigned int bytes_per_scan;
135 int err = 0;
136 int tmp;
137
138 @@ -3552,9 +3553,12 @@ static int ni_cdio_cmdtest(struct comedi
139 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
140 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
141 cmd->chanlist_len);
142 - err |= comedi_check_trigger_arg_max(&cmd->stop_arg,
143 - s->async->prealloc_bufsz /
144 - comedi_bytes_per_scan(s));
145 + bytes_per_scan = comedi_bytes_per_scan_cmd(s, cmd);
146 + if (bytes_per_scan) {
147 + err |= comedi_check_trigger_arg_max(&cmd->stop_arg,
148 + s->async->prealloc_bufsz /
149 + bytes_per_scan);
150 + }
151
152 if (err)
153 return 3;