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] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 4 Dec 2019 15:10:23 +0800
From:   "Johnny.Chuang" <johnny.chuang@....com.tw>
To:     "'Dmitry Torokhov'" <dmitry.torokhov@...il.com>
Cc:     <linux-kernel@...r.kernel.org>, <linux-input@...r.kernel.org>,
        'STRD2-蔡惠嬋' <jennifer.tsai@....com.tw>,
        <james.chen@....com.tw>,
        '梁博翔' <paul.liang@....com.tw>,
        "'jeff'" <jeff.chuang@....com.tw>
Subject: RE: [PATCH] Input: elants_i2c - Add Remark ID check flow in firmware update function

Hi Dmitry,

I had modified driver and responded you inline.

Many thanks,
Johnny

diff --git a/drivers/input/touchscreen/elants_i2c.c
b/drivers/input/touchscreen/elants_i2c.c
index 9a17af6..4911799 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -130,7 +130,6 @@ struct elants_data {
        u8 bc_version;
        u8 iap_version;
        u16 hw_version;
-       u16 remark_id;
        unsigned int x_res;     /* resolution in units/mm */
        unsigned int y_res;
        unsigned int x_max;
@@ -620,47 +619,33 @@ static int elants_i2c_fw_write_page(struct i2c_client
*client,
        return error;
 }

-static int elants_i2c_query_remark_id(struct elants_data *ts)
-{
-       struct i2c_client *client = ts->client;
-       int error;
-       const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21
};
-       u8 resp[6] = { 0 };
-
-       error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
-                                       resp, sizeof(resp));
-       if (error) {
-               dev_err(&client->dev, "get Remark ID failed: %d.\n", error);
-               return error;
-       }
-
-       ts->remark_id = get_unaligned_be16(&resp[3]);
-       dev_info(&client->dev, "remark_id=0x%04x.\n", ts->remark_id);
-
-       return 0;
-}
-
 static int elants_i2c_validate_remark_id(struct elants_data *ts,
                                         const struct firmware *fw)
 {
        struct i2c_client *client = ts->client;
        int error;
+       const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21
};
+       u8 resp[6] = { 0 };
+       u16 ts_remark_id = 0;
        u16 fw_remark_id = 0;

        /* Compare TS Remark ID and FW Remark ID */
-       error = elants_i2c_query_remark_id(ts);
+       error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
+                                       resp, sizeof(resp));
        if (error) {
                dev_err(&client->dev, "failed to query Remark ID: %d\n",
error);
                return error;
        }

+       ts_remark_id = get_unaligned_be16(&resp[3]);
+
        fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]);
-       dev_info(&client->dev, "fw_remark_id=0x%04x.\n", fw_remark_id);
-       if (fw_remark_id != ts->remark_id) {
+
+       if (fw_remark_id != ts_remark_id) {
                dev_err(&client->dev,
-                       "Remark ID Mismatched: ts_remark_id=0x%04x,
fw_remark_id=0x%x.\n",
-                       ts->remark_id, fw_remark_id);
-               return -ENODATA;
+                       "Remark ID Mismatched: ts_remark_id=0x%04x,
fw_remark_id=0x%04x.\n",
+                       ts_remark_id, fw_remark_id);
+               return -EINVAL;
        }

        return 0;
@@ -671,7 +656,6 @@ static int elants_i2c_do_update_firmware(struct
i2c_client *client,
                                         bool force)
 {
        struct elants_data *ts = i2c_get_clientdata(client);
-       static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A };
        const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 };
        const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 };
        const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc };
@@ -686,29 +670,18 @@ static int elants_i2c_do_update_firmware(struct
i2c_client *client,
        if (force) {
                dev_dbg(&client->dev, "Recovery mode procedure\n");

-               if (check_remark_id == true) {
-                       /* Validate Remark ID */
+               if (check_remark_id) {
                        error = elants_i2c_validate_remark_id(ts, fw);
-                       if (error) {
-                               dev_err(&client->dev,
-                                       "failed to validate Remark ID:
%d\n",
-                                       error);
+                       if (error)
                                return error;
-                       }
                }

-               error = elants_i2c_send(client, w_flashkey,
sizeof(w_flashkey));
-               if (error)
-                       dev_err(&client->dev, "failed to write flash key:
%d\n",
-                               error);
-
                error = elants_i2c_send(client, enter_iap2,
sizeof(enter_iap2));
                if (error) {
                        dev_err(&client->dev, "failed to enter IAP mode:
%d\n",
                                error);
                        return error;
                }
-               msleep(20);
        } else {
                /* Start IAP Procedure */
                dev_dbg(&client->dev, "Normal IAP procedure\n");
@@ -722,14 +695,10 @@ static int elants_i2c_do_update_firmware(struct
i2c_client *client,
                elants_i2c_sw_reset(client);
                msleep(20);

-               if (check_remark_id == true) {
-                       /* Validate Remark ID */
+               if (check_remark_id) {
                        error = elants_i2c_validate_remark_id(ts, fw);
-                       if (error) {
-                               dev_err(&client->dev, "failed to validate
Remark ID: %d\n",
-                                       error);
+                       if (error)
                                return error;
-                       }
                }

                error = elants_i2c_send(client, enter_iap,
sizeof(enter_iap));

-----Original Message-----
From: 'Dmitry Torokhov' [mailto:dmitry.torokhov@...il.com] 
Sent: Wednesday, December 04, 2019 3:48 AM
To: Johnny.Chuang
Cc: linux-kernel@...r.kernel.org; linux-input@...r.kernel.org; STRD2-蔡惠嬋;
james.chen@....com.tw; '梁博翔'; 'jeff'
Subject: Re: [PATCH] Input: elants_i2c - Add Remark ID check flow in
firmware update function

Hi Johnny,

On Tue, Nov 19, 2019 at 01:59:45PM +0800, Johnny.Chuang wrote:
> This patch add Remark ID check flow to firmware update function of 
> elan touchscreen driver.
> 
> It avoids firmware update with mismatched Remark ID.
> 
> This function is supported by our latest version of boot code, but it 
> cooperates well with earlier versions.
> 
> Our driver will decide if enable Remark ID check with boot code version.
> 
> Signed-off-by: Johnny Chuang <johnny.chuang@....com.tw>
> ---
>  drivers/input/touchscreen/elants_i2c.c | 108
> ++++++++++++++++++++++++++++++---
>  1 file changed, 100 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/elants_i2c.c
> b/drivers/input/touchscreen/elants_i2c.c
> index d4ad24e..9a17af6 100644
> --- a/drivers/input/touchscreen/elants_i2c.c
> +++ b/drivers/input/touchscreen/elants_i2c.c
> @@ -59,8 +59,10 @@
>  #define CMD_HEADER_WRITE	0x54
>  #define CMD_HEADER_READ		0x53
>  #define CMD_HEADER_6B_READ	0x5B
> +#define CMD_HEADER_ROM_READ	0x96
>  #define CMD_HEADER_RESP		0x52
>  #define CMD_HEADER_6B_RESP	0x9B
> +#define CMD_HEADER_ROM_RESP	0x95
>  #define CMD_HEADER_HELLO	0x55
>  #define CMD_HEADER_REK		0x66
>  
> @@ -128,6 +130,7 @@ struct elants_data {
>  	u8 bc_version;
>  	u8 iap_version;
>  	u16 hw_version;
> +	u16 remark_id;

We only use this during firmware version check phase, no need to store it in
the device data structure.
[J]: I remove remark_id and move work of elants_i2c_query_remark_id() into
elants_i2c_validate_remark_id().

>  	unsigned int x_res;	/* resolution in units/mm */
>  	unsigned int y_res;
>  	unsigned int x_max;
> @@ -200,6 +203,10 @@ static int elants_i2c_execute_command(struct 
> i2c_client *client,
>  		expected_response = CMD_HEADER_6B_RESP;
>  		break;
>  
> +	case CMD_HEADER_ROM_READ:
> +		expected_response = CMD_HEADER_ROM_RESP;
> +		break;
> +
>  	default:
>  		dev_err(&client->dev, "%s: invalid command %*ph\n",
>  			__func__, (int)cmd_size, cmd);
> @@ -556,6 +563,8 @@ static int elants_i2c_initialize(struct 
> elants_data *ts)
>  
>  	/* hw version is available even if device in recovery state */
>  	error2 = elants_i2c_query_hw_version(ts);
> +	if (!error2)
> +		error2 = elants_i2c_query_bc_version(ts);

Can you please explain why this change is done? This does not seem to relate
to the "remark id" functionality. Should it be a separate change?
[J]: We use ts->iap_version as check_remark_id to run validate remark id
flow or not. Hence we need to get iap_version by elants_i2c_query_bc_version
not only on normal mode but also on recovery mode.

>  	if (!error)
>  		error = error2;
>  
> @@ -564,8 +573,6 @@ static int elants_i2c_initialize(struct elants_data
*ts)
>  	if (!error)
>  		error = elants_i2c_query_test_version(ts);
>  	if (!error)
> -		error = elants_i2c_query_bc_version(ts);
> -	if (!error)
>  		error = elants_i2c_query_ts_info(ts);
>  
>  	if (error)
> @@ -613,39 +620,124 @@ static int elants_i2c_fw_write_page(struct 
> i2c_client *client,
>  	return error;
>  }
>  
> +static int elants_i2c_query_remark_id(struct elants_data *ts) {
> +	struct i2c_client *client = ts->client;
> +	int error;
> +	const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21
> };
> +	u8 resp[6] = { 0 };
> +
> +	error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
> +					resp, sizeof(resp));
> +	if (error) {
> +		dev_err(&client->dev, "get Remark ID failed: %d.\n", error);
> +		return error;
> +	}
> +
> +	ts->remark_id = get_unaligned_be16(&resp[3]);
> +	dev_info(&client->dev, "remark_id=0x%04x.\n", ts->remark_id);

I do not think we need be this noisy. Either dev_dbg, or drop it completely.
[J]: drop done.

> +
> +	return 0;
> +}
> +
> +static int elants_i2c_validate_remark_id(struct elants_data *ts,
> +					 const struct firmware *fw)
> +{
> +	struct i2c_client *client = ts->client;
> +	int error;
> +	u16 fw_remark_id = 0;
> +
> +	/* Compare TS Remark ID and FW Remark ID */
> +	error = elants_i2c_query_remark_id(ts);
> +	if (error) {
> +		dev_err(&client->dev, "failed to query Remark ID: %d\n",
> error);
> +		return error;
> +	}
> +
> +	fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]);
> +	dev_info(&client->dev, "fw_remark_id=0x%04x.\n", fw_remark_id);

Please drop this dev_info().
[J]: drop done.

> +	if (fw_remark_id != ts->remark_id) {
> +		dev_err(&client->dev,
> +			"Remark ID Mismatched: ts_remark_id=0x%04x,
> fw_remark_id=0x%x.\n",

You can use "%#04x" to format with prefix.
[J]: Thanks for your recommendation. I still keep 0x%04x as other in this
driver. I will submit another patch for all prefix change later.

> +			ts->remark_id, fw_remark_id);
> +		return -ENODATA;

I'd say -EINVAL here.
[J]: change done.

> +	}
> +
> +	return 0;
> +}
> +
>  static int elants_i2c_do_update_firmware(struct i2c_client *client,
>  					 const struct firmware *fw,
>  					 bool force)
>  {
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A };
>  	const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 };
>  	const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 };
>  	const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc };
> -	const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01};
> +	const u8 close_idle[] = { 0x54, 0x2c, 0x01, 0x01 };
>  	u8 buf[HEADER_SIZE];
>  	u16 send_id;
>  	int page, n_fw_pages;
>  	int error;
> +	bool check_remark_id = ts->iap_version >= 0x60;
>  
>  	/* Recovery mode detection! */
>  	if (force) {
>  		dev_dbg(&client->dev, "Recovery mode procedure\n");
> +
> +		if (check_remark_id == true) {

Simply
		if (check_remark_id) {
[J]: change done.


> +			/* Validate Remark ID */

This comment is not needed, you named the function that you are calling
below well and its name describes what we are trying to do perfectly.
[J]: drop done.

> +			error = elants_i2c_validate_remark_id(ts, fw);
> +			if (error) {
> +				dev_err(&client->dev,
> +					"failed to validate Remark ID:
> %d\n",
> +					error);

elants_i2c_validate_remark_id() already gives necessary diagnostic, this
message is not needed.
[J]: drop done.

> +				return error;
> +			}
> +		}
> +
> +		error = elants_i2c_send(client, w_flashkey,
> sizeof(w_flashkey));
> +		if (error)
> +			dev_err(&client->dev, "failed to write flash key:
> %d\n",
> +				error);

Sending flashkey in this chunk seems to be another change not directly
related to the remark id. Why do we need this? Should it be split out?
[J]: drop done. It's for another change.

> +
>  		error = elants_i2c_send(client, enter_iap2,
sizeof(enter_iap2));
> +		if (error) {
> +			dev_err(&client->dev, "failed to enter IAP mode:
> %d\n",
> +				error);
> +			return error;
> +		}
> +		msleep(20);

We already have msleep(20) in the common path below, do we really need 2nd
one here?
[J]: drop done. It's typo.

>  	} else {
>  		/* Start IAP Procedure */
>  		dev_dbg(&client->dev, "Normal IAP procedure\n");
> +
>  		/* Close idle mode */
>  		error = elants_i2c_send(client, close_idle,
sizeof(close_idle));
>  		if (error)
>  			dev_err(&client->dev, "Failed close idle: %d\n",
error);
>  		msleep(60);
> +
>  		elants_i2c_sw_reset(client);
>  		msleep(20);
> -		error = elants_i2c_send(client, enter_iap,
> sizeof(enter_iap));
> -	}
>  
> -	if (error) {
> -		dev_err(&client->dev, "failed to enter IAP mode: %d\n",
> error);
> -		return error;
> +		if (check_remark_id == true) {

		if (check_remark_id) {

> +			/* Validate Remark ID */

Drop comment.
[J]: drop done.

> +			error = elants_i2c_validate_remark_id(ts, fw);
> +			if (error) {
> +				dev_err(&client->dev, "failed to validate
> Remark ID: %d\n",
> +					error);

Drop message.
[J]: drop done.

> +				return error;
> +			}
> +		}
> +
> +		error = elants_i2c_send(client, enter_iap,
> sizeof(enter_iap));
> +		if (error) {
> +			dev_err(&client->dev, "failed to enter IAP mode:
> %d\n",
> +				error);
> +			return error;
> +		}
>  	}
>  
>  	msleep(20);
> --
> 2.7.4
> 

Thanks.

--
Dmitry

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ