summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Joseph <tomjoseph@in.ibm.com>2016-07-11 06:56:11 -0500
committerPatrick Williams <patrick@stwcx.xyz>2016-08-08 20:05:34 +0000
commit9a61b4f4e9213608653852ba2388fa89663029c3 (patch)
treeb52f1f75a4feeda1c3fbc9284fd17ec910f639ab
parent3551868f8b46bec8711887c72b26f4c628d1600f (diff)
downloadphosphor-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--Makefile14
-rwxr-xr-xgenerate_whitelist.sh27
-rw-r--r--host-ipmid-whitelist.conf24
-rw-r--r--ipmid-api.h1
-rw-r--r--ipmid.C86
-rw-r--r--ipmiwhitelist.H11
6 files changed, 159 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 08900ca..447b129 100644
--- a/Makefile
+++ b/Makefile
@@ -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,
};
diff --git a/ipmid.C b/ipmid.C
index 9590448..7848afe 100644
--- a/ipmid.C
+++ b/ipmid.C
@@ -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
OpenPOWER on IntegriCloud