summaryrefslogtreecommitdiff
path: root/lib/ipmi_sdr.c
diff options
context:
space:
mode:
authorAlexander Amelkin <alexander@amelkin.msk.ru>2019-04-19 15:07:25 +0300
committerAlexander Amelkin <mocbuhtig@amelkin.msk.ru>2019-05-27 15:38:23 +0300
commit12e2f5da63fcfdb544f87ec492e5b1bc4f89868c (patch)
tree25662c4198425db4c6acfb437e43a2c31c921d6c /lib/ipmi_sdr.c
parentd818c2ff85c011be29c8d3047e516a5e032a1923 (diff)
downloadipmitool-12e2f5da63fcfdb544f87ec492e5b1bc4f89868c.tar.gz
sdr: Fix segfault on invalid unit types
The program would crash if the BMC returned an out of range (>90) unit type for a full sensor record. This commit adds a range check and also add support for IPMI 2.0 additional unit types 91 and 92 ("fatal error" and "grams"). Resolves ipmitool/ipmitool#118 Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
Diffstat (limited to 'lib/ipmi_sdr.c')
-rw-r--r--lib/ipmi_sdr.c72
1 files changed, 50 insertions, 22 deletions
diff --git a/lib/ipmi_sdr.c b/lib/ipmi_sdr.c
index eb40b36..b43765a 100644
--- a/lib/ipmi_sdr.c
+++ b/lib/ipmi_sdr.c
@@ -68,8 +68,9 @@ static struct sdr_record_list *sdr_list_head = NULL;
static struct sdr_record_list *sdr_list_tail = NULL;
static struct ipmi_sdr_iterator *sdr_list_itr = NULL;
-/* unit description codes (IPMI v1.5 section 37.16) */
-#define UNIT_MAX 0x90
+/* IPMI 2.0 Table 43-15, Sensor Unit Type Codes */
+#define UNIT_TYPE_MAX 92 /* This is the ID of "grams" */
+#define UNIT_TYPE_LONGEST_NAME 19 /* This is the length of "color temp deg K" */
static const char *unit_desc[] = {
"unspecified",
"degrees C",
@@ -161,7 +162,9 @@ static const char *unit_desc[] = {
"characters",
"error",
"correctable error",
- "uncorrectable error"
+ "uncorrectable error",
+ "fatal error",
+ "grams"
};
/* sensor type codes (IPMI v1.5 table 36.3)
@@ -220,35 +223,60 @@ void printf_sdr_usage();
uint16_t
ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf);
-/* ipmi_sdr_get_unit_string - return units for base/modifier
+/** ipmi_sdr_get_unit_string - return units for base/modifier
*
- * @pct: units are a percentage
- * @type: unit type
- * @base: base
- * @modifier: modifier
+ * @param[in] pct Indicates that units are a percentage
+ * @param[in] relation Modifier unit to base unit relation
+ * (SDR_UNIT_MOD_NONE, SDR_UNIT_MOD_MUL,
+ * or SDR_UNIT_MOD_DIV)
+ * @param[in] base The base unit type id
+ * @param[in] modifier The modifier unit type id
*
- * returns pointer to static string
+ * @returns a pointer to static string
*/
const char *
-ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifier)
+ipmi_sdr_get_unit_string(bool pct, uint8_t relation,
+ uint8_t base, uint8_t modifier)
{
- static char unitstr[16];
+ /*
+ * Twice as long as the longest possible unit name, plus
+ * two characters for '%' and relation (either '*' or '/'),
+ * plus the terminating null-byte.
+ */
+ static char unitstr[2 * UNIT_TYPE_LONGEST_NAME + 2 + 1];
+
/*
* By default, if units are supposed to be percent, we will pre-pend
* the percent string to the textual representation of the units.
*/
- char *pctstr = pct ? "% " : "";
- memset(unitstr, 0, sizeof (unitstr));
- switch (type) {
- case 2:
- snprintf(unitstr, sizeof (unitstr), "%s%s * %s",
- pctstr, unit_desc[base], unit_desc[modifier]);
+ const char *pctstr = pct ? "% " : "";
+ const char *basestr;
+ const char *modstr;
+
+ if (base <= UNIT_TYPE_MAX) {
+ basestr = unit_desc[base];
+ }
+ else {
+ basestr = "invalid";
+ }
+
+ if (modifier <= UNIT_TYPE_MAX) {
+ modstr = unit_desc[base];
+ }
+ else {
+ modstr = "invalid";
+ }
+
+ switch (relation) {
+ case SDR_UNIT_MOD_MUL:
+ snprintf(unitstr, sizeof (unitstr), "%s%s*%s",
+ pctstr, basestr, modstr);
break;
- case 1:
+ case SDR_UNIT_MOD_DIV:
snprintf(unitstr, sizeof (unitstr), "%s%s/%s",
- pctstr, unit_desc[base], unit_desc[modifier]);
+ pctstr, basestr, modstr);
break;
- case 0:
+ case SDR_UNIT_MOD_NONE:
default:
/*
* Display the text "percent" only when the Base unit is
@@ -257,8 +285,8 @@ ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifi
if (base == 0 && pct) {
snprintf(unitstr, sizeof(unitstr), "percent");
} else {
- snprintf(unitstr, sizeof (unitstr), "%s%s",
- pctstr, unit_desc[base]);
+ snprintf(unitstr, sizeof (unitstr), "%s%s",
+ pctstr, basestr);
}
break;
}