summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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