e1000e: write protect ICHx NVM to prevent malicious write/erase
Set the hardware to ignore all write/erase cycles to the GbE region in the ICHx NVM. This feature can be disabled by the WriteProtectNVM module parameter (enabled by default) only after a hardware reset, but the machine must be power cycled before trying to enable writes. Signed-off-by: Bruce Allan <bruce.w.allan@intel.com> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> CC: arjan@linux.intel.com Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
20b918dc77
commit
4a77035828
|
@ -305,6 +305,7 @@ struct e1000_info {
|
|||
#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5)
|
||||
#define FLAG_HAS_SWSM_ON_LOAD (1 << 6)
|
||||
#define FLAG_HAS_JUMBO_FRAMES (1 << 7)
|
||||
#define FLAG_READ_ONLY_NVM (1 << 8)
|
||||
#define FLAG_IS_ICH (1 << 9)
|
||||
#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
|
||||
#define FLAG_IS_QUAD_PORT_A (1 << 12)
|
||||
|
@ -385,6 +386,7 @@ extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
|
|||
extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
|
||||
extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
|
||||
|
||||
extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
|
||||
extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
|
||||
bool state);
|
||||
extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
|
||||
|
|
|
@ -529,6 +529,9 @@ static int e1000_set_eeprom(struct net_device *netdev,
|
|||
if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
|
||||
return -EFAULT;
|
||||
|
||||
if (adapter->flags & FLAG_READ_ONLY_NVM)
|
||||
return -EINVAL;
|
||||
|
||||
max_len = hw->nvm.word_size * 2;
|
||||
|
||||
first_word = eeprom->offset >> 1;
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#define ICH_FLASH_HSFCTL 0x0006
|
||||
#define ICH_FLASH_FADDR 0x0008
|
||||
#define ICH_FLASH_FDATA0 0x0010
|
||||
#define ICH_FLASH_PR0 0x0074
|
||||
|
||||
#define ICH_FLASH_READ_COMMAND_TIMEOUT 500
|
||||
#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500
|
||||
|
@ -150,6 +151,19 @@ union ich8_hws_flash_regacc {
|
|||
u16 regval;
|
||||
};
|
||||
|
||||
/* ICH Flash Protected Region */
|
||||
union ich8_flash_protected_range {
|
||||
struct ich8_pr {
|
||||
u32 base:13; /* 0:12 Protected Range Base */
|
||||
u32 reserved1:2; /* 13:14 Reserved */
|
||||
u32 rpe:1; /* 15 Read Protection Enable */
|
||||
u32 limit:13; /* 16:28 Protected Range Limit */
|
||||
u32 reserved2:2; /* 29:30 Reserved */
|
||||
u32 wpe:1; /* 31 Write Protection Enable */
|
||||
} range;
|
||||
u32 regval;
|
||||
};
|
||||
|
||||
static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
|
||||
static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
|
||||
static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
|
||||
|
@ -1284,6 +1298,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|||
* programming failed.
|
||||
*/
|
||||
if (ret_val) {
|
||||
/* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
|
||||
hw_dbg(hw, "Flash commit failed.\n");
|
||||
e1000_release_swflag_ich8lan(hw);
|
||||
return ret_val;
|
||||
|
@ -1373,6 +1388,49 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|||
return e1000e_validate_nvm_checksum_generic(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000e_write_protect_nvm_ich8lan - Make the NVM read-only
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* To prevent malicious write/erase of the NVM, set it to be read-only
|
||||
* so that the hardware ignores all write/erase cycles of the NVM via
|
||||
* the flash control registers. The shadow-ram copy of the NVM will
|
||||
* still be updated, however any updates to this copy will not stick
|
||||
* across driver reloads.
|
||||
**/
|
||||
void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
|
||||
{
|
||||
union ich8_flash_protected_range pr0;
|
||||
union ich8_hws_flash_status hsfsts;
|
||||
u32 gfpreg;
|
||||
s32 ret_val;
|
||||
|
||||
ret_val = e1000_acquire_swflag_ich8lan(hw);
|
||||
if (ret_val)
|
||||
return;
|
||||
|
||||
gfpreg = er32flash(ICH_FLASH_GFPREG);
|
||||
|
||||
/* Write-protect GbE Sector of NVM */
|
||||
pr0.regval = er32flash(ICH_FLASH_PR0);
|
||||
pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK;
|
||||
pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK);
|
||||
pr0.range.wpe = true;
|
||||
ew32flash(ICH_FLASH_PR0, pr0.regval);
|
||||
|
||||
/*
|
||||
* Lock down a subset of GbE Flash Control Registers, e.g.
|
||||
* PR0 to prevent the write-protection from being lifted.
|
||||
* Once FLOCKDN is set, the registers protected by it cannot
|
||||
* be written until FLOCKDN is cleared by a hardware reset.
|
||||
*/
|
||||
hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
|
||||
hsfsts.hsf_status.flockdn = true;
|
||||
ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);
|
||||
|
||||
e1000_release_swflag_ich8lan(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_write_flash_data_ich8lan - Writes bytes to the NVM
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
#include "e1000.h"
|
||||
|
||||
#define DRV_VERSION "0.3.3.3-k2"
|
||||
#define DRV_VERSION "0.3.3.3-k4"
|
||||
char e1000e_driver_name[] = "e1000e";
|
||||
const char e1000e_driver_version[] = DRV_VERSION;
|
||||
|
||||
|
@ -4467,6 +4467,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
|||
|
||||
adapter->bd_number = cards_found++;
|
||||
|
||||
e1000e_check_options(adapter);
|
||||
|
||||
/* setup adapter struct */
|
||||
err = e1000_sw_init(adapter);
|
||||
if (err)
|
||||
|
@ -4482,6 +4484,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
|||
if (err)
|
||||
goto err_hw_init;
|
||||
|
||||
if ((adapter->flags & FLAG_IS_ICH) &&
|
||||
(adapter->flags & FLAG_READ_ONLY_NVM))
|
||||
e1000e_write_protect_nvm_ich8lan(&adapter->hw);
|
||||
|
||||
hw->mac.ops.get_bus_info(&adapter->hw);
|
||||
|
||||
adapter->hw.phy.autoneg_wait_to_complete = 0;
|
||||
|
@ -4573,8 +4579,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
|||
INIT_WORK(&adapter->reset_task, e1000_reset_task);
|
||||
INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
|
||||
|
||||
e1000e_check_options(adapter);
|
||||
|
||||
/* Initialize link parameters. User can change them with ethtool */
|
||||
adapter->hw.mac.autoneg = 1;
|
||||
adapter->fc_autoneg = 1;
|
||||
|
|
|
@ -133,6 +133,15 @@ E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
|
|||
*/
|
||||
E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
|
||||
|
||||
/*
|
||||
* Write Protect NVM
|
||||
*
|
||||
* Valid Range: 0, 1
|
||||
*
|
||||
* Default Value: 1 (enabled)
|
||||
*/
|
||||
E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]");
|
||||
|
||||
struct e1000_option {
|
||||
enum { enable_option, range_option, list_option } type;
|
||||
const char *name;
|
||||
|
@ -388,4 +397,25 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
|
|||
opt.def);
|
||||
}
|
||||
}
|
||||
{ /* Write-protect NVM */
|
||||
const struct e1000_option opt = {
|
||||
.type = enable_option,
|
||||
.name = "Write-protect NVM",
|
||||
.err = "defaulting to Enabled",
|
||||
.def = OPTION_ENABLED
|
||||
};
|
||||
|
||||
if (adapter->flags & FLAG_IS_ICH) {
|
||||
if (num_WriteProtectNVM > bd) {
|
||||
unsigned int write_protect_nvm = WriteProtectNVM[bd];
|
||||
e1000_validate_option(&write_protect_nvm, &opt,
|
||||
adapter);
|
||||
if (write_protect_nvm)
|
||||
adapter->flags |= FLAG_READ_ONLY_NVM;
|
||||
} else {
|
||||
if (opt.def)
|
||||
adapter->flags |= FLAG_READ_ONLY_NVM;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue