Create an OEM Intel IPMI whitelist filter
This is a derivative of the upstream whitelist filter that also tracks
the host state as part of the filtering information.
In addition, the filter understands per-channel filtering, so a command
can be filtered out on a per-channel basis.
Tested: With the upstream filter disabled, and this filter enabled, run
several checks:
1) execute a command prior to host POST completete over kcs (OK)
2) execute a command after host POST complete (denied)
3) execute a command filtered on a lan interface
4) execute a command whitelisted on a lan interface
Change-Id: I9b6755f4bf2c9b9e30de0289f1fed68b3709dea0
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 46cb8e8..f484d47 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -88,13 +88,22 @@
find_package (OpenSSL REQUIRED)
include_directories (SYSTEM ${OPENSSL_INCLUDE_DIR})
+include_directories (SYSTEM ${CMAKE_BINARY_DIR})
+add_custom_command(OUTPUT include/ipmi-whitelist.hpp
+ COMMAND ./generate-whitelist.py
+ ARGS ipmi-whitelist.conf ${CMAKE_BINARY_DIR}/ipmi-whitelist.hpp
+ MAIN_DEPENDENCY ipmi-whitelist.conf
+ DEPENDS generate-whitelist.py
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+
add_library (zinteloemcmds
SHARED src/oemcommands.cpp src/sensorcommands.cpp
src/storagecommands.cpp src/multinodecommands.cpp
src/firmware-update.cpp src/appcommands.cpp src/smbioshandler.cpp
src/smbiosmdrv2handler.cpp src/manufacturingcommands.cpp
src/bmccontrolservices.cpp src/bridgingcommands.cpp
- src/ipmi_to_redfish_hooks.cpp src/chassiscommands.cpp)
+ src/ipmi_to_redfish_hooks.cpp src/chassiscommands.cpp
+ src/whitelist-filter.cpp include/ipmi-whitelist.hpp)
set_target_properties (zinteloemcmds PROPERTIES VERSION "0.1.0")
set_target_properties (zinteloemcmds PROPERTIES SOVERSION "0")
target_link_libraries (zinteloemcmds stdc++fs)
diff --git a/generate-whitelist.py b/generate-whitelist.py
new file mode 100755
index 0000000..c732726
--- /dev/null
+++ b/generate-whitelist.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+
+import re, sys, os.path
+
+def usage():
+ sys.stderr.write("Usage: $0 whitelist-config-in whitelist-header-out\n")
+ sys.stderr.write(" Reads in whitelist config, sorting the contents\n")
+ sys.stderr.write(" and outputs a header file\n")
+ sys.exit(-1)
+
+class Error(Exception):
+ pass
+
+class DuplicateEntry(Error):
+ def __init__(self, e):
+ super(Error, self).__init__(
+ "Multiple entries with matching netfn/cmd found ({})".format(e))
+
+class ParseError(Error):
+ def __init__(self, d):
+ super(Error, self).__init__("Parse error at: '{}'".format(d))
+
+class entry:
+ linere = re.compile(
+ r'(0x[0-9a-f]{2}):(0x[0-9a-f]{2})((:(0x[0-9a-f]{4}))?)\s*((//\s*(.*))?)',
+ re.I
+ )
+ def __init__(self, data):
+ # parse data line into values:
+ # type 1, two values: netfn, cmd
+ # type 2, three values: netfn, cmd, channels
+ try:
+ m = self.linere.fullmatch(data).groups()
+ except:
+ raise ParseError(data)
+ self.netfn = int(m[0], 16)
+ self.cmd = int(m[1], 16)
+ if m[4] is not None:
+ self.channels = int(m[4], 16)
+ else:
+ # if no channel was provided, default to previous behavior, which
+ # is allow all interfaces, including the system interface (ch 15)
+ self.channels = 0xffff
+ if m[6] is not None:
+ self.comment = "// " + m[7]
+ else:
+ self.comment = "//"
+ def __str__(self):
+ return " ".join([ '{',
+ "0x{0.netfn:02x},".format(self),
+ "0x{0.cmd:02x},".format(self),
+ "0x{0.channels:04x}".format(self),
+ "},",
+ "{0.comment}".format(self),
+ ])
+ def __lt__(self, other):
+ if self.netfn == other.netfn:
+ return self.cmd < other.cmd
+ return self.netfn < other.netfn
+ def match(self, other):
+ return (self.netfn == other.netfn) and (self.cmd == other.cmd)
+
+def parse(config):
+ entries = []
+ with open(config) as f:
+ for line in f:
+ line = line.strip()
+ if len(line) == 0 or line[0] == '#':
+ continue
+ e = entry(line)
+ if any([e.match(item) for item in entries]):
+ d = DuplicateEntry(e)
+ sys.stderr.write("WARNING: {}\n".format(d))
+ else:
+ entries.append(e)
+ entries.sort()
+ return entries
+
+def output(entries, hppfile):
+ lines = [
+ "#pragma once",
+ "",
+ "// AUTOGENERATED FILE; DO NOT MODIFY",
+ "",
+ "#include <array>",
+ "#include <tuple>",
+ "",
+ "using netfncmd_tuple = std::tuple<unsigned char, unsigned char, unsigned short>;",
+ "",
+ "constexpr const std::array<netfncmd_tuple, {}> whitelist = ".format(
+ len(entries)),
+ "{{"
+ ]
+ lines.extend([' {}'.format(e) for e in entries])
+ lines.append("}};\n");
+
+ with open(hppfile, "w") as hpp:
+ hpp.write("\n".join(lines))
+
+
+if __name__ == "__main__":
+ if len(sys.argv) != 3:
+ usage()
+ config = sys.argv[1]
+ header = sys.argv[2]
+ entries = parse(config)
+ output(entries, header)
diff --git a/ipmi-whitelist.conf b/ipmi-whitelist.conf
new file mode 100644
index 0000000..aeafbf2
--- /dev/null
+++ b/ipmi-whitelist.conf
@@ -0,0 +1,319 @@
+#<NetFn>:<Command>:<ChannelMask> // comment
+0x00:0x00:0xffff //<Chassis>:<Get Chassis Capabiliti>
+0x00:0x01:0xffff //<Chassis>:<Get Chassis Status>
+0x00:0x02:0x7fff //<Chassis>:<Chassis Control>
+0x00:0x03:0x7fff //<Chassis>:<Chassis Reset>
+0x00:0x04:0xffff //<Chassis>:<Chassis Identify>
+0x00:0x05:0x7fff //<Chassis>:<Set Chassis Capabilities>
+0x00:0x06:0x7fff //<Chassis>:<Set Power Restore Policy>
+0x00:0x07:0xffff //<Chassis>:<Get System Restart Cause>
+0x00:0x08:0x7fff //<Chassis>:<Set System Boot Options>
+0x00:0x09:0xffff //<Chassis>:<Get System Boot Options>
+0x00:0x0a:0xffff //<Chassis>:<Set Front Panel Enables>
+0x00:0x0f:0xffff //<Chassis>:<Get POH Counter>
+0x04:0x00:0x7fff //<Sensor/Event>:<Set Event Receiver>
+0x04:0x01:0xffff //<Sensor/Event>:<Get Event Receiver>
+0x04:0x02:0xffff //<Sensor/Event>:<SEL Platform event>
+0x04:0x10:0xffff //<Sensor/Event>:<PEF Get Capabilities>
+0x04:0x11:0x7fff //<Sensor/Event>:<Arm PEF Postpone Timer>
+0x04:0x12:0x7fff //<Sensor/Event>:<PEF Set Configuration Parameters>
+0x04:0x13:0xffff //<Sensor/Event>:<PEF Get Configuration Parameters>
+0x04:0x14:0x7fff //<Sensor/Event>:<PEF Set Processed EventID>
+0x04:0x15:0xffff //<Sensor/Event>:<PEF Get Processed EventID>
+0x04:0x16:0x7fff //<Sensor/Event>:<Alert Immediate>
+0x04:0x17:0x7fff //<Sensor/Event>:<PET Acknowledge>
+0x04:0x20:0xffff //<Sensor/Event>:<Get Device SDR Info>
+0x04:0x21:0xffff //<Sensor/Event>:<Get Device SDR>
+0x04:0x23:0xffff //<Sensor/Event>:<Get Sensor Reading Factors>
+0x04:0x24:0x7fff //<Sensor/Event>:<Set Sensor Hysteresis>
+0x04:0x25:0xffff //<Sensor/Event>:<Get Sensor Hysteresis>
+0x04:0x26:0x7fff //<Sensor/Event>:<Set Sensor Threshold>
+0x04:0x27:0xffff //<Sensor/Event>:<Get Sensor Threshold>
+0x04:0x28:0x7fff //<Sensor/Event>:<Set SensorEvent Enable>
+0x04:0x29:0xffff //<Sensor/Event>:<Get SensorEvent Enable>
+0x04:0x2a:0x7fff //<Sensor/Event>:<Re-arm Sensor Events>
+0x04:0x2b:0xffff //<Sensor/Event>:<Get SensorEvent Status>
+0x04:0x2d:0xffff //<Sensor/Event>:<Get SensorReading>
+0x04:0x2e:0x7fff //<Sensor/Event>:<Get Sensor Type>
+0x04:0x2f:0xffff //<Sensor/Event>:<Get Sensor Type>
+0x04:0x30:0x7fff //<Sensor/Event>:<Set Sensor Reading and Event Status>
+0x06:0x01:0xffff //<App>:<Get Device ID>
+0x06:0x02:0xffff //<App>:<Cold Reset>
+0x06:0x04:0xffff //<App>:<Get Self Test>
+0x06:0x05:0x7fff //<App>:<Manufacturing Test Mode>
+0x06:0x06:0xffff //<App>:<Set ACPI Power State>
+0x06:0x07:0xffff //<App>:<Get ACPI Power State>
+0x06:0x08:0xffff //<App>:<Get Device GUID>
+0x06:0x22:0xffff //<App>:<Reset Watchdog Timer>
+0x06:0x24:0xffff //<App>:<Set Watchdog Timer>
+0x06:0x25:0xffff //<App>:<Get Watchdog Timer>
+0x06:0x2e:0x7fff //<App>:<Set BMC Global Enables>
+0x06:0x2f:0xffff //<App>:<Get BMC Global Enables>
+0x06:0x30:0xffff //<App>:<Clear Message Flags>
+0x06:0x31:0xffff //<App>:<Get Message Flags>
+0x06:0x33:0xffff //<App>:<Get Message>
+0x06:0x34:0x7fff //<App>:<Send Message>
+0x06:0x35:0xffff //<App>:<Read Event Message Buffer>
+0x06:0x37:0xffff //<App>:<Get System GUID>
+0x06:0x38:0xffff //<App>:<Get Channel Authentication Capability>
+0x06:0x39:0xffff //<App>:<Get Session Challenge>
+0x06:0x3a:0x7fff //<App>:<Activate Session>
+0x06:0x3b:0x7fff //<App>:<Set Session Privilege>
+0x06:0x3c:0x7fff //<App>:<Close Session>
+0x06:0x3d:0xffff //<App>:<Get Channel Session Info>
+0x06:0x3f:0x7fff //<App>:<Get Authentication Code>
+0x06:0x40:0x7fff //<App>:<Set Channel Access>
+0x06:0x41:0xffff //<App>:<Get Channel Access>
+0x06:0x42:0xffff //<App>:<Get Channel Info>
+0x06:0x43:0x7fff //<App>:<Set User Access>
+0x06:0x44:0xffff //<App>:<Get User Access>
+0x06:0x45:0x7fff //<App>:<Set User Name>
+0x06:0x46:0xffff //<App>:<Get User Name>
+0x06:0x47:0x7fff //<App>:<Set User Password>
+0x06:0x48:0x7fff //<App>:<Activate Payload>
+0x06:0x49:0x7fff //<App>:<Deactivate Payload>
+0x06:0x4a:0xffff //<App>:<Get Payload Activation Status>
+0x06:0x4b:0xffff //<App>:<Get Payload Instance Info>
+0x06:0x4c:0x7fff //<App>:<Set User Payload Access>
+0x06:0x4d:0xffff //<App>:<Get User Payload Access>
+0x06:0x4e:0xffff //<App>:<Get Channel Payload Support>
+0x06:0x4f:0xffff //<App>:<Get Channel Payload Version>
+0x06:0x50:0xffff //<App>:<Get Channel OEM Payload Info>
+0x06:0x52:0x7fff //<App>:<Master Write Read I2C>
+0x06:0x54:0xffff //<App>:<Get Channel Cipher Suites>
+0x06:0x55:0xffff //<App>:<Suspend Payload Encryption>
+0x06:0x56:0xffff //<App>:<Set Channel Security Keys>
+0x06:0x57:0xffff //<App>:<Get System Interface Capabilities>
+0x08:0x20:0xf9be //<Firmware>:<Get Version Information>
+0x08:0x21:0xf9be //<Firmware>:<Security Version Information>
+0x08:0x22:0xf9be //<Firmware>:<Firmware Update Channel Information>
+0x08:0x23:0xf9be //<Firmware>:<BMC Execution Context>
+0x08:0x24:0xf9be //<Firmware>:<Get Boot Certificate Info>
+0x08:0x25:0xf9be //<Firmware>:<Get Boot Certificate Data>
+0x08:0x26:0xf9be //<Firmware>:<Firmware Random Number Update>
+0x08:0x27:0xf9be //<Firmware>:<Set Firmware Update Mode>
+0x08:0x28:0xf9be //<Firmware>:<Exit Firmware Update Mode>
+0x08:0x29:0xf9be //<Firmware>:<Firmware Update Control>
+0x08:0x2a:0xf9be //<Firmware>:<Get Firmware Update Status>
+0x08:0x2b:0xf9be //<Firmware>:<Set Firmware Update Options>
+0x08:0x2c:0xf9be //<Firmware>:<Write Firmware Image>
+0x08:0x2d:0xf9be //<Firmware>:<Get Firmware Update Status Code Message>
+0x08:0xdb:0x79be //<Firmware>:<Enter Safe Mode>
+0x08:0xe0:0xf9be //<Firmware>:<Get Firmware Update Error Code Message>
+0x0a:0x10:0xffff //<Storage>:<Get FRU Inventory Area Info>
+0x0a:0x11:0xffff //<Storage>:<Read FRU Data>
+0x0a:0x12:0x7fff //<Storage>:<Write FRU Data>
+0x0a:0x20:0xffff //<Storage>:<Get SDR Repository Info>
+0x0a:0x21:0xffff //<Storage>:<Get SDR Alloc Info>
+0x0a:0x22:0xffff //<Storage>:<Reserve SDR>
+0x0a:0x23:0xffff //<Storage>:<Get SDR>
+0x0a:0x24:0x7fff //<Storage>:<Add SDR>
+0x0a:0x25:0x7fff //<Storage>:<Partial Add SDR>
+0x0a:0x26:0x7fff //<Storage>:<Delete SDR>
+0x0a:0x27:0x7fff //<Storage>:<Clear SDR>
+0x0a:0x28:0xffff //<Storage>:<SEL Get Time>
+0x0a:0x2c:0x7fff //<Storage>:<Run Init Agent>
+0x0a:0x40:0xffff //<Storage>:<Get SEL Info>
+0x0a:0x41:0xffff //<Storage>:<Get SEL Alloc Info>
+0x0a:0x42:0xffff //<Storage>:<SEL Reserve>
+0x0a:0x43:0xffff //<Storage>:<Get SEL Entry>
+0x0a:0x44:0x7fff //<Storage>:<Add SEL Entry>
+0x0a:0x45:0x7fff //<Storage>:<Add Partial SEL Entry>
+0x0a:0x46:0x7fff //<Storage>:<Delete SEL Entry>
+0x0a:0x47:0x7fff //<Storage>:<Clear SEL>
+0x0a:0x48:0xffff //<Storage>:<Get SEL Time>
+0x0a:0x49:0xffff //<Storage>:<Set SEL Time>
+0x0a:0x5a:0xffff //<Storage>:<Get SEL Auxiliary Log Status>
+0x0a:0x5b:0x7fff //<Storage>:<Set SEL Auxiliary Log Status>
+0x0a:0x5c:0xffff //<Storage>:<Get SEL Time UTC Offset>
+0x0a:0x5d:0x7fff //<Storage>:<Set SEL Time UTC Offset>
+0x0c:0x01:0x7fff //<Transport>:<Set LAN Configuration Parameters>
+0x0c:0x02:0xffff //<Transport>:<Get LAN Configuration Parameters>
+0x0c:0x03:0x7fff //<Transport>:<Suspend BMC ARPs>
+0x0c:0x04:0xffff //<Transport>:<Get IPUDPRMCP Statistics>
+0x0c:0x10:0x7fff //<Transport>:<7et Serial Modem Configuration>
+0x0c:0x11:0xffff //<Transport>:<Get Serial Modem Configuration>
+0x0c:0x12:0x7fff //<Transport>:<SM SetSerial Modem Mux>
+0x0c:0x14:0x7fff //<Transport>:<Set PPP UDP Proxy Transmit Data>
+0x0c:0x15:0x7fff //<Transport>:<Get PPP UDP Proxy Transmit Data>
+0x0c:0x16:0x7fff //<Transport>:<Send PPP UDP Proxy Packet>
+0x0c:0x17:0x7fff //<Transport>:<Get PPP UDP Proxy Receive Data>
+0x0c:0x18:0x7fff //<Transport>:<Serial Modem Connection Active>
+0x0c:0x19:0x7fff //<Transport>:<Callback>
+0x0c:0x1a:0x7fff //<Transport>:<Set User Callback Options>
+0x0c:0x1b:0x7fff //<Transport>:<Get User Callback Options>
+0x0c:0x1c:0x7fff //<Transport>:<Set Serial Routing Mux>
+0x0c:0x20:0x7fff //<Transport>:<SOL Activating>
+0x0c:0x21:0x7fff //<Transport>:<Set SOL Configuration Parameters>
+0x0c:0x22:0xffff //<Transport>:<Get SOL Configuration Parameters>
+0x2c:0x1f:0xffff //<Group Extension>:<Get CPU PECI Package Config Data>
+0x2c:0x20:0xffff //<Group Extension>:<Get MDR Data Region Status>
+0x2c:0x21:0x7fff //<Group Extension>:<Get MDR Region Update Complete>
+0x2c:0x22:0xffff //<Group Extension>:<Read MDR Region>
+0x2c:0x23:0x7fff //<Group Extension>:<Write MDR Region>
+0x2c:0x24:0x7fff //<Group Extension>:<Get MDR Region Lock>
+0x2c:0x25:0xffff //<Group Extension>:<Get System Mode>
+0x2c:0x26:0x7fff //<Group Extension>:<Set System Mode>
+0x2c:0x29:0xffff //<Group Extension>:<Get TPM Configuration>
+0x2c:0x30:0x7fff //<Group Extension>:<Set TPM Configuration>
+0x2c:0x31:0x7fff //<Group Extension>:<TPM Configuration Update Complete>
+0x2c:0x37:0xffff //<Group Extension>:<Read PCIe Cable EEPROM Data>
+0x30:0x02:0x7fff //<Intel General Application>:<Restore Configuration>
+0x30:0x03:0x7fff //<Intel General Application>:<Restore SDR>
+0x30:0x04:0xffff //<Intel General Application>:<Get NW Switch MIB>
+0x30:0x05:0xffff //<Intel General Application>:<Get PDB FW Version>
+0x30:0x09:0xffff //<Intel General Application>:<Get BMC Config>
+0x30:0x14:0xffff //<Intel General Application>:<Get SM Signal>
+0x30:0x15:0x7fff //<Intel General Application>:<Set SM Signal>
+0x30:0x19:0xffff //<Intel General Application>:<Read LAN Channel Port Value>
+0x30:0x1a:0xffff //<Intel General Application>:<Get NIC Info>
+0x30:0x1b:0xffff //<Intel General Application>:<Get LAN Available>
+0x30:0x1c:0x7fff //<Intel General Application>:<Set Master MAC>
+0x30:0x1d:0xffff //<Intel General Application>:<Get Master MAC>
+0x30:0x1f:0xffff //<Intel General Application>:<Get Secure Mode>
+0x30:0x20:0xffff //<Intel General Application>:<OEM Get SEL info>
+0x30:0x21:0xffff //<Intel General Application>:<OEM Get SEL Allocation Info>
+0x30:0x22:0xffff //<Intel General Application>:<OEM Platform Event Message>
+0x30:0x23:0xffff //<Intel General Application>:<OEM Get SEL Entry>
+0x30:0x24:0x7fff //<Intel General Application>:<OEM Add SEL Entry>
+0x30:0x26:0xffff //<Intel General Application>:<Set BIOS ID>
+0x30:0x27:0xffff //<Intel General Application>:<Get OEM Device Information>
+0x30:0x29:0x7fff //<Intel General Application>:<Write SSL Certificate File>
+0x30:0x2c:0x7fff //<Intel General Application>:<Set Processor Tcontrol>
+0x30:0x2d:0x7fff //<Intel General Application>:<Set Cold Redundancy Configuration>
+0x30:0x2e:0xffff //<Intel General Application>:<Get Cold Redundancy Configuration>
+0x30:0x30:0xffff //<Intel General Application>:<Get Sensor Severity>
+0x30:0x31:0xffff //<Intel General Application>:<Get AIC Slot FRU ID SLOT POS Records>
+0x30:0x33:0xffff //<Intel General Application>:<Get Controller Status>
+0x30:0x38:0xffff //<Intel General Application>:<Get Satellite Firmware update status>
+0x30:0x39:0xffff //<Intel General Application>:<HSBP Get Owner>
+0x30:0x3b:0x7fff //<Intel General Application>:<Set AIC MAC>
+0x30:0x3c:0xffff //<Intel General Application>:<Get AIC MAC>
+0x30:0x3d:0x7fff //<Intel General Application>:<Clear All AIC MACs>
+0x30:0x3f:0x7fff //<Intel General Application>:<Enable Onboard TPM>
+0x30:0x40:0x7fff //<Intel General Application>:<Resolve IP Address>
+0x30:0x41:0xffff //<Intel General Application>:<Set System GUID>
+0x30:0x42:0x7fff //<Intel General Application>:<Disable BMC System Reset Action>
+0x30:0x43:0xffff //<Intel General Application>:<Get BMC Reset Disables>
+0x30:0x44:0xffff //<Intel General Application>:<Send Embedded Firmware Update Status>
+0x30:0x47:0xffff //<Intel General Application>:<HSBP Get Version>
+0x30:0x48:0x7fff //<Intel General Application>:<Internal Platform Event>
+0x30:0x54:0x7fff //<Intel General Application>:<Set Power Restore Delay>
+0x30:0x55:0xffff //<Intel General Application>:<Get Power Restore Delay>
+0x30:0x57:0x7fff //<Intel General Application>:<Set Fault Indication>
+0x30:0x58:0xffff //<Intel General Application>:<Get DIMM Fault Status>
+0x30:0x5f:0x7fff //<Intel General Application>:<Set Special User Password>
+0x30:0x60:0x7fff //<Intel General Application>:<Set Shutdown Policy>
+0x30:0x62:0xffff //<Intel General Application>:<Get Shutdown Policy>
+0x30:0x63:0xffff //<Intel General Application>:<Get Node Slot Presence>
+0x30:0x64:0x7fff //<Intel General Application>:<Set HDD Drive Fault LED State>
+0x30:0x65:0xffff //<Intel General Application>:<Get HDD Drive Fault LED State>
+0x30:0x66:0xffff //<Intel General Application>:<Get Buffer Size>
+0x30:0x67:0x7fff //<Intel General Application>:<OEM Misc>
+0x30:0x71:0xffff //<Intel General Application>:<Get Advanced Support>
+0x30:0x72:0x7fff //<Intel General Application>:<Set EFI Payload>
+0x30:0x73:0xffff //<Intel General Application>:<Get EFI Payload>
+0x30:0x74:0xffff //<Intel General Application>:<Get RMM Status>
+0x30:0x75:0xffff //<Intel General Application>:<Get Voltage Name>
+0x30:0x80:0xffff //<Intel General Application>:<HSBP Get Register From Memory>
+0x30:0x81:0xffff //<Intel General Application>:<Get Power State>
+0x30:0x82:0xffff //<Intel General Application>:<Get ACPI Config>
+0x30:0x85:0xffff //<Intel General Application>:<Get SF PWM>
+0x30:0x87:0x7fff //<Intel General Application>:<Set DIMM Thermal Threshold>
+0x30:0x88:0x7fff //<Intel General Application>:<Fans-off Configuration>
+0x30:0x89:0x7fff //<Intel General Application>:<Set Fan Control Configuration>
+0x30:0x8a:0xffff //<Intel General Application>:<Get Fan Control Configuration>
+0x30:0x8b:0xffff //<Intel General Application>:<Auto Fan Detect>
+0x30:0x8c:0x7fff //<Intel General Application>:<Set fan speed offset>
+0x30:0x8d:0xffff //<Intel General Application>:<Get fan speed offset>
+0x30:0x8e:0x7fff //<Intel General Application>:<Set DIMM offset>
+0x30:0x8f:0xffff //<Intel General Application>:<Get DIMM offset>
+0x30:0x90:0x7fff //<Intel General Application>:<Set FSC Parameter>
+0x30:0x91:0xffff //<Intel General Application>:<Get FSC Parameter>
+0x30:0x92:0xffff //<Intel General Application>:<Get Chassis Identifier>
+0x30:0x93:0xffff //<Intel General Application>:<Read Base Board Product ID>
+0x30:0x94:0xffff //<Intel General Application>:<Get BMC Revision ID>
+0x30:0x95:0xffff //<Intel General Application>:<Get Is AP CPU>
+0x30:0x9a:0xffff //<Intel General Application>:<Get Processor Error Configuration and Status>
+0x30:0x9b:0x7fff //<Intel General Application>:<Set Processor Error Configuration>
+0x30:0x9c:0x7fff //<Intel General Application>:<Set Fan PWM Limit>
+0x30:0x9d:0xffff //<Intel General Application>:<Get Fan PWM Limit>
+0x30:0xb0:0xffff //<Intel General Application>:<Get LED Status>
+0x30:0xb1:0x7fff //<Intel General Application>:<Control BMC Services>
+0x30:0xb2:0xffff //<Intel General Application>:<Get BMC Service Status>
+0x30:0xb3:0xffff //<Intel General Application>:<Get BMC Security Control Mode>
+0x30:0xb4:0x7fff //<Intel General Application>:<Set BMC Security Control Mode>
+0x30:0xbb:0xffff //<Intel General Application>:<Get CPLD Revision ID>
+0x30:0xc2:0xffff //<Intel General Application>:<Get OEM Extended Sys Info>
+0x30:0xc3:0x7fff //<Intel General Application>:<Mount Virtual USB Device>
+0x30:0xc4:0x7fff //<Intel General Application>:<Unmount Virtual USB Device>
+0x30:0xc6:0xffff //<Intel General Application>:<Get Partition Config>
+0x30:0xc7:0xffff //<Intel General Application>:<Get Zone Information>
+0x30:0xc9:0xffff //<Intel General Application>:<Get Configuration Status>
+0x30:0xca:0xffff //<Intel General Application>:<Get Fabric Information>
+0x30:0xcb:0xffff //<Intel General Application>:<Get EndPoints Information>
+0x30:0xcc:0xffff //<Intel General Application>:<Get Switches Information>
+0x30:0xcd:0xffff //<Intel General Application>:<Get Switch Collection Information>
+0x30:0xd0:0xffff //<Intel General Application>:<Get NVMe Drive Data>
+0x30:0xd1:0xffff //<Intel General Application>:<HSBP Statistics>
+0x30:0xd3:0x7fff //<Intel General Application>:<Set BIOS Feature Capability>
+0x30:0xd4:0xffff //<Intel General Application>:<Get BIOS Capsule (OOB Update)>
+0x30:0xd5:0x7fff //<Intel General Application>:<Set Payload>
+0x30:0xd6:0xffff //<Intel General Application>:<Get Payload>
+0x30:0xd7:0x7fff //<Intel General Application>:<Set BIOS Password Hash Info>
+0x30:0xd8:0xffff //<Intel General Application>:<Get Stored BIOS Password>
+0x30:0xd9:0x7fff //<Intel General Application>:<OOB Update Status>
+0x30:0xdb:0x7fff //<Intel General Application>:<Get/Set BMC Remote Debug Parameters>
+0x30:0xe2:0xffff //<Intel General Application>:<OEM Get Reading>
+0x30:0xe5:0xffff //<Intel General Application>:<Get NMI Source>
+0x30:0xe6:0x7fff //<Intel General Application>:<Send Raw PECI>
+0x30:0xe7:0x7fff //<Intel General Application>:<Aggregate Send Raw PECI>
+0x30:0xe8:0xffff //<Intel General Application>:<Get PCIe SMBus Slot Card Info>
+0x30:0xe9:0xffff //<Intel General Application>:<Get BIOS POST CODE>
+0x30:0xf9:0xffff //<Intel General Application>:<Get POST Progress Codes>
+0x30:0xfa:0x7fff //<Intel General Application>:<Disable PSU for ME>
+0x30:0xfb:0x7fff //<Intel General Application>:<Restore PSU for ME>
+0x30:0xfd:0xffff //<Intel General Application>:<Get Riser Presence>
+0x32:0x60:0xffff //<Intel OEM Platform>:<Get PM Bus Information>
+0x32:0x63:0xffff //<Intel OEM Platform>:<Get Tach Information>
+0x32:0x80:0xffff //<Intel OEM Platform>:<Get SOL Log Number>
+0x32:0x81:0xffff //<Intel OEM Platform>:<Get SOL Log Entry>
+0x32:0x83:0xffff //<Intel OEM Platform>:<Get SOL Control>
+0x32:0x8d:0xffff //<Intel OEM Platform>:<Get SSD Power>
+0x32:0x90:0x7fff //<Intel OEM Platform>:<Get-Set Serial Port Speed>
+0x3e:0x02:0xffff //<Intel Managed Data Region>:<BMC Data Region Update Event Message>
+0x3e:0x20:0x7fff //<Intel Managed Data Region>:<BMC Region Status>
+0x3e:0x21:0x7fff //<Intel Managed Data Region>:<BMC Region Update Complete>
+0x3e:0x22:0xffff //<Intel Managed Data Region>:<MDR Event>
+0x3e:0x23:0xffff //<Intel Managed Data Region>:<BMC Region Read>
+0x3e:0x24:0x7fff //<Intel Managed Data Region>:<BMC Region Write>
+0x3e:0x25:0x7fff //<Intel Managed Data Region>:<BMC Region Lock>
+0x3e:0x28:0xffff //<Intel Managed Data Region>:<Get DIMM information>
+0x3e:0x30:0xffff //<Intel Managed Data Region>:<MDR2 Status>
+0x3e:0x31:0xffff //<Intel Managed Data Region>:<MDR2 GET Direction>
+0x3e:0x32:0xffff //<Intel Managed Data Region>:<MDR2 Get Data Set Info>
+0x3e:0x33:0xffff //<Intel Managed Data Region>:<MDR2 Lock Data>
+0x3e:0x34:0xffff //<Intel Managed Data Region>:<MDR2 Unlock Data>
+0x3e:0x35:0xffff //<Intel Managed Data Region>:<MDR2 Dget Data Block>
+0x3e:0x38:0xffff //<Intel Managed Data Region>:<MDR2 Send Direction>
+0x3e:0x39:0xffff //<Intel Managed Data Region>:<MDR2 Data Info Offer>
+0x3e:0x3a:0x7fff //<Intel Managed Data Region>:<MDR2 Data Info>
+0x3e:0x3b:0x7fff //<Intel Managed Data Region>:<MDR2 Data Start>
+0x3e:0x3c:0x7fff //<Intel Managed Data Region>:<MDR2 Data Done>
+0x3e:0x3d:0x7fff //<Intel Managed Data Region>:<MDR2 Data Block>
+0x3e:0x40:0x7fff //<Intel Managed Data Region>:<Set Get LAN Failover>
+0x3e:0x41:0xffff //<Intel Managed Data Region>:<Enter Platform Debug Log file transfer mode>
+0x3e:0x42:0xffff //<Intel Managed Data Region>:<Read Platform Debug Log file>
+0x3e:0x43:0xffff //<Intel Managed Data Region>:<Status of the Platform Debug Log file transfer mode>
+0x3e:0x44:0xffff //<Intel Managed Data Region>:<Exit Platform Debug Log file transfer mode>
+0x3e:0x47:0x7fff //<Intel Managed Data Region>:<Get/Set BMC Application Fault Management Config>
+0x3e:0x48:0x7fff //<Intel Managed Data Region>:<Get/Set BMC Boot Fault Management Config>
+0x3e:0x50:0xffff //<Intel Managed Data Region>:<Node IPMB slave address>
+0x3e:0x51:0xffff //<Intel Managed Data Region>:<Slot IPMB>
+0x3e:0x52:0xffff //<Intel Managed Data Region>:<Slot I2C Master Write Read>
+0x3e:0x70:0x7fff //<Intel Managed Data Region>:<SDR Configuration File control>
+0x3e:0x71:0x7fff //<Intel Managed Data Region>:<SDR Configuration File Write>
+0x3e:0x72:0x7fff //<Intel Managed Data Region>:<SDR Configuration File Read>
+0x3e:0x73:0x7fff //<Intel Managed Data Region>:<SDR Configuration File Management>
+0x3e:0x75:0xffff //<Intel Managed Data Region>:<Get Remote Log IP>
+0x3e:0x76:0x7fff //<Intel Managed Data Region>:<Get/Set Password Mode>
diff --git a/src/whitelist-filter.cpp b/src/whitelist-filter.cpp
new file mode 100644
index 0000000..099362c
--- /dev/null
+++ b/src/whitelist-filter.cpp
@@ -0,0 +1,375 @@
+#include <algorithm>
+#include <array>
+#include <ipmi-whitelist.hpp>
+#include <ipmid/api.hpp>
+#include <ipmid/utils.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
+
+namespace ipmi
+{
+
+// put the filter provider in an unnamed namespace
+namespace
+{
+
+/** @class WhitelistFilter
+ *
+ * Class that implements an IPMI message filter based
+ * on incoming interface and a restriction mode setting
+ */
+class WhitelistFilter
+{
+
+ public:
+ WhitelistFilter();
+ ~WhitelistFilter() = default;
+ WhitelistFilter(WhitelistFilter const&) = delete;
+ WhitelistFilter(WhitelistFilter&&) = delete;
+ WhitelistFilter& operator=(WhitelistFilter const&) = delete;
+ WhitelistFilter& operator=(WhitelistFilter&&) = delete;
+
+ private:
+ void postInit();
+ void cacheRestrictedAndPostCompleteMode();
+ void handleRestrictedModeChange(sdbusplus::message::message& m);
+ void handlePostCompleteChange(sdbusplus::message::message& m);
+ void updatePostComplete(const std::string& value);
+ void updateRestrictionMode(const std::string& value);
+ ipmi::Cc filterMessage(ipmi::message::Request::ptr request);
+
+ // the BMC KCS Policy Control Modes document uses different names
+ // than the RestrictionModes D-Bus interface; use aliases
+ static constexpr RestrictionMode::Modes restrictionModeAllowAll =
+ RestrictionMode::Modes::Provisioning;
+ static constexpr RestrictionMode::Modes restrictionModeRestricted =
+ RestrictionMode::Modes::ProvisionedHostWhitelist;
+ static constexpr RestrictionMode::Modes restrictionModeDenyAll =
+ RestrictionMode::Modes::ProvisionedHostDisabled;
+
+ RestrictionMode::Modes restrictionMode = restrictionModeRestricted;
+ bool postCompleted = false;
+ std::shared_ptr<sdbusplus::asio::connection> bus;
+ std::unique_ptr<sdbusplus::bus::match::match> modeChangeMatch;
+ std::unique_ptr<sdbusplus::bus::match::match> modeIntfAddedMatch;
+ std::unique_ptr<sdbusplus::bus::match::match> postCompleteMatch;
+ std::unique_ptr<sdbusplus::bus::match::match> postCompleteIntfAddedMatch;
+
+ static constexpr const char restrictionModeIntf[] =
+ "xyz.openbmc_project.Control.Security.RestrictionMode";
+ static constexpr const char* systemOsStatusIntf =
+ "xyz.openbmc_project.State.OperatingSystem.Status";
+};
+
+WhitelistFilter::WhitelistFilter()
+{
+ bus = getSdBus();
+
+ log<level::INFO>("Loading whitelist filter");
+
+ ipmi::registerFilter(ipmi::prioOpenBmcBase,
+ [this](ipmi::message::Request::ptr request) {
+ return filterMessage(request);
+ });
+
+ // wait until io->run is going to fetch RestrictionMode
+ post_work([this]() { postInit(); });
+}
+
+void WhitelistFilter::cacheRestrictedAndPostCompleteMode()
+{
+ std::string restrictionModePath;
+ std::string restrictionModeService;
+ std::string systemOsStatusPath;
+ std::string systemOsStatusService;
+ try
+ {
+ ipmi::DbusObjectInfo restrictionObj =
+ ipmi::getDbusObject(*bus, restrictionModeIntf);
+
+ restrictionModePath = restrictionObj.first;
+ restrictionModeService = restrictionObj.second;
+
+ ipmi::DbusObjectInfo postCompleteObj =
+ ipmi::getDbusObject(*bus, systemOsStatusIntf);
+
+ systemOsStatusPath = postCompleteObj.first;
+ systemOsStatusService = postCompleteObj.second;
+ }
+ catch (const std::exception&)
+ {
+ log<level::ERR>(
+ "Could not initialize provisioning mode, defaulting to restricted",
+ entry("VALUE=%d", static_cast<int>(restrictionMode)));
+ return;
+ }
+
+ bus->async_method_call(
+ [this](boost::system::error_code ec, ipmi::Value v) {
+ if (ec)
+ {
+ log<level::ERR>(
+ "Could not initialize provisioning mode, "
+ "defaulting to restricted",
+ entry("VALUE=%d", static_cast<int>(restrictionMode)));
+ return;
+ }
+ auto mode = std::get<std::string>(v);
+ restrictionMode = RestrictionMode::convertModesFromString(mode);
+ log<level::INFO>(
+ "Read restriction mode",
+ entry("VALUE=%d", static_cast<int>(restrictionMode)));
+ },
+ restrictionModeService, restrictionModePath,
+ "org.freedesktop.DBus.Properties", "Get", restrictionModeIntf,
+ "RestrictionMode");
+
+ bus->async_method_call(
+ [this](boost::system::error_code ec, const ipmi::Value& v) {
+ if (ec)
+ {
+ log<level::ERR>("Error in OperatingSystemState Get");
+ postCompleted = true;
+ return;
+ }
+ auto value = std::get<std::string>(v);
+ if (value == "Standby")
+ {
+ postCompleted = true;
+ }
+ else
+ {
+ postCompleted = false;
+ }
+ log<level::INFO>("Read POST complete value",
+ entry("VALUE=%d", postCompleted));
+ },
+ systemOsStatusService, systemOsStatusPath,
+ "org.freedesktop.DBus.Properties", "Get", systemOsStatusIntf,
+ "OperatingSystemState");
+}
+
+void WhitelistFilter::updateRestrictionMode(const std::string& value)
+{
+ restrictionMode = RestrictionMode::convertModesFromString(value);
+ log<level::INFO>("Updated restriction mode",
+ entry("VALUE=%d", static_cast<int>(restrictionMode)));
+}
+
+void WhitelistFilter::handleRestrictedModeChange(sdbusplus::message::message& m)
+{
+ std::string signal = m.get_member();
+ if (signal == "PropertiesChanged")
+ {
+ std::string intf;
+ std::vector<std::pair<std::string, ipmi::Value>> propertyList;
+ m.read(intf, propertyList);
+ for (const auto& property : propertyList)
+ {
+ if (property.first == "RestrictionMode")
+ {
+ updateRestrictionMode(std::get<std::string>(property.second));
+ }
+ }
+ }
+ else if (signal == "InterfacesAdded")
+ {
+ sdbusplus::message::object_path path;
+ DbusInterfaceMap restModeObj;
+ m.read(path, restModeObj);
+ auto intfItr = restModeObj.find(restrictionModeIntf);
+ if (intfItr == restModeObj.end())
+ {
+ return;
+ }
+ PropertyMap& propertyList = intfItr->second;
+ auto itr = propertyList.find("RestrictionMode");
+ if (itr == propertyList.end())
+ {
+ return;
+ }
+ updateRestrictionMode(std::get<std::string>(itr->second));
+ }
+}
+
+void WhitelistFilter::updatePostComplete(const std::string& value)
+{
+ if (value == "Standby")
+ {
+ postCompleted = true;
+ }
+ else
+ {
+ postCompleted = false;
+ }
+ log<level::INFO>(postCompleted ? "Updated to POST Complete"
+ : "Updated to !POST Complete");
+}
+
+void WhitelistFilter::handlePostCompleteChange(sdbusplus::message::message& m)
+{
+ std::string signal = m.get_member();
+ if (signal == "PropertiesChanged")
+ {
+ std::string intf;
+ std::vector<std::pair<std::string, ipmi::Value>> propertyList;
+ m.read(intf, propertyList);
+ for (const auto& property : propertyList)
+ {
+ if (property.first == "OperatingSystemState")
+ {
+ updatePostComplete(std::get<std::string>(property.second));
+ }
+ }
+ }
+ else if (signal == "InterfacesAdded")
+ {
+ sdbusplus::message::object_path path;
+ DbusInterfaceMap postCompleteObj;
+ m.read(path, postCompleteObj);
+ auto intfItr = postCompleteObj.find(systemOsStatusIntf);
+ if (intfItr == postCompleteObj.end())
+ {
+ return;
+ }
+ PropertyMap& propertyList = intfItr->second;
+ auto itr = propertyList.find("OperatingSystemState");
+ if (itr == propertyList.end())
+ {
+ return;
+ }
+ updatePostComplete(std::get<std::string>(itr->second));
+ }
+}
+void WhitelistFilter::postInit()
+{
+ // Wait for changes on Restricted mode
+ namespace rules = sdbusplus::bus::match::rules;
+ const std::string filterStrModeChange =
+ rules::type::signal() + rules::member("PropertiesChanged") +
+ rules::interface("org.freedesktop.DBus.Properties") +
+ rules::argN(0, restrictionModeIntf);
+
+ const std::string filterStrModeIntfAdd =
+ rules::interfacesAdded() +
+ rules::argNpath(
+ 0, "/xyz/openbmc_project/control/security/restriction_mode");
+
+ const std::string filterStrPostComplete =
+ rules::type::signal() + rules::member("PropertiesChanged") +
+ rules::interface("org.freedesktop.DBus.Properties") +
+ rules::argN(0, systemOsStatusIntf);
+
+ const std::string filterStrPostIntfAdd =
+ rules::interfacesAdded() +
+ rules::argNpath(0, "/xyz/openbmc_project/state/os");
+
+ modeChangeMatch = std::make_unique<sdbusplus::bus::match::match>(
+ *bus, filterStrModeChange, [this](sdbusplus::message::message& m) {
+ handleRestrictedModeChange(m);
+ });
+ modeIntfAddedMatch = std::make_unique<sdbusplus::bus::match::match>(
+ *bus, filterStrModeIntfAdd, [this](sdbusplus::message::message& m) {
+ handleRestrictedModeChange(m);
+ });
+
+ postCompleteMatch = std::make_unique<sdbusplus::bus::match::match>(
+ *bus, filterStrPostComplete, [this](sdbusplus::message::message& m) {
+ handlePostCompleteChange(m);
+ });
+
+ postCompleteIntfAddedMatch = std::make_unique<sdbusplus::bus::match::match>(
+ *bus, filterStrPostIntfAdd, [this](sdbusplus::message::message& m) {
+ handlePostCompleteChange(m);
+ });
+
+ // Initialize restricted mode
+ cacheRestrictedAndPostCompleteMode();
+}
+
+ipmi::Cc WhitelistFilter::filterMessage(ipmi::message::Request::ptr request)
+{
+ auto channelMask = static_cast<unsigned short>(1 << request->ctx->channel);
+ bool whitelisted = std::binary_search(
+ whitelist.cbegin(), whitelist.cend(),
+ std::make_tuple(request->ctx->netFn, request->ctx->cmd, channelMask),
+ [](const netfncmd_tuple& first, const netfncmd_tuple& value) {
+ return (std::get<2>(first) & std::get<2>(value))
+ ? first < std::make_tuple(std::get<0>(value),
+ std::get<1>(value),
+ std::get<2>(first))
+ : first < value;
+ });
+
+ // no special handling for non-system-interface channels
+ if (request->ctx->channel != ipmi::channelSystemIface)
+ {
+ if (!whitelisted)
+ {
+ log<level::INFO>("Channel/NetFn/Cmd not whitelisted",
+ entry("CHANNEL=0x%X", request->ctx->channel),
+ entry("NETFN=0x%X", int(request->ctx->netFn)),
+ entry("CMD=0x%X", int(request->ctx->cmd)));
+ return ipmi::ccCommandNotAvailable;
+ }
+ return ipmi::ccSuccess;
+ }
+
+ // for system interface, filtering is done as follows:
+ // Allow All: preboot ? ccSuccess : ccSuccess
+ // Restricted: preboot ? ccSuccess :
+ // ( whitelist ? ccSuccess : // ccCommandNotAvailable )
+ // Deny All: preboot ? ccSuccess : ccCommandNotAvailable
+
+ if (!postCompleted)
+ {
+ // Allow all commands, till POST is not completed
+ return ipmi::ccSuccess;
+ }
+
+ switch (restrictionMode)
+ {
+ case RestrictionMode::Modes::None:
+ case restrictionModeAllowAll:
+ {
+ // Allow All
+ return ipmi::ccSuccess;
+ break;
+ }
+ case restrictionModeRestricted:
+ {
+ // Restricted - follow whitelist
+ break;
+ }
+ case restrictionModeDenyAll:
+ {
+ // Deny All
+ whitelisted = false;
+ break;
+ }
+ default: // for whitelist and blacklist
+ return ipmi::ccCommandNotAvailable;
+ }
+
+ if (!whitelisted)
+ {
+ log<level::INFO>("Channel/NetFn/Cmd not whitelisted",
+ entry("CHANNEL=0x%X", request->ctx->channel),
+ entry("NETFN=0x%X", int(request->ctx->netFn)),
+ entry("CMD=0x%X", int(request->ctx->cmd)));
+ return ipmi::ccCommandNotAvailable;
+ }
+ return ipmi::ccSuccess;
+} // namespace
+
+// instantiate the WhitelistFilter when this shared object is loaded
+WhitelistFilter whitelistFilter;
+
+} // namespace
+
+} // namespace ipmi