lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4F0B55E7.1070909@synaptics.com>
Date:	Mon, 9 Jan 2012 13:02:31 -0800
From:	Christopher Heiny <cheiny@...aptics.com>
To:	Dmitry Torokhov <dmitry.torokhov@...il.com>
CC:	Jean Delvare <khali@...ux-fr.org>,
	Linux Kernel <linux-kernel@...r.kernel.org>,
	Linux Input <linux-input@...r.kernel.org>,
	Joerie de Gram <j.de.gram@...il.com>,
	Linus Walleij <linus.walleij@...ricsson.com>,
	Naveen Kumar Gaddipati <naveen.gaddipati@...ricsson.com>,
	Vivian Ly <vly@...aptics.com>
Subject: Re: [RFC PATCH 10/11] input: RMI4 F19 - capacitive buttons

On 01/05/2012 06:50 PM, Dmitry Torokhov wrote:
> On Thu, Jan 05, 2012 at 04:05:43PM -0800, Christopher Heiny wrote:
>> On 01/04/2012 11:53 PM, Dmitry Torokhov wrote:
>>> Hi Christopher,
>>>
>>> On Wed, Dec 21, 2011 at 06:10:01PM -0800, Christopher Heiny wrote:
>>>> +
>>>> +struct f19_0d_control {
>>>> +	struct f19_0d_control_0 *general_control;
>>>
>>> Single instance, does not need to be allocated separately.
>>>
>>>> +	struct f19_0d_control_1 *button_int_enable;
>>>> +	struct f19_0d_control_2 *single_button_participation;
>>>> +	struct f19_0d_control_3_4 *sensor_map;
>>>
>>> This should probably be an array of
>>>
>>> struct f19_button_ctrl {
>>> 	struct f19_0d_control_1 int_enable;
>>> 	struct f19_0d_control_2 participation;
>>> 	struct f19_0d_control_3_4 sensor_map;
>>> };
>>>
>>> located at the end of f19_0d_control structure so it can be all
>>> allocated in one shot.
>>
>> We organized it this way because of how the controls are organized
>> in the register map: first the interrupt enables for all buttons,
>> then the participation for all buttons, and then the sensor map for
>> all buttons.  Typical client interactions are to adjust these in an
>> "all at once" approach - that is, change as a single group all the
>> interrupt enables, all the participation settings, or all the sensor
>> map.  By organizing them the way we did, it makes it very easy to
>> read/write the data to the RMI4 sensor's register map.  Using an
>> array of structs would require a building buffers (on write) or
>> tedious extraction from buffers (on read).
>>
>> However, the first two of these are bitmasks, and don't really need
>> their own structs - they can conveniently be u8 * instead.
>
> I'll try coding something to show that it is not as bad as it seems...

OK, we'll look forward to that.

[snip]

>
>>>> +
>>>> +static struct device_attribute attrs[] = {
>>>> +	__ATTR(button_count, RMI_RO_ATTR,
>>>> +		rmi_f19_button_count_show, rmi_store_error),
>>>
>>> Why not NULL instead of rmi_store_error?
>>
>> We found that customers picking up our driver would try to write RO
>> sysfs attributes (or read WO attrs) by invoking echo from the
>> command line.  The operation would fail silently (I'm looking at
>> you, Android shell), leaving the engineer baffled as to why the
>> sensor behavior didn't change.  So we adopted this approach so as to
>> give some clue as to the fact that the operation failed.
>
> But this ends up in various logs (dmesg, /var/log/messages, etc) making
> it potentially DOS scenario. Please help fixing tools instead.

I see your point about the DOS scenario.  How about we do this: make the 
rmi_store/show_error routines a #define, that normally is set to NULL, 
but have an optional debug flag (RMI4_SYSFS_DEBUG) that uses these 
verbose functions.

>
>>>> +
>>>> +	f19->button_control->single_button_participation =
>>>> +		kzalloc(f19->button_data_buffer_size *
>>>> +			sizeof(struct f19_0d_control_2), GFP_KERNEL);
>>>> +	if (!f19->button_control->single_button_participation) {
>>>> +		dev_err(&fc->dev, "Failed to allocate"
>>>> +			" f19_0d_control_2.\n");
>>>
>>> Do not split error messages; it's OK if they exceed 80 column limit.
>>
>> We have one customer who refuses to accept any code if any line
>> exceeds 80 columns, so we wind up with ugliness like this.
>
> This is contrary to current kernel policy though
> (Documentation/CodingStyle, ch 2):
>
> "However, never break user-visible strings such as
> printk messages, because that breaks the ability to grep for them."

Yes, but then checkpatch.pl whines about them, which is also 
unacceptable to that customer.  However, at this point I think 
usefulness takes priority, so we'll unbreak those strings.

[snip]

>>>> +
>>>> +	/* Generate events for buttons that change state. */
>>>> +	for (button = 0; button<   f19->button_count;
>>>> +	     button++) {
>>>> +		int button_reg;
>>>> +		int button_shift;
>>>> +		bool button_status;
>>>> +
>>>> +		/* determine which data byte the button status is in */
>>>> +		button_reg = button / 7;
>>>> +		/* bit shift to get button's status */
>>>> +		button_shift = button % 8;
>>>> +		button_status =
>>>> +		    ((f19->button_data_buffer[button_reg]>>   button_shift)
>>>> +			&   0x01) != 0;
>>>> +
>>>> +		/* if the button state changed from the last time report it
>>>> +		 * and store the new state */
>>>> +		if (button_status != f19->button_down[button]) {
>>>> +			dev_dbg(&fc->dev, "%s: Button %d (code %d) ->   %d.\n",
>>>> +				__func__, button, f19->button_map[button],
>>>> +				 button_status);
>>>> +			/* Generate an event here. */
>>>> +			input_report_key(f19->input, f19->button_map[button],
>>>> +					 button_status);
>>>> +			f19->button_down[button] = button_status;
>>>> +		}
>>>> +	}
>>>
>>> All of the above could be reduced to:
>>>
>>> 	for (button = 0; button<   f19->button_count; button++)
>>> 		input_report_key(f19->input, f19->button_map[button],
>>> 				 test_bit(button, f19->button_data_buffer);
>>
>> I'd like to, but I'm not sure - can we count on the endian-ness of
>> the host processor being the same as the RMI4 register endian-ness?
>
> Hmm, I'd expect RMI transport functions take care of converting into
> proper endianness.

If I can convince myself that it will never do something surprising, 
we'll implement that.

>
>>
>> [snip]
>>
>>>> +
>>>> +static ssize_t rmi_f19_sensor_map_store(struct device *dev,
>>>> +					 struct device_attribute *attr,
>>>> +					 const char *buf, size_t count)
>>>> +{
>>>> +	struct rmi_function_container *fc;
>>>> +	struct f19_data *data;
>>>> +	int sensor_map;
>>>> +	int i;
>>>> +	int retval = count;
>>>> +	int button_count = 0;
>>>> +	int ctrl_bass_addr;
>>>> +	int button_reg;
>>>> +	fc = to_rmi_function_container(dev);
>>>> +	data = fc->data;
>>>> +
>>>> +	if (data->button_query.configurable == 0) {
>>>> +		dev_err(dev,
>>>> +			"%s: Error - sensor map is not configuralbe at"
>>>> +			" run-time", __func__);
>>>
>>> This is not driver error, return error silently.
>>
>> I don't like failing silently, for reasons outlined above.
>
> And for the reason also outlined above I disagree. Driver errors
> (especially KERNEL_ERR level) should be used to signal conditions when
> driver either can't continue or its functionality is seriously impaired.
> Bad user input does not qualify here.

I think switching to the attribute groups will eliminate this particular 
case, along with a few others.  We'll switch others to warning, which is 
a more appropriate level, and look at making them conditional (default 
to silent).

[snip]

>>>> +static ssize_t rmi_f19_button_map_store(struct device *dev,
>>>> +				struct device_attribute *attr,
>>>> +				const char *buf,
>>>> +				size_t count)
>>>> +{
>>>> +	struct rmi_function_container *fc;
>>>> +	struct f19_data *data;
>>>> +	unsigned int button;
>>>> +	int i;
>>>> +	int retval = count;
>>>> +	int button_count = 0;
>>>> +	unsigned char temp_button_map[KEY_MAX];
>>>> +
>>>> +	fc = to_rmi_function_container(dev);
>>>> +	data = fc->data;
>>>> +
>>>> +	/* Do validation on the button map data passed in.  Store button
>>>> +	 * mappings into a temp buffer and then verify button count and
>>>> +	 * data prior to clearing out old button mappings and storing the
>>>> +	 * new ones. */
>>>> +	for (i = 0; i<   data->button_count&&   *buf != 0;
>>>> +	     i++) {
>>>> +		/* get next button mapping value and store and bump up to
>>>> +		 * point to next item in buf */
>>>> +		sscanf(buf, "%u",&button);
>>>> +
>>>> +		/* Make sure the key is a valid key */
>>>> +		if (button>   KEY_MAX) {
>>>> +			dev_err(dev,
>>>> +				"%s: Error - button map for button %d is not a"
>>>> +				" valid value 0x%x.\n", __func__, i, button);
>>>> +			retval = -EINVAL;
>>>> +			goto err_ret;
>>>> +		}
>>>> +
>>>> +		temp_button_map[i] = button;
>>>> +		button_count++;
>>>> +
>>>> +		/* bump up buf to point to next item to read */
>>>> +		while (*buf != 0) {
>>>> +			buf++;
>>>> +			if (*(buf - 1) == ' ')
>>>> +				break;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	/* Make sure the button count matches */
>>>> +	if (button_count != data->button_count) {
>>>> +		dev_err(dev,
>>>> +		    "%s: Error - button map count of %d doesn't match device "
>>>> +		     "button count of %d.\n", __func__, button_count,
>>>> +		     data->button_count);
>>>> +		retval = -EINVAL;
>>>> +		goto err_ret;
>>>> +	}
>>>> +
>>>> +	/* Clear the key bits for the old button map. */
>>>> +	for (i = 0; i<   button_count; i++)
>>>> +		clear_bit(data->button_map[i], data->input->keybit);
>>>> +
>>>> +	/* Switch to the new map. */
>>>> +	memcpy(data->button_map, temp_button_map,
>>>> +	       data->button_count);
>>>> +
>>>> +	/* Loop through the key map and set the key bit for the new mapping. */
>>>> +	for (i = 0; i<   button_count; i++)
>>>> +		set_bit(data->button_map[i], data->input->keybit);
>>>> +
>>>> +err_ret:
>>>> +	return retval;
>>>> +}
>>>
>>> Button map (keymap) should be manipulated with EVIOCGKEYCODE and
>>> EVIOCSKEYCODE ioctls, no need to invent driver-specific way of doing
>>> this.
>>
>> Makes sense, but... we had a customer request to specify the
>> boot-time keymap through the RMI4 driver's platform data.  Is it
>> legal to call setkeycode() to do that instead?
>
> No, the input device should be fully registered for that... But you can
> supply initial keymap in platform data, almost all drivers do that. It
> is new sysfs interface I object to here.

Thanks - we'll study this more closely.  I agree with not having another 
sysfs interface if the functionality is already there.  We just don't 
always realize that there is already an existing interface.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ