diff options
author | Tom Joseph <tomjoseph@in.ibm.com> | 2016-07-11 06:56:11 -0500 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2016-08-08 20:05:34 +0000 |
commit | 9a61b4f4e9213608653852ba2388fa89663029c3 (patch) | |
tree | b52f1f75a4feeda1c3fbc9284fd17ec910f639ab | |
parent | 3551868f8b46bec8711887c72b26f4c628d1600f (diff) | |
download | phosphor-host-ipmid-9a61b4f4e9213608653852ba2388fa89663029c3.tar.gz phosphor-host-ipmid-9a61b4f4e9213608653852ba2388fa89663029c3.zip |
Whitelist IPMI commands based on Restricted mode
Whitelisting of IPMI commands is done to ensure that in restricted
mode only whitelisted commands are executed. Commands that are not
whitelisted is restricted and insufficient privilege is returned as the
completion code.
When the server is deployed it would be set to restricted mode. In this
scenario certain IPMI commands need to be restricted which would not be
added to the whitelist.
Change-Id: I90b8124e34263c4ffc5bcf06a28a7e88231aaf40
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
-rw-r--r-- | Makefile | 14 | ||||
-rwxr-xr-x | generate_whitelist.sh | 27 | ||||
-rw-r--r-- | host-ipmid-whitelist.conf | 24 | ||||
-rw-r--r-- | ipmid-api.h | 1 | ||||
-rw-r--r-- | ipmid.C | 86 | ||||
-rw-r--r-- | ipmiwhitelist.H | 11 |
6 files changed, 159 insertions, 4 deletions
@@ -5,7 +5,8 @@ TESTER = testit TESTADDSEL = testaddsel DAEMON = ipmid -DAEMON_OBJ = ipmid.o +DAEMON_OBJ = ipmid.o \ + ipmiwhitelist.o LIB_APP_OBJ = apphandler.o \ sensorhandler.o \ @@ -44,8 +45,14 @@ SBINDIR ?= /usr/sbin INCLUDEDIR ?= /usr/include LIBDIR ?= /usr/lib +WHITELIST_SRC = ipmiwhitelist.C +WHITELIST_CONF ?= host-ipmid-whitelist.conf + all: $(DAEMON) $(LIB_APP) $(LIB_HOST_SRV) $(TESTER) +$(WHITELIST_SRC) : generate_whitelist.sh $(WHITELIST_CONF) + ./$^ > $@ + %.o: %.C $(CXX) -std=c++14 -fpic -c $< $(CXXFLAGS) $(INC_FLAG) $(IPMID_PATH) -o $@ @@ -62,11 +69,11 @@ $(TESTER): $(TESTER_OBJ) $(CXX) $^ $(LDFLAGS) $(LIB_FLAG) -o $@ -ldl clean: - rm -f $(DAEMON) $(TESTER) *.o *.so + rm -f $(DAEMON) $(TESTER) *.o *.so $(WHITELIST_SRC) $(TESTADDSEL): $(TESTADDSEL_OBJ) $(CXX) $^ $(LDFLAGS) $(LIB_FLAG) -o $@ -ldl - + install: install -m 0755 -d $(DESTDIR)$(SBINDIR) install -m 0755 ipmid $(DESTDIR)$(SBINDIR) @@ -75,3 +82,4 @@ install: install -m 0755 -d $(DESTDIR)$(INCLUDEDIR)/host-ipmid install -m 0644 $(INSTALLED_HEADERS) $(DESTDIR)$(INCLUDEDIR)/host-ipmid + diff --git a/generate_whitelist.sh b/generate_whitelist.sh new file mode 100755 index 0000000..e0dded3 --- /dev/null +++ b/generate_whitelist.sh @@ -0,0 +1,27 @@ +#/bin/sh + +# Ensure some files have been passed. +if [ "x$*" == "x" ]; then + echo "Usage: $0 [whitelist_files+]" >&2 + exit -1 +fi + +cat << EOF +#include <ipmiwhitelist.H> + +const std::vector<netfncmd_pair> whitelist = { + +EOF + +# Output each row of whitelist vector. +# Concatenate all the passed files. +# Remove comments and empty lines. +# Sort the list [numerically]. +# Remove any duplicates. +# Turn "a:b //<NetFn>:<Command>" -> "{ a, b }, //<NetFn>:<Command>" +cat $* | sed "s/#.*//" | sed '/^$/d' | sort -n | uniq | sed "s/^/ { /" | \ + sed "s/\:\(....\)\(.*\)/ , \1 }, \2/" + +cat << EOF +}; +EOF diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf new file mode 100644 index 0000000..bd02898 --- /dev/null +++ b/host-ipmid-whitelist.conf @@ -0,0 +1,24 @@ +#<NetFn>:<Command> +0x00:0x02 //<Chassis>:<Chassis Control> +0x00:0x08 //<Chassis>:<Set System Boot Options> +0x00:0x09 //<Chassis>:<Get System Boot Options> +0x04:0x2D //<Sensor/Event>:<Get Sensor Reading> +0x04:0x2F //<Sensor/Event>:<Get Sensor Type> +0x04:0x30 //<Sensor/Event>:<Set Sensor Reading and Event Status> +0x06:0x01 //<App>:<Get Device ID> +0x06:0x08 //<App>:<Get Device GUID> +0x06:0x22 //<App>:<Reset Watchdog Timer> +0x06:0x24 //<App>:<Set Watchdog Timer> +0x06:0x2E //<App>:<Set BMC Global Enables> +0x06:0x31 //<App>:<Get Message Flags> +0x06:0x35 //<App>:<Read Event Message Buffer> +0x06:0x36 //<App>:<Get BT Interface Capabilities> +0x06:0x42 //<App>:<Get Channel Info Command> +0x0A:0x40 //<Storage>:<Get SEL Info> +0x0A:0x42 //<Storage>:<Reserve SEL> +0x0A:0x44 //<Storage>:<Add SEL Entry> +0x0A:0x48 //<Storage>:<Get SEL Time> +0x0A:0x49 //<Storage>:<Set SEL Time> +0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters> +0x2C:0x00 //<Group Extension>:<Group Extension Command> +0x2C:0x03 //<Group Extension>:<Get Power Limit> diff --git a/ipmid-api.h b/ipmid-api.h index cf3eaab..0c92069 100644 --- a/ipmid-api.h +++ b/ipmid-api.h @@ -97,6 +97,7 @@ enum ipmi_return_codes IPMI_CC_PARM_OUT_OF_RANGE = 0xC9, IPMI_CC_SENSOR_INVALID = 0xCB, IPMI_CC_RESPONSE_ERROR = 0xCE, + IPMI_CC_INSUFFICIENT_PRIVILEGE = 0xD4, IPMI_CC_UNSPECIFIED_ERROR = 0xFF, }; @@ -13,10 +13,17 @@ #include <errno.h> #include <mapper.h> #include "sensorhandler.h" +#include <vector> +#include <algorithm> +#include <iterator> +#include <ipmiwhitelist.H> sd_bus *bus = NULL; sd_bus_slot *ipmid_slot = NULL; +// Initialise restricted mode to true +bool restricted_mode = true; + FILE *ipmiio, *ipmidbus, *ipmicmddetails; void print_usage(void) { @@ -27,10 +34,15 @@ void print_usage(void) { fprintf(stderr, " mask : 0xFF - Print all trace\n"); } +// Host settings in DBUS +constexpr char settings_host_bus[] = "org.openbmc.settings.Host"; +constexpr char settings_host_object[] = "/org/openbmc/settings/host0"; +constexpr char settings_host_intf[] = "org.freedesktop.DBus.Properties"; + const char * DBUS_INTF = "org.openbmc.HostIpmi"; const char * FILTER = "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'"; - +constexpr char RESTRICTED_MODE_FILTER[] = "type='signal',interface='org.freedesktop.DBus.Properties',path='/org/openbmc/settings/host0'"; typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t; typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t; @@ -128,6 +140,22 @@ ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t // return from the Command handlers. ipmi_ret_t rc = IPMI_CC_INVALID; + // If restricted mode is true and command is not whitelisted, don't + // execute the command + if(restricted_mode) + { + if (!std::binary_search(whitelist.cbegin(), whitelist.cend(), + std::make_pair(netfn, cmd))) + { + printf("Net function:[0x%X], Command:[0x%X] is not whitelisted\n", + netfn, cmd); + rc = IPMI_CC_INSUFFICIENT_PRIVILEGE; + memcpy(response, &rc, IPMI_CC_LEN); + *data_len = IPMI_CC_LEN; + return rc; + } + } + // Walk the map that has the registered handlers and invoke the approprite // handlers for matching commands. auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd)); @@ -237,6 +265,53 @@ final: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } +void cache_restricted_mode() +{ + sd_bus *bus = ipmid_get_sd_bus_connection(); + sd_bus_message *reply = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + int rc = 0; + + rc = sd_bus_call_method(bus, + settings_host_bus, + settings_host_object, + settings_host_intf, + "Get", + &error, + &reply, + "ss", + settings_host_bus, + "restricted_mode"); + if(rc < 0) + { + fprintf(stderr, "Failed sd_bus_call_method method for restricted mode: %s\n", + strerror(-rc)); + goto cleanup; + } + + rc = sd_bus_message_read(reply, "v", "b", &restricted_mode); + if(rc < 0) + { + fprintf(stderr, "Failed to parse response message for restricted mode: %s\n", + strerror(-rc)); + // Fail-safe to restricted mode + restricted_mode = true; + } + + printf("Restricted mode = %d\n", restricted_mode); + +cleanup: + sd_bus_error_free(&error); + reply = sd_bus_message_unref(reply); +} + +static int handle_restricted_mode_change(sd_bus_message *m, void *user_data, + sd_bus_error *ret_error) +{ + cache_restricted_mode(); + return 0; +} + static int handle_ipmi_command(sd_bus_message *m, void *user_data, sd_bus_error *ret_error) { int r = 0; @@ -444,6 +519,15 @@ int main(int argc, char *argv[]) goto finish; } + // Wait for changes on Restricted mode + r = sd_bus_add_match(bus, &ipmid_slot, RESTRICTED_MODE_FILTER, handle_restricted_mode_change, NULL); + if (r < 0) { + fprintf(stderr, "Failed: sd_bus_add_match: %s : %s\n", strerror(-r), RESTRICTED_MODE_FILTER); + goto finish; + } + + // Initialise restricted mode + cache_restricted_mode(); for (;;) { /* Process requests */ diff --git a/ipmiwhitelist.H b/ipmiwhitelist.H new file mode 100644 index 0000000..b07451a --- /dev/null +++ b/ipmiwhitelist.H @@ -0,0 +1,11 @@ +#ifndef __HOST_IPMID_IPMI_WHITELIST_H__ +#define __HOST_IPMID_IPMI_WHITELIST_H_ + +#include <vector> +#include <utility> + +using netfncmd_pair = std::pair<unsigned char, unsigned char>; + +extern const std::vector<netfncmd_pair> whitelist; + +#endif |