Hello Andrzej Pietrasiewicz,
The patch 83167f12da05: "usb: gadget: nokia: convert to new interface
of f_phonet" from May 23, 2013, leads to the following Smatch
warnings:
drivers/usb/gadget/nokia.c:209 nokia_bind_config() error: potential NULL
dereference 'f_obex2'.
drivers/usb/gadget/nokia.c:211 nokia_bind_config() error: potential NULL
dereference 'f_obex1'.
drivers/usb/gadget/nokia.c:213 nokia_bind_config() error: potential NULL
dereference 'f_phonet'.
Let me walk you throug the code for the first warning.
drivers/usb/gadget/nokia.c
115 static struct usb_function_instance *fi_acm;
116 static struct usb_function_instance *fi_ecm;
117 static struct usb_function_instance *fi_obex1;
118 static struct usb_function_instance *fi_obex2;
119 static struct usb_function_instance *fi_phonet;
120
121 static int __init nokia_bind_config(struct usb_configuration *c)
122 {
123 struct usb_function *f_acm;
124 struct usb_function *f_phonet = NULL;
125 struct usb_function *f_obex1 = NULL;
126 struct usb_function *f_ecm;
127 struct usb_function *f_obex2 = NULL;
128 int status = 0;
129 int obex1_stat = 0;
130 int obex2_stat = 0;
131 int phonet_stat = 0;
We need to trace three variables to understand the first warning
message: fi_obex2, f_obex2, and obex2_stat.
Lets start with the assumption that "fi_obex2" is an error pointer at
the start of the function.
f_obex2 is NULL.
obex2_stat is zero.
132
133 if (!IS_ERR(fi_phonet)) {
134 f_phonet = usb_get_function(fi_phonet);
135 if (IS_ERR(f_phonet))
136 pr_debug("could not get phonet function\n");
137 }
138
139 if (!IS_ERR(fi_obex1)) {
140 f_obex1 = usb_get_function(fi_obex1);
141 if (IS_ERR(f_obex1))
142 pr_debug("could not get obex function 0\n");
It's funny that the human readable messages start counting from zero as
in "obex function 0" and "obex function 1" but the computer code starts
counting from 1 as in "fi_obex1" and "fi_obex2". Normally you would
expect it to be the other way around. Also this is not consistent with
the rest of the driver.
143 }
144
145 if (!IS_ERR(fi_obex2)) {
146 f_obex2 = usb_get_function(fi_obex2);
147 if (IS_ERR(f_obex2))
148 pr_debug("could not get obex function 1\n");
149 }
fi_obex2 is an error pointer.
f_obex2 is NULL.
obex2_stat is zero.
150
151 f_acm = usb_get_function(fi_acm);
152 if (IS_ERR(f_acm)) {
153 status = PTR_ERR(f_acm);
154 goto err_get_acm;
155 }
156
157 f_ecm = usb_get_function(fi_ecm);
158 if (IS_ERR(f_ecm)) {
159 status = PTR_ERR(f_ecm);
160 goto err_get_ecm;
161 }
162
163 if (!IS_ERR_OR_NULL(f_phonet)) {
164 phonet_stat = usb_add_function(c, f_phonet);
165 if (phonet_stat)
166 pr_debug("could not add phonet function\n");
167 }
168
169 if (!IS_ERR_OR_NULL(f_obex1)) {
170 obex1_stat = usb_add_function(c, f_obex1);
171 if (obex1_stat)
172 pr_debug("could not add obex function 0\n");
173 }
174
175 if (!IS_ERR_OR_NULL(f_obex2)) {
176 obex2_stat = usb_add_function(c, f_obex2);
177 if (obex2_stat)
178 pr_debug("could not add obex function 1\n");
179 }
f_obex2 is NULL so the condition is false.
obex2_stat is zero.
180
181 status = usb_add_function(c, f_acm);
182 if (status)
183 goto err_conf;
Let's assume we hit this goto.
184
185 status = usb_add_function(c, f_ecm);
186 if (status) {
187 pr_debug("could not bind ecm config %d\n", status);
188 goto err_ecm;
189 }
190 if (c == &nokia_config_500ma_driver) {
191 f_acm_cfg1 = f_acm;
192 f_ecm_cfg1 = f_ecm;
193 f_phonet_cfg1 = f_phonet;
194 f_obex1_cfg1 = f_obex1;
195 f_obex2_cfg1 = f_obex2;
196 } else {
197 f_acm_cfg2 = f_acm;
198 f_ecm_cfg2 = f_ecm;
199 f_phonet_cfg2 = f_phonet;
200 f_obex1_cfg2 = f_obex1;
201 f_obex2_cfg2 = f_obex2;
Btw, we are assigning an ERR_PTR to the global here. It means we need
to constantly check it, which the code does, but it's messy. The driver
would be cleaner if we never did this.
202 }
203
204 return status;
Just "return 0" here to make it more obvious that we are returning zero.
205 err_ecm:
206 usb_remove_function(c, f_acm);
207 err_conf:
208 if (!obex2_stat)
209 usb_remove_function(c, f_obex2);
obex2_stat is zero.
f_obex2 is NULL.
This causes a NULL dereference.
We could initialize obex2_stat to -1 instead of 0 which would fix the
NULL deref but the real problem is that this code is quite messy.
We should be clearing the ERR_PTRs right away if we aren't going to use
the values.
f_obex1 = usb_get_function(fi_obex1);
if (IS_ERR(f_obex1)) {
pr_debug("could not get obex function 0\n");
f_obex1 = NULL;
}
I'm not very familiar with this hardware, why is it not an error when
the usb_get_function() and usb_add_function() calls fail?
210 if (!obex1_stat)
211 usb_remove_function(c, f_obex1);
212 if (!phonet_stat)
213 usb_remove_function(c, f_phonet);
214 usb_put_function(f_ecm);
215 err_get_ecm:
216 usb_put_function(f_acm);
217 err_get_acm:
218 if (!IS_ERR_OR_NULL(f_obex2))
219 usb_put_function(f_obex2);
220 if (!IS_ERR_OR_NULL(f_obex1))
221 usb_put_function(f_obex1);
222 if (!IS_ERR_OR_NULL(f_phonet))
223 usb_put_function(f_phonet);
224 return status;
225 }
regards,
dan carpenter
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html