diff options
-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 |