| Age | Commit message (Collapse) | Author | Files | Lines |
|
Extract the long signal handler lambda in startAsyncWaitForSignal() into
a named member function, afterWaitForSignal(), bound via
std::bind_front(), per the <10 line lambda coding standard in
docs/COMMON_ERRORS.md.
Tested on AST2600 SoC:
- `kill -HUP <bmcweb pid>`, then `GET /redfish/v1/`
Expected: cert reload, service stays active, 200 OK
Actual: bmcweb.service remained active, GET returned HTTP 200
- `kill -TERM <bmcweb pid>`
Expected: clean shutdown
Actual: journalctl confirmed "bmcweb.service: Deactivated
successfully"
- RSV: 5845 Pass / 353 Warn / 0 Fail
Change-Id: Id02f26fd680ae34639b521962b0f4e3d67c534bc
Signed-off-by: Yuvakumar Selvamani <yuvakumars@ami.com>
|
|
Move long lambdas in getUserInfo() and onRequestRecv() into named
functions, afterGetUserInfo() and afterCompleteRequest(), per the <10
line lambda rule in docs/COMMON_ERRORS.md. No functional change.
Tested:
- Tested on AST2600 SoC.
- getUserInfo/afterGetUserInfo: sent an authenticated Basic-auth Redfish
GET and confirmed a 200 response with no "Failed to populate user
information" error in journalctl, proving populateUserInfo() succeeded
via the extracted callback.
- onRequestRecv/afterCompleteRequest: RSV's client uses HTTP/1.1, so it
does not exercise this HTTP/2-only code path. Instead, used
"curl --http2" and confirmed ALPN negotiated h2 and the request
completed as HTTP/2 200. journalctl -u bmcweb confirmed both
"onRequestRecv streamId:1" and the extracted callback's
"res.completeRequestHandler called" fired for that stream.
- Redfish Service Validator: 5830 Pass / 353 Warn / 0 Fail.
Change-Id: I0e6365c682f6acc8d39510ad5f1fe239d747154f
Signed-off-by: Yuvakumar Selvamani <yuvakumars@ami.com>
|
|
Extract the long completion lambda in handleMessage() into a named
member function, afterHandleMessage(), bound via std::bind_front(), per
the <10 line lambda coding standard in docs/COMMON_ERRORS.md.
Tested:
- No functional change.
- Build successfully compiled.
- Redfish Service Validator passed with no new errors or warnings
introduced.
Change-Id: I54f4cbee152c04c2bd083e5fbbf6859b8277b887
Signed-off-by: Yuvakumar Selvamani <yuvakumars@ami.com>
|
|
Previously, http2 disconnects that weren't cleanly stopped in openssl
would result in a log message like:
'''
[http2_connection.hpp:998] 0x2bba5e0 Error while reading: stream truncated
'''
While it's valid to log that a client disconnected unclealy, clients
seem to do this and clog up the logs.
Tested: Redfish Service validator passes.
I don't have a client that reproduces this; Inspection only.
Change-Id: I9205500171912f7d82b31487b7df8d1a293d8c89
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
We have experienced a `std::bad_function_call` exception [1].
The journal entries are showing
```
Jun 17 15:27:21.985663 bmcwebd[1995]: [http_client.hpp:391] recvMessage() failed: asio.ssl error from https://10.5.10.140:17443/redfish/events
Jun 17 15:27:22.043798 bmcwebd[1995]: [http_client.hpp:391] recvMessage() failed: stale parser from https://10.5.10.140:17443/redfish/events
Jun 17 15:27:22.085644 bmcwebd[1995]: terminate called after throwing an instance of 'std::bad_function_call'
Jun 17 15:27:22.086908 bmcwebd[1995]: what(): bad_function_call
Jun 17 15:27:22.163520 systemd-coredump[4621]: Process 1995 (bmcwebd) of user 0 terminated abnormally with signal 6/ABRT
```
The matching line is
```
void recvMessage(const std::shared_ptr<ConnectionInfo>& /*self*/,
const boost::system::error_code& ec,
std::size_t bytesTransferred)
{
...
callback(parser->keep_alive(), connId, res);
...
}
```
This would imply that the callback function pointer became null when it
is invoked.
```
void sendNext(bool keepAlive, uint32_t connId)
{
...
conn->callback = nullptr;
...
}
```
This may be happening due to the race condition between multiple async
operations where the async call is waiting to be invoked but sendNext is
executed first.
This commit is to make the defensive checking of `callback` function
pointer before invoking like
```
if (callback) {
callback(parser->keep_alive(), connId, res);
}
```
[1] https://en.cppreference.com/cpp/utility/functional/bad_function_call
Change-Id: Ic23e17ea486433e3bb7493e8e3c1e56b1798c8e9
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
|
|
Add Response::headerCount() to return the total number of
stored header fields on a response. The implementation counts
the current header entries directly from the underlying Beast
header container.
Added unit coverage to verify the method reports the full
header count after headers are added through the normal
addHeader() path.
Tested with:
meson test -C build http_response_test --print-errorlogs
This helper is used by response unit tests to verify that only
the expected headers are present and that no unexpected headers
are added to the response. See also:
https://gerrit.openbmc.org/c/openbmc/bmcweb/+/91848
Change-Id: I28432bb4fc982db44cee0688395d04ac513d6749
Signed-off-by: Joel Pullokaran Jesin <joelpj@ami.com>
|
|
This regressed when the bypass was added. Fix the code for
resolver=asio to properly construct the results object using the built
in asio type instead of std::vector.
Tested: Code compiles with resolver=asio again.
Change-Id: I3d9ddc38b88a392cf82fc81bd5609f3360837393
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
parseStringAsJson() routes through BmcwebSaxParse, which hard-caps a
payload at 500 total JSON values to defend against malicious external
HTTP request bodies.
The most visible symptom is that bmcweb silently loses every persisted
session across a restart once ~50 sessions accumulate (each persisted
session is ~11 JSON values, so the file trips the cap and is treated
as malformed). Tntegration testing hit this 50 session limit and
failed. (Was failing our internal but also the
openbmc-test-automation robot suite)
I had originally implemented a solution as a "trusted reader"
with no limit
( https://gerrit.openbmc.org/c/openbmc/bmcweb/+/90138 ); however,
the security implications of "no limit" weren't attractive.
This area may be refactored in the near future to represent each
session as a distinct json file. This value bump gets us past
the immediate needs without introducing a lot of churn in code
that will be refactored.
Change-Id: Ifd3514bd8ee15c8bdf1b6c2119451a2965801671
Signed-off-by: Rick Yazwinski <rickyaz@meta.com>
|
|
Long lambdas have been documented as an anti-pattern for some time.[1]
Despite this being generally understood, bmcweb has a long ways to go
cleaning these up, and routinely code is submitted in violation of this
anti-pattern.
Invent an ast-grep rule that can identify when new examples of this
anti-pattern are added, and ignore the existing 200+ examples that are
in the codebase already using ast-grep ignore. These flags will give us
something to search for as we clean this up, and will help to prevent
new instances from being added unintentionally.
[1] https://github.com/openbmc/docs/blob/master/anti-patterns.md#very-long-lambda-callbacks
Tested: Comment only change. ast-grep passes. Manually removing an
ast-grep ignore flag shows as a failure in ast-grep scan
Change-Id: I77d634a393884969f184d2c39c02cc08288d5a29
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
bmcweb HTTP server accept handling had a critical bug where a single
socket pointer was reused across multiple acceptors, causing undefined
behavior and potential crashes.
1. Move socket creation into doAcceptOne() to ensure each acceptor
creates its own unique socket instance.
2. Pass acceptor pointer to afterAccept() callback to track which
acceptor completed the accept operation.
3. Replace doAccept() call with doAcceptOne() in afterAccept() to
resume accepting on only the specific acceptor that handled the
connection, not all acceptors.
This ensures proper socket lifecycle management and prevents race
conditions from shared socket instances.
Tested:
HTTP server accepts connections correctly with multiple
acceptors (HTTP/HTTPS) without crashes or undefined behavior.
Change-Id: I0540802cdd682e8e7d7312d6edfd5651bf09378a
Signed-off-by: Kokilambal Varadhan <kokilavaradhan@gmail.com>
|
|
HTTP/2 connections were not passing the resolved client IP into
the per-request ipAddress field, causing sessions to report
0.0.0.0 instead of the actual client address.
Additionally, authentication::authenticate() was called with an
empty IP, resulting in Basic Auth sessions being created with
an incorrect clientIp in the session store.
Pass the IP through the HTTP2Connection constructor, use it in
the authenticate() call, and assign it to req->ipAddress during
request dispatch in onRequestRecv.
Tested:
- Client IP correctly displayed in Redfish SessionService
on HTTP/2 connections.
- Before patch: ClientOriginIPAddress showed "0.0.0.0"
- After patch: ClientOriginIPAddress shows actual client IP
- Redfish Service Validator (v3.1.4) passed on
/redfish/v1/SessionService tree:
PASS: 44, WARN: 0, FAIL: 0, NOT TESTED: 41
Before:
curl -k https://127.0.0.1:2443/redfish/v1/\
SessionService/Sessions/O9gUpSoxbe -u root:0penBmc
{
"@odata.id": "/redfish/v1/SessionService/Sessions/O9gUpSoxbe",
"@odata.type": "#Session.v1_7_0.Session",
"ClientOriginIPAddress": "0.0.0.0",
"Description": "Manager User Session",
"Id": "O9gUpSoxbe",
"Name": "User Session",
"Roles": [
"Administrator"
],
"UserName": "root"
}
After this patch:
curl -k https://172.31.216.225/redfish/v1/\
SessionService/Sessions/LuttjprSGD -u root:0penBmc
{
"@odata.id": "/redfish/v1/SessionService/Sessions/LuttjprSGD",
"@odata.type": "#Session.v1_7_0.Session",
"ClientOriginIPAddress": "10.0.136.165",
"Description": "Manager User Session",
"Id": "LuttjprSGD",
"Name": "User Session",
"Roles": [
"Administrator"
],
"UserName": "root"
}
Change-Id: I223e5c90448419ba87b690de38cc5e69ffb6a0c3
Signed-off-by: Vijaysankar Ravi <vijaysankarr@ami.com>
|
|
Continue moving OpenSSL into reusable RAII classes that can be used in
unit tests and other places. This is slightly more code, but as we're
adding unit tests, it allows reuse between unit tests rather than
writing C directly. It also encapsulates the complexity of parsing
openssl output (usually in bytes) into standard types (string) that can
be compared/modified.
Functionally this adds two new classes to the "wrappers" functions,
OpenSSLSSLCtx and OpenSSLSSL, which each wrap SSL_CTX and SSL objects
respectively from openssl. These are rough approximations of the boost
equivalents.
Change-Id: Id87ac4ccde88890bd70861deffdb256188ec0e39
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
Add specific warning for empty or missing Content-Type header to help
debug malformed Redfish requests. Keep existing warning for invalid
content types. Avoid reflecting user-controlled input such as URL or
header values in log messages to prevent log flooding from malicious
requests.
Tested: Verified log message appears when Content-Type header is
empty. Confirmed no user input is reflected in logs. Verified warning
still appears for invalid content types like text/plain. Tested on
Ubuntu 24.04.1 LTS.
Change-Id: I6b873e8f7517aaea1a010bf9cbb5533a410e1b21
Signed-off-by: Akash Arunkumar <mirrorghost007@gmail.com>
|
|
Commit 2d7dc991 changed the body storage from being saved in a separate
field to a std::variant. Calling str() calls emplace<std::string>(),
which destroys the active FileBody in-place on file-backed bodies (e.g.
the Web UI) and closes the FD.
Any subsequent action now tries to access a non-existing FD (dummy
handle returning -1 as FD.)
Fix by returning early from `attemptZstdCompression` when the body is
file-backed, as file-backed bodies are already handled by the streaming
zstdCompressor in the writer.
Tested: cURL with "Accept-Encoding: zstd" to favicon.ico, ensuring that
it returns data again.
Fixes: 2d7dc991 ("Optimize bmcweb memory usage for multipart fw
update")
Change-Id: Ia54712f89d8c5f7dc9ce7c5d040aed06e8f6fded
Signed-off-by: Tan Siewert <tan.siewert@9elements.com>
|
|
Issue:
BMCWeb crashes with segmentation fault when HTTP client connections are
rapidly created and destroyed while async operations are pending. This
occurs during event subscription deletion, BMCWeb shutdown, or network
timeout scenarios where ConnectionPool is destroyed while callbacks are
still executing.
Root Cause:
Race condition between async callback execution and ConnectionPool
destruction leads to three failure modes:
1. Out-of-bounds vector access in sendNext() when connId is invalid
2. Null pointer dereference when connection pointer is null
3. Use-after-free when callback executes after pool destruction
The issue manifests as:
- Segmentation fault in sendNext()
- Crash in afterSendData() when accessing destroyed pool
- Invalid memory access during callback execution
Key Fixes:
1. Bounds Checking
- Validate connId < connections.size() before vector access
- Prevents segmentation fault from out-of-bounds access
- Returns early with error log if connId invalid
2. Null Pointer Validation
- Check if connection pointer is null before dereferencing
- Provides graceful error handling instead of crash
- Logs error and returns safely
3. Reordered afterSendData()
- Check ConnectionPool validity BEFORE calling user callback
- Prevents callback execution if pool has been destroyed
- Ensures safe early return if pool no longer exists
Testing:
Reproduced coredump by simulating aggressive client behavior:
- Client rapidly creates HTTP connections to BMCWeb
- Client sends POST requests to create event subscriptions
- Client abruptly closes connections during SSL handshake
- Client destroys sessions while async operations are pending
- This triggers race condition where callbacks execute after
ConnectionPool destruction
Example Python code that reproduces the issue:
```
for i in range(100):
session = requests.Session()
session.post('https://bmc/redfish/v1/EventService/Subscriptions',
json={'Destination': 'http://192.0.2.1:8080/events'})
time.sleep(0.01) # Brief delay
session.close() # Abrupt destruction while request pending
del session
```
Before fix:
- Segmentation fault in sendNext()
- BMCWeb process crashes
- Coredump generated
After fix:
- No coredumps detected
- BMCWeb process remains stable
- Graceful error handling with log messages:
"Invalid connId: X (size: Y)"
"Connection at index X is null"
"Failed to capture connection"
Expected logs during aggressive client testing (normal behavior):
- SSL handshake failures (client abruptly disconnects)
- Authentication failures (connections close during auth)
- No segmentation faults or process crashes
Verification:
coredumpctl list bmcweb # No new coredumps
systemctl status bmcweb # Process still running
dmesg | grep segfault # No segmentation faults
Change-Id: I7b7a61aa8fcce1e32b5e3893da5ff0d5b3e3344f
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
|
|
Have seen this a few times where the BMC is spammed by some client and
bmcweb hits its max connections. Have also gotten feedback that the
current "Max connection count exceeded." isn't very useful since it
doesn't tell you who is spamming the BMC. These cases have not been
malicious, instead an automated malfunctioning network agent.
Even if they were malicious recording/printing the IP address of the
attacker is referenced by several documents on detecting and responding
to a DoS attack. "see a surge in web traffic, seemingly out of nowhere,
that’s coming from the same IP address or range." [1] "An IP address
makes x requests over y seconds" [2]
OpenBMC's security considerations document discusses DoS.[3] bmcweb
doesn't claim to have DoS protection and a best practice is for the BMC
to be on a dedicated management network.
Network Analysis could be used to identify the offending client(s) but
specially for after the fact, having the ip address recorded is more
reliable.
The downside of this change is now when bmcweb is at the max
connections, it is reading the IP Address and keeping the connection
open slightly longer. In practice, did not see a measurable difference.
[1]: https://www.microsoft.com/en-us/security/business/security-101/what-is-a-ddos-attack
[2]: https://www.loggly.com/blog/ddos-monitoring-how-to-know-youre-under-attack/
[3]: https://github.com/openbmc/docs/blob/643e73605907251d80166d3d3c984456fc7fd599/security/network-security-considerations.md
Tested:
200+ concurrent connections with keep-alive true to leave connections.
Sent
```
curl -v -k https://${bmc}/redfish/v1
```
Saw in logs
```
[http_connection.hpp:214] 0x1ab4c70 Max connection count exceeded. Request <IP>
```
Change-Id: Ib9225e0ee67caafe90b958eb89534adfb0831646
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
Signed-off-by: Justin Nguyen <justinnanguyen@gmail.com>
|
|
There was a regression on json parsing due to a merge conflict
resolution on 2d7dc991600297d04e50d7958fe9611f9ac42bcf. Update the
connection unit tests to test the body catching this case, and fix the
error.
Tested: Unit tests pass. Redfish service validator passes
Change-Id: I4ad8802b7c75001ca7a2b1619af2f368bfe448ee
Signed-off-by: Ed Tanous <etanous@nvidia.com>
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
|
|
Users (or attackers) may give bad input to the frontend socket.
Reducing these to warnings means the they will no longer print logs if
given randomized byte input.
Change-Id: Ic78427242bb01e2a1c23a62cbb90af807ed19312
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
Previously, firmware updates via multipart/form-data stored two copies
of the entire upload in memory (200MB+ for a 100MB image). This change
reduces memory usage by incrementally processing multipart data in
chunks, running through the parser as required. This avoids a copy into
the http body. With this change, bmcweb no longer retains any duplicate
copy of the image in memory, thereby limiting memory consumption to
roughly the size of the image itself.
To accomplish this, the multipart parser is rewritten to support
incremental parsing. This should be 100% compatible with the old
parser, with one exception, bytes at the end of the payload are no
longer accepted and ignored.
Tests:
Multipart FW Update using a 114.2MB file shows bmcweb memory usage in
line with one copy of the image, not two. Unit tests pass.
Change-Id: Id18e20004059bfbc7de62f4f6c9542430c7943b0
Signed-off-by: Rajeev Ranjan <ranjan.rajeev1609@gmail.com>
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
In preparation for allowing handlers to "steal" the input (thus saving
memory), make the router pass a non-const Request down the pipeline.
Tested: Redfish service validator passes. No functional changes.
Change-Id: Ic2f44081bc7b6a0e4a82c6ac498eb040574e79be
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
bmcweb openssl usage is a mess. Start cleaning it up.
1. Make RAII objects for any held memory.
2. Move methods from hostname monitor into the ssl namespace, so not all
compile units need to pull in openssl headers
3. Move methods to static where functions can be encapsulated.
Because we're now testing openssl, we need to register memory init so
that the sanitizers don't cause issues when mallocing from non
bootstrapped openssl binaries. Openssl provides a handle for this, so
use it in those unit tests.
Tested:
Unit tests pass. bmcweb launches and can open ssl with curl as it did
previously.
Change-Id: If0340692d2c56a6c45bb8d661d654a4b58ff3d2c
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
To do this, refactor the date string function to a single method that
can be unit tested easily. While we're here, deprecate our usage of
time_t and move to std::chrono
Tested: Redifsh service validator passes
Change-Id: I67d4fe66d40b06ed0a0b60286adc75394c34ea1e
Signed-off-by: Ed Tanous <ed@tanous.net>
|
|
Domain names are case-insensitive per RFC standards [1]. Update
isUPNMatch() to perform case-insensitive comparison of domain
labels.
This ensures UPNs like user@DOMAIN.COM match hostnames like
host.domain.com, as per DNS standards.
Tested:
1. Unit tests
2. Built an image, flashed to real BMC, made sure curl requests that use
mTLS auth with certs that use UPN work
3. Redfish service validator
[1] https://datatracker.ietf.org/doc/html/rfc4343
Change-Id: Ibf5715fdddace4263d0aeef54e518457cf03dfcc
Signed-off-by: Igor Kanyuka <ifelmail@gmail.com>
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
Per common error #5 failing to catch thrown exceptions can lead to a
crash. It turns out that the boost::beast::http::fields::set call can
throw in extreme circumstances (large headers). There are two uses to
clean up. Port these to using an overload that returns an error code to
make sure that we don't accidentally set headers or throw an uncaught
exception.
[1] https://github.com/openbmc/bmcweb/blob/master/docs/COMMON_ERRORS.md#5-using-methods-that-throw-or-not-handling-bad-inputs
Tested: Verified unit test coverage on both of these.
Change-Id: I996b64ebb34c4ff7f4e582506d1acfabea05d72e
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
Reject requests whose Content-Length exceeds BMCWEB_HTTP_BODY_LIMIT
before calling reserve().
BMCWEB_HTTP_BODY_LIMIT is defaulted to 30 Mebibyte (MiB). Make the unit
clear in the meson.option too.
Tested: See the trace. The reserve doesn't happen. Not sending a
RST_STREAM / 413 based on how init() works today. WIP.
Change-Id: Ie1e0ba19e2999c2f6c9e18f2b98e49c4bd100bcc
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
|
|
Make sure the body limit enforcement happens before the Expect:
100-continue check.
Tested: Verified the body limit check happens first, even when Expect:
100-continue is used. Now rejects with 413 Payload Too Large.
Normal operations such as the Redfish Validator still work.
Change-Id: I185dab82c75b3c44d89102750fd03666659a57a6
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
|
|
setCipherSuiteTLSext() sets SNI via SSL_set_tlsext_host_name()
but never verifies that the peer certificate matches the
destination hostname. The existing verify_peer mode validates
the certificate chain to a trusted CA but does not check the
certificate's Subject Alternative Name against the hostname.
Any certificate signed by a CA in the BMC's trust store passes
the handshake, regardless of which host it was issued for.
This allows MITM on outbound connections (Redfish Event
subscriptions, firmware downloads) by an attacker holding any
valid certificate signed by a trusted CA, even one issued for
a completely different domain.
Register Boost Asio's ssl::host_name_verification as the SSL
stream's verify_callback, gated on verifyCert != NoVerify to
preserve the existing operator opt-out. host_name_verification
is Boost Asio's wrapper around X509_check_host(), the OpenSSL
1.0.2+ hostname-matching API. Boost's SSL documentation uses
this pattern in its "Verified connection" example.
This patch uses ssl::host_name_verification (registered via
set_verify_callback), rather than calling SSL_set1_host directly
on the native handle as an earlier version of this change did.
Both reach the same OpenSSL primitive (X509_check_host); Asio's
wrapper is the idiomatic form, and is what Boost documentation
points at for hostname verification. libcurl reaches the same
check via X509_VERIFY_PARAM_set1_host on its verify parameters,
which SSL_set1_host is a thin alias for -- libcurl is not
skipping the check.
This fix requires the VerifyCertificate enum inversion fix
(change 89409) to be effective: verify_peer must actually be
enabled for host_name_verification to run its check.
Depends-On: Iecf1d03d2caee141f6eb4a6a4f284e4e36a3b693
Tested: Docker CI passes (format, build, all tests).
Booted OpenBMC on AST2600 (evb-ast2600-renode) in Renode 1.16,
drove Redfish subscriptions through bmcweb's outbound TLS path
to a test HTTPS server presenting a cert with either a matching
(good.example.com) or mismatching (evil.example.com) SAN. The
test CA was installed in the BMC trust store.
Phase 1 (upstream/master, no patch applied):
Benign (good SAN, VerifyCertificate=true) PASS
delivers because chain validates.
MITM (wrong SAN, VerifyCertificate=true) FAIL
"Event was delivered despite a cert that should have
caused rejection."
Reproduces the bug: bmcweb accepts any CA-signed
cert regardless of hostname.
NoVerify (wrong SAN, VerifyCertificate=false) PASS
opt-out delivers regardless of cert.
Phase 2 (upstream/master + this patch):
Benign (good SAN, VerifyCertificate=true) PASS
chain + SAN both check.
MITM (wrong SAN, VerifyCertificate=true) PASS
host_name_verification rejects at the verify_callback;
event is NOT delivered.
NoVerify (wrong SAN, VerifyCertificate=false) PASS
opt-out path unchanged.
The MITM PASS in phase 2 is specifically a hostname-verification
result: Benign's PASS in the same run confirms the chain itself
validates cleanly, so MITM's rejection is exactly the hostname
check doing its job.
Change-Id: Ia1178e4ce662b88d76b4649cf39797e8ede7f42f
Signed-off-by: Gary Beihl <garybeihl@microsoft.com>
|
|
These static variables have the potential to cause reentrancy issues.
In practice, the conditions to cause issues would require someone to
basically write incorrect code, but it makes sense to wrap this into a
state tracker anyway to clean up the code. While we're here, convert to
using std::chrono.
Note, this changes the behavior such that the values produced are now no
longer dependent on timezone. Functionally, Redfish only recently got
the ability to set a timezone, so this is not expected to have any user
facing impact, even though the unit tests need to change.
Tested: RSV Passes
Change-Id: Icb7cff1d289ae23790a5fb1db6604abd73dd68fd
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
Very few people actually need to debug the connection classes, so having
lots of logs clogs up debugging for most people. Comment out the log
lines, but leave them in place such that if someone (possibly me) needs
to they can be re-enabled easily.
Tested: With logging enabled, running queries on the bmc doesn't result
in logs printed per timer arm.
Change-Id: Idcba1111091dab45e417a118c9eb093d84f8b2ec
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
We should have a single entry point where we do json parsing. There are
configurations for nlohmmann that we had previously documented, but were
not well enforced. Move all uses to using the helper parse functions.
Tested: Unit tests pass.
Redfish service validator passes.
Change-Id: I2a8aed9327b6b15219dc9b4d6db146b69bcd8eb3
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
Boost seems to have removed some of the enums that were previously
in the enumeration[1]. We relied on two of these Http2-Settings and
Content-Tranfer-Encoding. It's not clear why they were removed, but
move those to using inline strings.
[1] https://github.com/boostorg/beast/pull/3042/changes/db31a880525fe84b0e17b80015049363106c5b61
Change-Id: I233f103531de1361f903bae5c2981845143983d1
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
TLS session resumption allows to bypass full TLS handshake in subsequent
connections, it's enabled in OpenSSL, so clients that support it use it.
One of the optimizations is, the client passes Session ID in subsequent
request and does not pass certificates. Since client certificate is not
passed, the callback that populates user session out of the certificate
is not called, and as result, auth fails for requests sents in
subsequent connections. This change enables session ID in memory cache,
lookup of the certificate in the cache by the session ID received from
the client and constructing user session out of it for subsequent
connections.
The cache is stored in RAM [1]. According to Nginx doc [2], size of one
session is about 250 bytes. If sessions use mTLS, they will also contain
a cert which is typically up 2kb. A client establishes connections as
part of a session, so a session can be associated with multiple
connections. In the worst case, when many clients establish a single
connection at a time, or a client always uses a new session for every
established connection, there will be number of session entries in the
cache equals to the number of connections. While OpenSSL limits cache
size to SSL_SESSION_CACHE_MAX_SIZE_DEFAULT which is 20480 [3], OpenBMC
limits number of established connections to 200 [4], so in the worst
case, memory usage will be ~50kb for non mTLS clients, and ~440kb for
mTLS clients. Typically, when there are just 2-3 clients connected, even
if them maintain multiple connections within their sessions, the cache
size will be less than 10kb for mTLS. To prevent high memory usage by
the cache, the change sets cache size to 100 entries. Expired sessions
are automatically removed on every 255th session [5].
Tested:
Deployed on one of our envs and ran client that quickly sends multiple
requests to the BMC (so the client created several connections), and
make sure the 401 auth problem had been observed before gone. Also, made
sure BMCWeb logged debug messages about existing session detection.
Ran tests from the openbmc-test-automation repository, esp related to
certificate and user management. They do session auth and not
mTLS/multi-connection, so they could not detect/confirm the problem is
fixed, but they confirm the change does not break the primary use case.
[1] https://docs.openssl.org/3.6/man3/SSL_CTX_set_session_cache_mode/#notes
[2] https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_session_cache
[3] https://github.com/openssl/openssl/blob/5869303daaecf037f0d00dc33a00f9bdc1e71f2f/include/openssl/ssl.h.in#L670
[4] https://github.com/openbmc/bmcweb/blob/master/http/http_connection.hpp#L219C13-L219C28
[5] https://docs.openssl.org/3.6/man3/SSL_CTX_flush_sessions/#notes
Change-Id: Ia94d1e323cd464cc7ca5b0f9c7d6a76e4c780e9a
Signed-off-by: Igor Kanyuka <ifelmail@gmail.com>
|
|
When starting up in http mode, the socket needs to be of type http to
allow the flow to work correctly. As is, enabling insecure-disable-ssl
results in a non functional api due to hardcoded https.
Teted:
enabled insecure-disable-ssl; Verify that curl to http port 80 works
Change-Id: I2958d6f39b642a02b6ce5f1c69d1da409dafc70d
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
This isn't an error message, change it for making the command output of
'journalctl -u bmcweb' clean.
Change-Id: Iff3af323b863776e2e49abcda51198f6b571007d
Signed-off-by: Haiyue Wang <haiyuewa@163.com>
|
|
When taking json directly from a user, we should set some limits on
parsing depth as well as total number of value elements. Value elements
are considered any individual value, the start of an array, the start of
a dictionary, or null. This is to prevent flooding type attacks
creating large number of objects, while still keeping under the depth 10
cap. This commit makes use of the nlohmann sax parse to handle this by
injecting a new error handler in between that will impose new limits.
Currently this sets the depth limit to 10 and the total number of keys
to 500; These are intentionally high, and could be tuned or expanded on
in the future.
Tested: Unit tests pass.
Change-Id: I789543679e22b0b0ce0b2b0b71f31377b0759cd7
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
The body object seems to work properly when init isn't called, but to
make things efficient, init can call std::string::reserve when
appropriate and avoid mallocs.
Tested: Unit tests pass. Good coverage for http2.
Change-Id: I7abba9640ad711678f1ca2ed6d1b42d9aba22dcc
Signed-off-by: Ed Tanous <etanous@nvidia.com>
Signed-off-by: Rajeev Ranjan <ranjan.rajeev1609@gmail.com>
|
|
zstd compression allows for reducing the size of payloads with repeating
elements. Pretty printed json is one very specific case where we would
prefer to not change the behavior, but would also like to avoid the
overhead of TLS compression.
When ztd is present, the webserver will look for the Accepts-Encoding
header to contain zstd, and if it does, compress the payload before
sending.
Tested:
Webui loads correctly, and shows zstd being used for download.
Redfish service validator runs. (does not support zstd)
Unit tests pass.
Change-Id: Ic575911fea70d218d1efb4df030d3cc098f1ecd0
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
Changes added : handle dangling pointer in response completion handler
Problem : When high number of connections made to BMC and suddenly
reset those connections, crash was observed in bmcweb.
Fix : Since the connection already torn but bmcweb trying to close those
connections in response completion handler causing the crash. Added
code to handle the closed or reset connections
Tested :
made around 200 connections and reset them immediately, repeated these
steps around 15 times no crash observed
Change-Id: I03b5fd563275c4138a6eb004e09d277547af9692
Signed-off-by: Chandra Harkude <chandramohan.harkude@gmail.com>
|
|
Couple of these logs are heavy hitters and fill up the journal
especially with external entities constantly hitting the
redfish endpoints. This change moves the largest two logs
we saw (on a yosemite4 machine) from INFO to DEBUG.
Change-Id: Iac7337e3040e0348e41bba79c8200320e8ba12ef
Signed-off-by: Amithash Prasad <amithash@meta.com>
|
|
This fix enables TCP keepalives at the OS layer. It also enables a 15
minute deadline timer at the bmcweb level when waiting on an idle HTTP
keepalive connection.
Tested: romulus image running bmcweb, start connections with keepalive,
block incoming connections `iptables -P INPUT DROP`, validate that
sockets eventually die and are tracked with keepalives `ss -nto`
Change-Id: I8f5040440348c060dae1d0516ec202a0e4dc349e
Signed-off-by: Joey Berkovitz <joey@berkovitz.us>
|
|
Deprecate intoToHex handler now that we can do everything using
std::format.
Tested: RSV passes
Redfish protocol validator passes
Change-Id: I71000506573314d6c9326c4677f5fbca1ca02b46
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
EOF occurs when HTTP/2 clients close connection after completing
requests (e.g., curl). This is normal for multiplexed connections. EOF
indicates graceful shutdown, not an error condition.
Change-Id: I3291b23c7784a2273f2de05afc71ddb57dd0c28a
Signed-off-by: Amy Chang <yahanc@nvidia.com>
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
The commit b0ae71c[1] mishandles the error handling branches which
cause `operation_aborted` to be reported as an error.
```
else if (ec != <error-cases>)
{
BMCWEB_LOG_ERROR("doRead error {}", ec);
}
else if (ec == boost::asio::error::operation_aborted)
{
BMCWEB_LOG_WARNING("doRead operation is aborted: {}", ec);
}
```
This needs to handle `operation_aborted` first.
Tested:
- Unit test passes
[1] https://github.com/openbmc/bmcweb/commit/b0ae71c8f503b9e56a5bf88549346b15e7961e26
Change-Id: Ie4b0eafabcf41adf661ab3abc1fe1282c13d1d82
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
|
|
When websocket is aborted under some situations like GUI console is
aborted earlier before websocket write is still waiting for completion,
it is currently logged as ERROR. However, it may not need to be an
error. This commit will change it as WARNING.
For example,
```
Oct 31 10:40:29 balco10 bmcwebd[1230]: [websocket_impl.hpp:305] Error in ws.async_write Operation canceled [system:125 at /usr/include/boost/beast/websocket/impl/stream_impl.hpp:355:13 in function 'bool boost::beast::websocket::stream< <template-parameter-1-1>, <anonymous> >::impl_type::check_stop_now(boost::beast::error_code&)']
```
Tested:
- While GUI page is loading pages (e.g. pcie topology), close
web-browser and check the bmcweb journal records.
Change-Id: I4b16c21d2784ec0b9774ab256f833bb38fc34a27
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
|
|
Move out the large lambdas into normal methods to maintain more easily.
Tested:
- Unit tests pass
Change-Id: I9450af36d45b2b17e8a063f383d91026db581d27
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
|
|
If we are given an ip address to the http client, there's no reason to
call the dns resolver. Implement a procedure to "skip" resolution if
the http client is an ip address.
Tested:
Using an ipv4 address from a system not running OpenBMC dbus (in this
case an Ubuntu system) now can resolve an IP address. Redfish works
with later patches.
Change-Id: I094ec7b3015e1e31cb83f0e1c25f6c1fb6685219
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
Add support for basic authentication when connecting to aggregation
sources. This allows satellite BMCs to be authenticated using
username and password credentials.
The implementation:
- Stores credentials alongside URLs in AggregationSource struct
- Validates credentials: no colons, max 40 chars, not empty strings
- Creates Basic Auth headers using base64 encoding
- Only sends Authorization header when both username and password exist
- Adds PATCH handler for updating credentials independently
- Prevents duplicate aggregation sources with same hostname
- Cleans up credentials when aggregation sources are deleted
Tested: Manual testing with authenticated aggregation sources
Change-Id: Ide17a3c08a4a8f6b90a2ffcd2c798cbbec578db8
Signed-off-by: Kamran Hasan <khasan@nvidia.com>
|
|
This utility function is being removed for several reasons. First, it
does not verify the full string on URIs and paths, so things like
/foo/bar/baz/valid_id would still pass this check.
Second, it is used for both URIs and dbus paths, both of which we have
better utility functions these days respectively, boost::url for urls
and sdbusplus::message::object_path for dbus paths. Neither of the two
is escaped properly when this function is used.
Therefore, remove it and replace it with the appropriate alternatives.
The existing URI functions were found to not accept fragments (given
they are rarely used in PATCH). Add support for fragments to cover the
getNthStringFromPath use cases.
Tested: Redfish service validator passes.
Change-Id: Ibc6755ad69397123d7fef0e0b764042bbb48888b
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|
|
The routing table may potentially become corrupted during the routing
table construction as the vector element pointer becomes invalid if the
vector is resized [1].
http/routing/trie.hpp#L241:
```
ContainedType& node = nodes[idx];
size_t* param = &node.stringParamChild;
if (str1 == "<path>")
{
param = &node.pathParamChild;
}
if (*param == 0U)
{
L249:
*param = newNode(); // <---
}
idx = *param;
```
Here, `newNodes()` at L249 may resize the vector of `nodes[]` and thus
the reference of `nodes[idx]` becomes invalid and thus the previously
saved the pointer of `param` is invalid.
The similar issue is also at sub_route_trie construction [5].
This problem may be shown during CI/valgrind test depending on the order
of route setups in [2].
For example, for the commit 39574 [3], if `requestsRoutesAssembly()` is
added earlier than `requestRoutesProcessorCollection()`, it causes
CI/valgrind test fails [3].
The error looks like [4].
[1] https://github.com/openbmc/bmcweb/blob/master/http/routing/trie.hpp#L241
[2] https://github.com/openbmc/bmcweb/blob/master/redfish-core/src/redfish.cpp
[3] https://gerrit.openbmc.org/c/openbmc/bmcweb/+/39574
[4] https://gerrit.openbmc.org/c/openbmc/bmcweb/+/39574/comment/15e652e0_f8881ffc/
[5] https://github.com/openbmc/bmcweb/blob/master/redfish-core/include/sub_route_trie.hpp#L160
Tested:
- CI with https://gerrit.openbmc.org/c/openbmc/bmcweb/+/39574 passes
after rebase of having earlier `requestsRoutesAssembly()`.
- Redfish Service Validator passes
Change-Id: I349777dfab65f2d41eb5db25796d82322b3c36cc
Signed-off-by: Myung Bae <myungbae@us.ibm.com>
|
|
http2 maintains its own frame ACK window per stream. While the defaults
work well in most cases, for large binary uploads, like Redfish
UpdateService, the relatively small default window size of 16KB leads to
slower performance than http1. While it's not expected to see a
performance improvement, we would prefer to not see a regression for a
normal use case.
Update the HTTP2 max frame size to 16KB. Setting the internal buffer to
the same size + the http2 header allows clocking in the entire frame in
one async read. Note, setting the value higher than 16KB doesn't appear
to allow curl to send larger frames.
Also update the HTTP window size to 512KB, or 32 times the max frame
size. Note, all streams including the control stream are set to this
value, which, while somewhat arbitrary, allows for continued
UpdateService pushing without pauses for window ACK.
Tested:
POST /redfish/v1/UpdateService/update-multipart
Of an arbitrary 100MB file through curl shows that --http1.1 option and
--http2 option are within 5% of the same upload time.
Change-Id: I7ff6296a9cc0794aad63f5058620c0f1fb9299e3
Signed-off-by: Ed Tanous <etanous@nvidia.com>
|