Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: boot partition ro lock support

Enable boot partitions to be read-only locked until next power on via
a sysfs entry. There will be one sysfs entry for each boot partition:

/sys/block/mmcblkXbootY/ro_lock_until_next_power_on

Each boot partition is locked by writing 1 to its file.

Signed-off-by: Johan Rudholm <johan.rudholm@stericsson.com>
Signed-off-by: John Beckett <john.beckett@stericsson.com>
Signed-off-by: Chris Ball <cjb@laptop.org>

authored by

Johan Rudholm and committed by
Chris Ball
add710ea 92df954d

+153 -11
+13
Documentation/mmc/mmc-dev-parts.txt
··· 25 25 To re-enable read-only access: 26 26 27 27 echo 1 > /sys/block/mmcblkXbootY/force_ro 28 + 29 + The boot partitions can also be locked read only until the next power on, 30 + with: 31 + 32 + echo 1 > /sys/block/mmcblkXbootY/ro_lock_until_next_power_on 33 + 34 + This is a feature of the card and not of the kernel. If the card does 35 + not support boot partition locking, the file will not exist. If the 36 + feature has been disabled on the card, the file will be read-only. 37 + 38 + The boot partitions can also be locked permanently, but this feature is 39 + not accessible through sysfs in order to avoid accidental or malicious 40 + bricking.
+113 -8
drivers/mmc/card/block.c
··· 107 107 */ 108 108 unsigned int part_curr; 109 109 struct device_attribute force_ro; 110 + struct device_attribute power_ro_lock; 111 + int area_type; 110 112 }; 111 113 112 114 static DEFINE_MUTEX(open_lock); ··· 165 163 kfree(md); 166 164 } 167 165 mutex_unlock(&open_lock); 166 + } 167 + 168 + static ssize_t power_ro_lock_show(struct device *dev, 169 + struct device_attribute *attr, char *buf) 170 + { 171 + int ret; 172 + struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); 173 + struct mmc_card *card = md->queue.card; 174 + int locked = 0; 175 + 176 + if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN) 177 + locked = 2; 178 + else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) 179 + locked = 1; 180 + 181 + ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); 182 + 183 + return ret; 184 + } 185 + 186 + static ssize_t power_ro_lock_store(struct device *dev, 187 + struct device_attribute *attr, const char *buf, size_t count) 188 + { 189 + int ret; 190 + struct mmc_blk_data *md, *part_md; 191 + struct mmc_card *card; 192 + unsigned long set; 193 + 194 + if (kstrtoul(buf, 0, &set)) 195 + return -EINVAL; 196 + 197 + if (set != 1) 198 + return count; 199 + 200 + md = mmc_blk_get(dev_to_disk(dev)); 201 + card = md->queue.card; 202 + 203 + mmc_claim_host(card->host); 204 + 205 + ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, 206 + card->ext_csd.boot_ro_lock | 207 + EXT_CSD_BOOT_WP_B_PWR_WP_EN, 208 + card->ext_csd.part_time); 209 + if (ret) 210 + pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret); 211 + else 212 + card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; 213 + 214 + mmc_release_host(card->host); 215 + 216 + if (!ret) { 217 + pr_info("%s: Locking boot partition ro until next power on\n", 218 + md->disk->disk_name); 219 + set_disk_ro(md->disk, 1); 220 + 221 + list_for_each_entry(part_md, &md->part, part) 222 + if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) { 223 + pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name); 224 + set_disk_ro(part_md->disk, 1); 225 + } 226 + } 227 + 228 + mmc_blk_put(md); 229 + return count; 168 230 } 169 231 170 232 static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, ··· 1413 1347 struct device *parent, 1414 1348 sector_t size, 1415 1349 bool default_ro, 1416 - const char *subname) 1350 + const char *subname, 1351 + int area_type) 1417 1352 { 1418 1353 struct mmc_blk_data *md; 1419 1354 int devidx, ret; ··· 1439 1372 if (!subname) { 1440 1373 md->name_idx = find_first_zero_bit(name_use, max_devices); 1441 1374 __set_bit(md->name_idx, name_use); 1442 - } 1443 - else 1375 + } else 1444 1376 md->name_idx = ((struct mmc_blk_data *) 1445 1377 dev_to_disk(parent)->private_data)->name_idx; 1378 + 1379 + md->area_type = area_type; 1446 1380 1447 1381 /* 1448 1382 * Set the read-only status based on the supported commands ··· 1538 1470 size = card->csd.capacity << (card->csd.read_blkbits - 9); 1539 1471 } 1540 1472 1541 - md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL); 1473 + md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL, 1474 + MMC_BLK_DATA_AREA_MAIN); 1542 1475 return md; 1543 1476 } 1544 1477 ··· 1548 1479 unsigned int part_type, 1549 1480 sector_t size, 1550 1481 bool default_ro, 1551 - const char *subname) 1482 + const char *subname, 1483 + int area_type) 1552 1484 { 1553 1485 char cap_str[10]; 1554 1486 struct mmc_blk_data *part_md; 1555 1487 1556 1488 part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro, 1557 - subname); 1489 + subname, area_type); 1558 1490 if (IS_ERR(part_md)) 1559 1491 return PTR_ERR(part_md); 1560 1492 part_md->part_type = part_type; ··· 1588 1518 card->part[idx].part_cfg, 1589 1519 card->part[idx].size >> 9, 1590 1520 card->part[idx].force_ro, 1591 - card->part[idx].name); 1521 + card->part[idx].name, 1522 + card->part[idx].area_type); 1592 1523 if (ret) 1593 1524 return ret; 1594 1525 } ··· 1618 1547 1619 1548 static void mmc_blk_remove_req(struct mmc_blk_data *md) 1620 1549 { 1550 + struct mmc_card *card; 1551 + 1621 1552 if (md) { 1553 + card = md->queue.card; 1622 1554 if (md->disk->flags & GENHD_FL_UP) { 1623 1555 device_remove_file(disk_to_dev(md->disk), &md->force_ro); 1556 + if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && 1557 + card->ext_csd.boot_ro_lockable) 1558 + device_remove_file(disk_to_dev(md->disk), 1559 + &md->power_ro_lock); 1624 1560 1625 1561 /* Stop new requests from getting into the queue */ 1626 1562 del_gendisk(md->disk); ··· 1656 1578 static int mmc_add_disk(struct mmc_blk_data *md) 1657 1579 { 1658 1580 int ret; 1581 + struct mmc_card *card = md->queue.card; 1659 1582 1660 1583 add_disk(md->disk); 1661 1584 md->force_ro.show = force_ro_show; ··· 1666 1587 md->force_ro.attr.mode = S_IRUGO | S_IWUSR; 1667 1588 ret = device_create_file(disk_to_dev(md->disk), &md->force_ro); 1668 1589 if (ret) 1669 - del_gendisk(md->disk); 1590 + goto force_ro_fail; 1591 + 1592 + if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && 1593 + card->ext_csd.boot_ro_lockable) { 1594 + mode_t mode; 1595 + 1596 + if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) 1597 + mode = S_IRUGO; 1598 + else 1599 + mode = S_IRUGO | S_IWUSR; 1600 + 1601 + md->power_ro_lock.show = power_ro_lock_show; 1602 + md->power_ro_lock.store = power_ro_lock_store; 1603 + md->power_ro_lock.attr.mode = mode; 1604 + md->power_ro_lock.attr.name = 1605 + "ro_lock_until_next_power_on"; 1606 + ret = device_create_file(disk_to_dev(md->disk), 1607 + &md->power_ro_lock); 1608 + if (ret) 1609 + goto power_ro_lock_fail; 1610 + } 1611 + return ret; 1612 + 1613 + power_ro_lock_fail: 1614 + device_remove_file(disk_to_dev(md->disk), &md->force_ro); 1615 + force_ro_fail: 1616 + del_gendisk(md->disk); 1670 1617 1671 1618 return ret; 1672 1619 }
+12 -2
drivers/mmc/core/mmc.c
··· 348 348 part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; 349 349 mmc_part_add(card, part_size, 350 350 EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, 351 - "boot%d", idx, true); 351 + "boot%d", idx, true, 352 + MMC_BLK_DATA_AREA_BOOT); 352 353 } 353 354 } 354 355 } ··· 436 435 hc_wp_grp_sz); 437 436 mmc_part_add(card, part_size << 19, 438 437 EXT_CSD_PART_CONFIG_ACC_GP0 + idx, 439 - "gp%d", idx, false); 438 + "gp%d", idx, false, 439 + MMC_BLK_DATA_AREA_GP); 440 440 } 441 441 } 442 442 card->ext_csd.sec_trim_mult = ··· 448 446 ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; 449 447 card->ext_csd.trim_timeout = 300 * 450 448 ext_csd[EXT_CSD_TRIM_MULT]; 449 + 450 + /* 451 + * Note that the call to mmc_part_add above defaults to read 452 + * only. If this default assumption is changed, the call must 453 + * take into account the value of boot_locked below. 454 + */ 455 + card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; 456 + card->ext_csd.boot_ro_lockable = true; 451 457 } 452 458 453 459 if (card->ext_csd.rev >= 5) {
+9 -1
include/linux/mmc/card.h
··· 71 71 bool hpi_en; /* HPI enablebit */ 72 72 bool hpi; /* HPI support bit */ 73 73 unsigned int hpi_cmd; /* cmd used as HPI */ 74 + unsigned int boot_ro_lock; /* ro lock support */ 75 + bool boot_ro_lockable; 74 76 u8 raw_partition_support; /* 160 */ 75 77 u8 raw_erased_mem_count; /* 181 */ 76 78 u8 raw_ext_csd_structure; /* 194 */ ··· 189 187 unsigned int part_cfg; /* partition type */ 190 188 char name[MAX_MMC_PART_NAME_LEN]; 191 189 bool force_ro; /* to make boot parts RO by default */ 190 + unsigned int area_type; 191 + #define MMC_BLK_DATA_AREA_MAIN (1<<0) 192 + #define MMC_BLK_DATA_AREA_BOOT (1<<1) 193 + #define MMC_BLK_DATA_AREA_GP (1<<2) 192 194 }; 193 195 194 196 /* ··· 271 265 * This function fill contents in mmc_part. 272 266 */ 273 267 static inline void mmc_part_add(struct mmc_card *card, unsigned int size, 274 - unsigned int part_cfg, char *name, int idx, bool ro) 268 + unsigned int part_cfg, char *name, int idx, bool ro, 269 + int area_type) 275 270 { 276 271 card->part[card->nr_parts].size = size; 277 272 card->part[card->nr_parts].part_cfg = part_cfg; 278 273 sprintf(card->part[card->nr_parts].name, name, idx); 279 274 card->part[card->nr_parts].force_ro = ro; 275 + card->part[card->nr_parts].area_type = area_type; 280 276 card->nr_parts++; 281 277 } 282 278
+6
include/linux/mmc/mmc.h
··· 280 280 #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ 281 281 #define EXT_CSD_SANITIZE_START 165 /* W */ 282 282 #define EXT_CSD_WR_REL_PARAM 166 /* RO */ 283 + #define EXT_CSD_BOOT_WP 173 /* R/W */ 283 284 #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ 284 285 #define EXT_CSD_PART_CONFIG 179 /* R/W */ 285 286 #define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ ··· 321 320 */ 322 321 323 322 #define EXT_CSD_WR_REL_PARAM_EN (1<<2) 323 + 324 + #define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) 325 + #define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) 326 + #define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04) 327 + #define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) 324 328 325 329 #define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) 326 330 #define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)