Skip to content

Commit 3c3673b

Browse files
vvfedorenkokuba-moo
authored andcommitted
ptp: ocp: Add firmware header checks
Right now it's possible to flash any kind of binary via devlink and break the card easily. This diff adds an optional header check when installing the firmware. Signed-off-by: Vadim Fedorenko <[email protected]> Signed-off-by: Jonathan Lemon <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent b88fdbb commit 3c3673b

File tree

1 file changed

+73
-5
lines changed

1 file changed

+73
-5
lines changed

drivers/ptp/ptp_ocp.c

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/i2c.h>
2020
#include <linux/mtd/mtd.h>
2121
#include <linux/nvmem-consumer.h>
22+
#include <linux/crc16.h>
2223

2324
#define PCI_VENDOR_ID_FACEBOOK 0x1d9b
2425
#define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400
@@ -213,6 +214,17 @@ struct ptp_ocp_flash_info {
213214
void *data;
214215
};
215216

217+
struct ptp_ocp_firmware_header {
218+
char magic[4];
219+
__be16 pci_vendor_id;
220+
__be16 pci_device_id;
221+
__be32 image_size;
222+
__be16 hw_revision;
223+
__be16 crc;
224+
};
225+
226+
#define OCP_FIRMWARE_MAGIC_HEADER "OCPC"
227+
216228
struct ptp_ocp_i2c_info {
217229
const char *name;
218230
unsigned long fixed_rate;
@@ -1323,25 +1335,81 @@ ptp_ocp_find_flash(struct ptp_ocp *bp)
13231335
return dev;
13241336
}
13251337

1338+
static int
1339+
ptp_ocp_devlink_fw_image(struct devlink *devlink, const struct firmware *fw,
1340+
const u8 **data, size_t *size)
1341+
{
1342+
struct ptp_ocp *bp = devlink_priv(devlink);
1343+
const struct ptp_ocp_firmware_header *hdr;
1344+
size_t offset, length;
1345+
u16 crc;
1346+
1347+
hdr = (const struct ptp_ocp_firmware_header *)fw->data;
1348+
if (memcmp(hdr->magic, OCP_FIRMWARE_MAGIC_HEADER, 4)) {
1349+
devlink_flash_update_status_notify(devlink,
1350+
"No firmware header found, flashing raw image",
1351+
NULL, 0, 0);
1352+
offset = 0;
1353+
length = fw->size;
1354+
goto out;
1355+
}
1356+
1357+
if (be16_to_cpu(hdr->pci_vendor_id) != bp->pdev->vendor ||
1358+
be16_to_cpu(hdr->pci_device_id) != bp->pdev->device) {
1359+
devlink_flash_update_status_notify(devlink,
1360+
"Firmware image compatibility check failed",
1361+
NULL, 0, 0);
1362+
return -EINVAL;
1363+
}
1364+
1365+
offset = sizeof(*hdr);
1366+
length = be32_to_cpu(hdr->image_size);
1367+
if (length != (fw->size - offset)) {
1368+
devlink_flash_update_status_notify(devlink,
1369+
"Firmware image size check failed",
1370+
NULL, 0, 0);
1371+
return -EINVAL;
1372+
}
1373+
1374+
crc = crc16(0xffff, &fw->data[offset], length);
1375+
if (be16_to_cpu(hdr->crc) != crc) {
1376+
devlink_flash_update_status_notify(devlink,
1377+
"Firmware image CRC check failed",
1378+
NULL, 0, 0);
1379+
return -EINVAL;
1380+
}
1381+
1382+
out:
1383+
*data = &fw->data[offset];
1384+
*size = length;
1385+
1386+
return 0;
1387+
}
1388+
13261389
static int
13271390
ptp_ocp_devlink_flash(struct devlink *devlink, struct device *dev,
13281391
const struct firmware *fw)
13291392
{
13301393
struct mtd_info *mtd = dev_get_drvdata(dev);
13311394
struct ptp_ocp *bp = devlink_priv(devlink);
1332-
size_t off, len, resid, wrote;
1395+
size_t off, len, size, resid, wrote;
13331396
struct erase_info erase;
13341397
size_t base, blksz;
1335-
int err = 0;
1398+
const u8 *data;
1399+
int err;
1400+
1401+
err = ptp_ocp_devlink_fw_image(devlink, fw, &data, &size);
1402+
if (err)
1403+
goto out;
13361404

13371405
off = 0;
13381406
base = bp->flash_start;
13391407
blksz = 4096;
1340-
resid = fw->size;
1408+
resid = size;
13411409

13421410
while (resid) {
13431411
devlink_flash_update_status_notify(devlink, "Flashing",
1344-
NULL, off, fw->size);
1412+
NULL, off, size);
13451413

13461414
len = min_t(size_t, resid, blksz);
13471415
erase.addr = base + off;
@@ -1351,7 +1419,7 @@ ptp_ocp_devlink_flash(struct devlink *devlink, struct device *dev,
13511419
if (err)
13521420
goto out;
13531421

1354-
err = mtd_write(mtd, base + off, len, &wrote, &fw->data[off]);
1422+
err = mtd_write(mtd, base + off, len, &wrote, data + off);
13551423
if (err)
13561424
goto out;
13571425

0 commit comments

Comments
 (0)