Skip to content

Commit 1e02b9b

Browse files
committed
MB-69017: Split Cookie::validate() ...
... into one method for server requests and one for client requests Change-Id: If9edbfcc05045006fa714738722352c131526dd7 Reviewed-on: https://review.couchbase.org/c/kv_engine/+/235416 Tested-by: Build Bot <[email protected]> Reviewed-by: Pavlos Georgiou <[email protected]>
1 parent 0f2b89f commit 1e02b9b

File tree

2 files changed

+61
-41
lines changed

2 files changed

+61
-41
lines changed

daemon/cookie.cc

Lines changed: 58 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -481,86 +481,83 @@ void Cookie::initialize(std::chrono::steady_clock::time_point now,
481481
start = now;
482482
}
483483

484-
cb::mcbp::Status Cookie::validate() {
485-
using cb::mcbp::Status;
484+
cb::mcbp::Status Cookie::validateServerRequest(
485+
const cb::mcbp::Request& request) {
486+
using namespace cb::mcbp;
487+
// We should not be receiving a server command.
488+
auto opcode = request.getServerOpcode();
489+
if (is_valid_opcode(opcode)) {
490+
// Ideally we should have validated its content, but given that
491+
// we don't support any server commands we can just return not supported
492+
// instead
493+
return Status::NotSupported;
494+
}
486495

496+
audit_invalid_packet(connection, getPacket());
497+
return Status::UnknownCommand;
498+
}
499+
500+
cb::mcbp::Status Cookie::validateClientRequest(
501+
const cb::mcbp::Request& request) {
502+
using namespace cb::mcbp;
487503
static McbpValidator packetValidator;
488504

489505
// Note: validate is called after the connection fetched the frame
490506
// off the network, and in order to know when the frame ends
491507
// it needed to validate the frame layout (known magic and
492508
// all the length fields inside the raw header adds up so
493509
// that the bodylen() contains the entire data).
494-
const auto& header = getHeader();
495-
if (header.isResponse()) {
496-
// We don't have packet validators for responses (yet)
497-
validated = true;
498-
return cb::mcbp::Status::Success;
499-
}
500-
501-
const auto& request = header.getRequest();
502-
if (cb::mcbp::is_server_magic((request.getMagic()))) {
503-
// We should not be receiving a server command.
504-
auto opcode = request.getServerOpcode();
505-
if (!cb::mcbp::is_valid_opcode(opcode)) {
506-
return cb::mcbp::Status::UnknownCommand;
507-
}
508-
509-
audit_invalid_packet(connection, getPacket());
510-
return cb::mcbp::Status::NotSupported;
511-
}
512-
513-
auto opcode = request.getClientOpcode();
510+
const auto opcode = request.getClientOpcode();
514511

515512
if (!connection.isAuthenticated()) {
516513
// We're not authenticated. To reduce the attack vector we'll only
517514
// allow certain commands to be executed
518-
constexpr std::array<cb::mcbp::ClientOpcode, 5> allowed{
519-
{cb::mcbp::ClientOpcode::Hello,
520-
cb::mcbp::ClientOpcode::SaslListMechs,
521-
cb::mcbp::ClientOpcode::SaslAuth,
522-
cb::mcbp::ClientOpcode::SaslStep,
523-
cb::mcbp::ClientOpcode::GetErrorMap}};
515+
constexpr std::array<ClientOpcode, 5> allowed{
516+
{ClientOpcode::Hello,
517+
ClientOpcode::SaslListMechs,
518+
ClientOpcode::SaslAuth,
519+
ClientOpcode::SaslStep,
520+
ClientOpcode::GetErrorMap}};
524521
if (std::ranges::find(allowed, opcode) == allowed.end()) {
525522
#if CB_DEVELOPMENT_ASSERTS
526-
if (cb::mcbp::is_valid_opcode(opcode)) {
523+
if (is_valid_opcode(opcode)) {
527524
LOG_WARNING_CTX(
528525
"Trying to execute before authentication. Returning "
529526
"eaccess",
530527
{"conn_id", getConnectionId()},
531528
{"opcode", opcode});
532529
}
533530
#endif
534-
return cb::mcbp::Status::Eaccess;
531+
return Status::Eaccess;
535532
}
536533
}
537534

538-
if (!cb::mcbp::is_valid_opcode(opcode)) {
535+
if (!is_valid_opcode(opcode)) {
539536
// We don't know about this command. Stop processing
540537
// It is legal to send unknown commands, so we don't log or audit this
541-
return cb::mcbp::Status::UnknownCommand;
538+
return Status::UnknownCommand;
542539
}
543540

544541
// A cluster-only bucket don't have an associated engine parameter
545542
// so we don't even want to try to validate the packet unless it is
546543
// one of the few commands allowed to be executed in such a bucket
547544
// (to avoid a potential call throug a nil pointer)
548545
if (connection.getBucket().type == BucketType::ClusterConfigOnly) {
549-
constexpr std::array<cb::mcbp::ClientOpcode, 4> allowed{
550-
{cb::mcbp::ClientOpcode::Hello,
551-
cb::mcbp::ClientOpcode::GetErrorMap,
552-
cb::mcbp::ClientOpcode::GetClusterConfig,
553-
cb::mcbp::ClientOpcode::SelectBucket}};
546+
constexpr std::array<ClientOpcode, 4> allowed{
547+
{ClientOpcode::Hello,
548+
ClientOpcode::GetErrorMap,
549+
ClientOpcode::GetClusterConfig,
550+
ClientOpcode::SelectBucket}};
554551
if (std::ranges::find(allowed, opcode) == allowed.end()) {
555552
if (connection.isXerrorSupport()) {
556-
return cb::mcbp::Status::EConfigOnly;
553+
return Status::EConfigOnly;
557554
}
558-
return cb::mcbp::Status::NotSupported;
555+
return Status::NotSupported;
559556
}
560557
}
561558

562-
auto result = packetValidator.validate(opcode, *this);
563-
if (!cb::mcbp::isStatusSuccess(result)) {
559+
const auto result = packetValidator.validate(opcode, *this);
560+
if (!isStatusSuccess(result)) {
564561
if (result != Status::UnknownCollection &&
565562
result != Status::NotMyVbucket &&
566563
result != Status::BucketSizeLimitExceeded &&
@@ -596,6 +593,26 @@ cb::mcbp::Status Cookie::validate() {
596593
return Status::Success;
597594
}
598595

596+
cb::mcbp::Status Cookie::validate() {
597+
using namespace cb::mcbp;
598+
const auto& header = getHeader();
599+
if (header.isRequest()) [[likely]] {
600+
const auto& request = header.getRequest();
601+
if (is_server_magic(request.getMagic())) [[unlikely]] {
602+
return validateServerRequest(request);
603+
}
604+
return validateClientRequest(request);
605+
}
606+
607+
// We can't really validate a response packets in this context as we would
608+
// break the protocol if we tried to send a response to a response packet
609+
// Instead we'll let each handler validate the response packet before they
610+
// use it and optionally just disconnect the client if they think it is
611+
// the right thing to do.
612+
validated = true;
613+
return Status::Success;
614+
}
615+
599616
Cookie::~Cookie() {
600617
if (isEwouldblock()) {
601618
LOG_CRITICAL_CTX(

daemon/cookie.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,9 @@ class Cookie : public CookieIface {
634634
}
635635

636636
protected:
637+
cb::mcbp::Status validateClientRequest(const cb::mcbp::Request& request);
638+
cb::mcbp::Status validateServerRequest(const cb::mcbp::Request& request);
639+
637640
/// Set the internal ewouldblock variable
638641
void setEwouldblockVariable(cb::engine_errc value);
639642

0 commit comments

Comments
 (0)