SERVER-115584 detect huge procfs files during FTDC collection (#47923)
Co-authored-by: Billy Donahue <BillyDonahue@users.noreply.github.com> GitOrigin-RevId: 43dc25b39b217c41e6c3cc0ab37e69f60134db3f
This commit is contained in:
parent
dcc27418ff
commit
1de5943c67
@ -119,7 +119,10 @@ mongo_cc_library(
|
||||
"//src/mongo/s:common_s",
|
||||
"//src/mongo/util:processinfo",
|
||||
] + select({
|
||||
"@platforms//os:linux": ["//src/mongo/util:procparser"],
|
||||
"@platforms//os:linux": [
|
||||
"//src/mongo/util:procparser",
|
||||
"//src/mongo/util:procparser_parameters",
|
||||
],
|
||||
"@platforms//os:windows": ["//src/mongo/util:perfctr_collect"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
|
||||
@ -584,14 +584,36 @@ mongo_cc_library(
|
||||
name = "procparser",
|
||||
srcs = [
|
||||
"procparser.cpp",
|
||||
"procparser.h",
|
||||
],
|
||||
hdrs = ["procparser.h"],
|
||||
target_compatible_with = select({
|
||||
"@platforms//os:linux": [],
|
||||
"//conditions:default": ["@platforms//:incompatible"],
|
||||
}),
|
||||
deps = [
|
||||
":pcre_wrapper",
|
||||
"//src/mongo/db:server_base",
|
||||
],
|
||||
)
|
||||
|
||||
idl_generator(
|
||||
name = "procparser_parameters_gen",
|
||||
src = "procparser_parameters.idl",
|
||||
)
|
||||
|
||||
mongo_cc_library(
|
||||
name = "procparser_parameters",
|
||||
srcs = [
|
||||
"procparser_parameters.cpp",
|
||||
":procparser_parameters_gen",
|
||||
],
|
||||
hdrs = ["procparser_parameters.h"],
|
||||
target_compatible_with = select({
|
||||
"@platforms//os:linux": [],
|
||||
"//conditions:default": ["@platforms//:incompatible"],
|
||||
}),
|
||||
deps = [
|
||||
":procparser",
|
||||
"//src/mongo:base",
|
||||
],
|
||||
)
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
@ -68,6 +69,7 @@
|
||||
#include "mongo/bson/util/builder.h"
|
||||
#include "mongo/config.h" // IWYU pragma: keep
|
||||
#include "mongo/logv2/log.h"
|
||||
#include "mongo/logv2/log_severity_suppressor.h"
|
||||
#include "mongo/util/assert_util.h"
|
||||
#include "mongo/util/errno_util.h"
|
||||
#include "mongo/util/pcre.h"
|
||||
@ -116,6 +118,41 @@ const size_t kFileReadRetryCount = 5;
|
||||
|
||||
constexpr auto kSysBlockDeviceDirectoryName = "device";
|
||||
|
||||
/**
|
||||
* Open and read a whole file, discarding data, just to get its size.
|
||||
* Full read is needed for special files because stat will report 0 size.
|
||||
*/
|
||||
size_t fileByteCount(StringData filename) {
|
||||
std::ifstream ifs(std::string{filename});
|
||||
auto buf = std::make_unique_for_overwrite<std::array<char, kFileBufferSize>>();
|
||||
size_t nr = 0;
|
||||
while (ifs) {
|
||||
ifs.read(buf->data(), buf->size());
|
||||
nr += ifs.gcount();
|
||||
}
|
||||
return nr;
|
||||
}
|
||||
|
||||
Status detectHugeFile(StringData filename, const BufBuilder& builder) {
|
||||
const size_t sizeLimit = procparser::getProcFileSizeLimit();
|
||||
if (static_cast<size_t>(builder.len()) < sizeLimit)
|
||||
return Status::OK();
|
||||
static logv2::SeveritySuppressor logSeverity(
|
||||
Minutes{5}, logv2::LogSeverity::Warning(), logv2::LogSeverity::Debug(3));
|
||||
if (auto sev = logSeverity(); shouldLog(MONGO_LOGV2_DEFAULT_COMPONENT, sev)) {
|
||||
LOGV2_DEBUG(
|
||||
11558400,
|
||||
sev.toInt(),
|
||||
"Huge file",
|
||||
"filename"_attr = filename,
|
||||
"byteCount"_attr = fileByteCount(filename),
|
||||
"sizeLimit"_attr = static_cast<long long>(sizeLimit),
|
||||
"partialContents"_attr =
|
||||
StringData(builder.buf(), static_cast<size_t>(builder.len())).substr(0, 256));
|
||||
}
|
||||
return {ErrorCodes::FileStreamFailed, fmt::format("Huge file {:?}", filename)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file from disk as a string with a null-terminating byte using the POSIX file api.
|
||||
*
|
||||
@ -137,7 +174,7 @@ StatusWith<std::string> readFileAsString(StringData filename) {
|
||||
ScopeGuard scopedGuard([fd] { close(fd); });
|
||||
|
||||
BufBuilder builder(kFileBufferSize);
|
||||
std::array<char, kFileBufferSize> buf;
|
||||
auto buf = std::make_unique_for_overwrite<std::array<char, kFileBufferSize>>();
|
||||
|
||||
ssize_t size_read = 0;
|
||||
|
||||
@ -148,7 +185,7 @@ StatusWith<std::string> readFileAsString(StringData filename) {
|
||||
size_t retry = 0;
|
||||
|
||||
do {
|
||||
size_read = read(fd, buf.data(), kFileBufferSize);
|
||||
size_read = read(fd, buf->data(), buf->size());
|
||||
|
||||
if (size_read == -1) {
|
||||
auto ec = lastPosixError();
|
||||
@ -169,7 +206,9 @@ StatusWith<std::string> readFileAsString(StringData filename) {
|
||||
} while (true);
|
||||
|
||||
if (size_read != 0) {
|
||||
builder.appendBuf(buf.data(), size_read);
|
||||
builder.appendBuf(buf->data(), size_read);
|
||||
if (auto err = detectHugeFile(filename, builder); !err.isOK())
|
||||
return err;
|
||||
}
|
||||
} while (size_read != 0);
|
||||
|
||||
@ -208,12 +247,22 @@ const char* const kDiskFields[] = {
|
||||
|
||||
const size_t kDiskFieldCount = std::extent<decltype(kDiskFields)>::value;
|
||||
|
||||
size_t procFileSizeLimit = size_t{1} * 1024 * 1024; // 1MiB
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace procparser {
|
||||
|
||||
using StringSplitIterator = boost::split_iterator<StringData::const_iterator>;
|
||||
|
||||
void setProcFileSizeLimit(size_t limit) {
|
||||
procFileSizeLimit = limit;
|
||||
}
|
||||
|
||||
size_t getProcFileSizeLimit() {
|
||||
return procFileSizeLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is a generic function that passes in logic to parse a proc file. It looks for
|
||||
* keys within the data param and captures the corresponding values. If no keys were found
|
||||
|
||||
@ -266,5 +266,13 @@ Status parseProcPressure(StringData data, BSONObjBuilder* builder);
|
||||
*/
|
||||
Status parseProcPressureFile(StringData key, StringData filename, BSONObjBuilder* builder);
|
||||
|
||||
/**
|
||||
* Procfs files such as the files parsed by this component should be just a small to moderate amount
|
||||
* of text. To protect us from abnormally huge or even corrupted procfs files, we enforce a max size
|
||||
* on them. The ability to adjust this limit is allowed as a safety measure for the safety measure.
|
||||
*/
|
||||
void setProcFileSizeLimit(size_t limit);
|
||||
size_t getProcFileSizeLimit();
|
||||
|
||||
} // namespace procparser
|
||||
} // namespace mongo
|
||||
|
||||
41
src/mongo/util/procparser_parameters.cpp
Normal file
41
src/mongo/util/procparser_parameters.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (C) 2026-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#include "mongo/util/procparser_parameters.h"
|
||||
|
||||
#include "mongo/util/procparser.h"
|
||||
|
||||
namespace mongo::procparser {
|
||||
|
||||
Status onUpdateProcFileSizeLimit(const long long& limit) {
|
||||
setProcFileSizeLimit(limit);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
} // namespace mongo::procparser
|
||||
45
src/mongo/util/procparser_parameters.h
Normal file
45
src/mongo/util/procparser_parameters.h
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (C) 2026-present MongoDB, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the Server Side Public License, version 1,
|
||||
* as published by MongoDB, Inc.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* Server Side Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Server Side Public License
|
||||
* along with this program. If not, see
|
||||
* <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
*
|
||||
* As a special exception, the copyright holders give permission to link the
|
||||
* code of portions of this program with the OpenSSL library under certain
|
||||
* conditions as described in each individual source file and distribute
|
||||
* linked combinations including the program with the OpenSSL library. You
|
||||
* must comply with the Server Side Public License in all respects for
|
||||
* all of the code used other than as permitted herein. If you modify file(s)
|
||||
* with this exception, you may extend this exception to your version of the
|
||||
* file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
* delete this exception statement from your version. If you delete this
|
||||
* exception statement from all source files in the program, then also delete
|
||||
* it in the license file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mongo/base/status.h"
|
||||
#include "mongo/util/modules.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace mongo {
|
||||
namespace procparser {
|
||||
|
||||
Status onUpdateProcFileSizeLimit(const long long& limit);
|
||||
|
||||
} // namespace procparser
|
||||
} // namespace mongo
|
||||
41
src/mongo/util/procparser_parameters.idl
Normal file
41
src/mongo/util/procparser_parameters.idl
Normal file
@ -0,0 +1,41 @@
|
||||
# Copyright (C) 2026-present MongoDB, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the Server Side Public License, version 1,
|
||||
# as published by MongoDB, Inc.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# Server Side Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the Server Side Public License
|
||||
# along with this program. If not, see
|
||||
# <http://www.mongodb.com/licensing/server-side-public-license>.
|
||||
#
|
||||
# As a special exception, the copyright holders give permission to link the
|
||||
# code of portions of this program with the OpenSSL library under certain
|
||||
# conditions as described in each individual source file and distribute
|
||||
# linked combinations including the program with the OpenSSL library. You
|
||||
# must comply with the Server Side Public License in all respects for
|
||||
# all of the code used other than as permitted herein. If you modify file(s)
|
||||
# with this exception, you may extend this exception to your version of the
|
||||
# file(s), but you are not obligated to do so. If you do not wish to do so,
|
||||
# delete this exception statement from your version. If you delete this
|
||||
# exception statement from all source files in the program, then also delete
|
||||
# it in the license file.
|
||||
#
|
||||
global:
|
||||
cpp_namespace: "mongo::procparser"
|
||||
cpp_includes:
|
||||
- "mongo/util/procparser_parameters.h"
|
||||
|
||||
server_parameters:
|
||||
procFileSizeLimit:
|
||||
description: "Server will not read procfs files larger than this limit"
|
||||
set_at: ["startup"]
|
||||
cpp_varname: "procFileSizeLimit"
|
||||
cpp_vartype: long long
|
||||
default: 1048576 # 1MiB
|
||||
redact: false
|
||||
on_update: onUpdateProcFileSizeLimit
|
||||
Loading…
Reference in New Issue
Block a user