)]}'
{
  "commit": "36c25549c8b0a5684e5501ca6b6eed04bf79ea9d",
  "tree": "23e0ce4f278d30d7cf70ebaaee02889345e4f0fd",
  "parents": [
    "092ab54ebc57ab35ceddd717701c7c94d732a4e9"
  ],
  "author": {
    "name": "Michael Brown",
    "email": "mcb30@ipxe.org",
    "time": "Wed Aug 05 13:17:16 2026 +0100"
  },
  "committer": {
    "name": "Michael Brown",
    "email": "mcb30@ipxe.org",
    "time": "Wed Aug 05 13:48:16 2026 +0100"
  },
  "message": "[settings] Fix limited out-of-bounds read in fetch_numeric_setting()\n\nThe code in fetch_numeric_setting() reads the setting value into a\nlocal fixed-size buffer but then passes the full setting length to\nnumeric_setting_value().  If the setting length exceeds the size of\nthe fixed-size buffer, then numeric_setting_value() will continue to\nread bytes from the stack.\n\nThe number of bytes read is constrained: numeric_setting_value() will\nexit with -ERANGE as soon as the value being constructed exceeds the\nrange of an unsigned long.  The existence of a return address on the\nstack thus provides an upper bound on how far numeric_setting_value()\ncan read before terminating with an error.\n\nCreating a setting with a length of more than an unsigned long is\ntrivial, for example:\n\n  set thing:hexraw 00000000000000000000000000000000\n\nHowever, the out-of-bounds read can be reached only via calls to the\nfetch_[u]int[z]_setting() family of internal helper functions.\nReading the setting in a script via e.g. ${thing:uint32} goes via a\ndifferent code path that does not use a fixed-length buffer.\n\nThe fetch_[u]int[z]_setting() functions are called from only a few\nplaces.  Most uses are for boolean flags or bit masks.  A few are\ngenuinely used as numeric values: the settings mechanism itself reads\nand uses the \"priority\" setting, the network core reads the \"mtu\"\nsetting, and the SAN boot mechanism reads the drive number and retry\ncount.\n\nAn extremely determined attacker could potentially obtain up to eight\nbytes of information from the stack (in a 64-bit build) by, for\nexample, creating two sibling settings blocks where one has an\noverlength \"priority\" setting value, and then repeatedly manipulating\nthe priority in the other settings block and testing to see which\nblock ends up with the higher priority.  The information that could be\nobtained in this way is limited to the temporary values stored on the\nstack by fetch_numeric_setting() itself, along with its own return\naddress.  None of this information is security-sensitive, and so any\ninformation leakage is a mere curiosity.\n\nFix by allocating a temporary copy within fetch_numeric_setting()\ninstead of using a fixed-size buffer.  This has the downside of\nintroducing an otherwise unnecessary memory allocation (which could\npotentially itself fail), but guarantees consistency with other\nnumeric interpretations of setting values.  (The alternative approach\nof rejecting overlength setting values would introduce a potential\ninconsistency between the value returned by fetch_numeric_setting()\nand the value obtained by formatting a setting using a numeric setting\ntype, or by numerating the setting.)\n\nSigned-off-by: Michael Brown \u003cmcb30@ipxe.org\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "2e576033026154a7bf985c53c4c539a78dad37ff",
      "old_mode": 33188,
      "old_path": "src/core/settings.c",
      "new_id": "221d8a1bd067e2fbc391c45b719770a11ea04031",
      "new_mode": 33188,
      "new_path": "src/core/settings.c"
    }
  ]
}
