-
Notifications
You must be signed in to change notification settings - Fork 640
Do not expand errorpage %codes injected by X509 certificates #2416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
dc1301e
1dab512
17b5b30
48a03a6
b7c4596
9e3285b
fda31c0
f81c9ad
eacceb3
96a7d12
7838ebc
679ac79
95408d6
d05744a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -21,16 +21,18 @@ class ErrorDetail: public RefCountable | |||||
| { | ||||||
| public: | ||||||
| using Pointer = ErrorDetailPointer; | ||||||
| using ErrorTemplateCompiler = ErrorState; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Error" word is redundant within the scope
Suggested change
|
||||||
|
|
||||||
| ~ErrorDetail() override {} | ||||||
|
|
||||||
| /// \returns a single "token" summarizing available details | ||||||
| /// suitable as an access.log field and similar output processed by programs | ||||||
| virtual SBuf brief() const = 0; | ||||||
|
|
||||||
| /// \returns all available details; may be customized for the given request | ||||||
| /// \returns all available details | ||||||
| /// suitable for error pages and other output meant for human consumption | ||||||
| virtual SBuf verbose(const HttpRequestPointer &) const = 0; | ||||||
| /// Supports configurable templates populated by the given compiler. | ||||||
| virtual SBuf verbose(const ErrorTemplateCompiler &) const = 0; | ||||||
|
|
||||||
| // Duplicate details for the same error typically happen when we update some | ||||||
| // error storage (e.g., ALE) twice from the same detail source (e.g., the | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -92,6 +92,11 @@ class Error; | |||||
| class ErrorDetail; | ||||||
| class ErrorState; | ||||||
|
|
||||||
| namespace ErrorPage { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong namespace. This is the forward declarations for the The maintenance work fixing |
||||||
| class PercentCodeCompiler; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why "PercentCode" ? we dont have other types of page compiler for error pages.
Suggested change
I do not see the required |
||||||
| class Build; | ||||||
| } // namespace ErrorPage | ||||||
|
|
||||||
| typedef RefCount<ErrorDetail> ErrorDetailPointer; | ||||||
|
|
||||||
| #endif /* SQUID_SRC_ERROR_FORWARD_H */ | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -102,16 +102,6 @@ class ErrorDynamicPageInfo { | |
|
|
||
| namespace ErrorPage { | ||
|
|
||
| /// state and parameters shared by several ErrorState::compile*() methods | ||
| class Build | ||
| { | ||
| public: | ||
| SBuf output; ///< compilation result | ||
| const char *input = nullptr; ///< template bytes that need to be compiled | ||
| bool building_deny_info_url = false; ///< whether we compile deny_info URI | ||
| bool allowRecursion = false; ///< whether top-level compile() calls are OK | ||
| }; | ||
|
|
||
| /// pretty-prints error page/deny_info building error | ||
| class BuildErrorPrinter | ||
| { | ||
|
|
@@ -1002,9 +992,7 @@ ErrorState::compileLegacyCode(Build &build) | |
| if (!build.allowRecursion) | ||
| p = "%D"; // if recursion is not allowed, do not convert | ||
| else if (detail) { | ||
| auto rawDetail = detail->verbose(request); | ||
| // XXX: Performance regression. c_str() reallocates | ||
| const auto compiledDetail = compileBody(rawDetail.c_str(), false); | ||
| const auto compiledDetail = detail->verbose(*this); | ||
| mb.append(compiledDetail.rawContent(), compiledDetail.length()); | ||
| do_quote = 0; | ||
| } | ||
|
|
@@ -1456,23 +1444,55 @@ ErrorState::compile(const char *input, bool building_deny_info_url, bool allowRe | |
| build.allowRecursion = allowRecursion; | ||
| build.input = input; | ||
|
|
||
| compile(build); | ||
| Assure(!*build.input); // compiled the whole template | ||
|
|
||
| return build.output; | ||
| } | ||
|
|
||
| SBuf | ||
| ErrorState::compileDetail(const char * const format, const ErrorPage::PercentCodeCompiler * const secondaryCompiler) const | ||
| { | ||
| Assure(format); | ||
|
|
||
| Build build; | ||
| build.input = format; | ||
| build.secondaryCompiler = secondaryCompiler; // may be nil | ||
|
|
||
| compile(build); | ||
| Assure(!*build.input); // compiled the whole template | ||
|
|
||
| return build.output; | ||
| } | ||
|
|
||
| /// Replaces all %code sequences found in build.input. | ||
| /// Appends processed input to build.output. | ||
| /// Consumes processed build.input. | ||
| void | ||
| ErrorState::compile(Build &build) const | ||
| { | ||
| Assure(build.input); | ||
|
|
||
| // TODO: Instead of violating const-correctness with const_cast<ErrorState*> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed please do that. I suggest looking into whether the member holding output be |
||
| // below, adjust compile*() methods to avoid ErrorState modifications. | ||
|
|
||
| auto blockStart = build.input; | ||
| while (const auto letter = *build.input) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, albeit slightly. This change removes one (poor) duplicate of this "find and replace all %codes" loop. It also provides better access to detail-rendering context via the A lot of work is still required to modernize legacy errorpage code, of course, including addressing const-correctness problems marked in this PR.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks can be deceiving. The order of refactoring is causing regressions and an increase in technical debt. |
||
| if (letter == '%') { | ||
| build.output.append(blockStart, build.input - blockStart); | ||
| compileLegacyCode(build); | ||
| if (!build.secondaryCompiler || !build.secondaryCompiler->compilePercentCode(build)) | ||
| const_cast<ErrorState*>(this)->compileLegacyCode(build); | ||
| blockStart = build.input; | ||
| } | ||
| else if (letter == '@' && LogformatMagic.cmp(build.input, LogformatMagic.length()) == 0) { | ||
| build.output.append(blockStart, build.input - blockStart); | ||
| compileLogformatCode(build); | ||
| const_cast<ErrorState*>(this)->compileLogformatCode(build); | ||
| blockStart = build.input; | ||
| } else { | ||
| ++build.input; | ||
| } | ||
| } | ||
| build.output.append(blockStart, build.input - blockStart); | ||
| return build.output; | ||
| } | ||
|
|
||
| /// react to a compile() error | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |||||
| #ifndef SQUID_SRC_ERRORPAGE_H | ||||||
| #define SQUID_SRC_ERRORPAGE_H | ||||||
|
|
||||||
| #include "base/TypeTraits.h" | ||||||
| #include "cbdata.h" | ||||||
| #include "comm/forward.h" | ||||||
| #include "error/Detail.h" | ||||||
|
|
@@ -78,18 +79,14 @@ class MemBuf; | |||||
| class StoreEntry; | ||||||
| class wordlist; | ||||||
|
|
||||||
| namespace ErrorPage { | ||||||
|
|
||||||
| class Build; | ||||||
|
|
||||||
| } // namespace ErrorPage | ||||||
|
|
||||||
| /// \ingroup ErrorPageAPI | ||||||
| class ErrorState | ||||||
| { | ||||||
| CBDATA_CLASS(ErrorState); | ||||||
|
|
||||||
| public: | ||||||
| using Build = ErrorPage::Build; | ||||||
|
|
||||||
| /// creates an error of type other than ERR_RELAY_REMOTE | ||||||
| ErrorState(err_type type, Http::StatusCode, HttpRequest * request, const AccessLogEntryPointer &al); | ||||||
| ErrorState() = delete; // not implemented. | ||||||
|
|
@@ -113,12 +110,15 @@ class ErrorState | |||||
| /// ensures that a future BuildHttpReply() is likely to succeed | ||||||
| void validate(); | ||||||
|
|
||||||
| /// Replaces all %codes in the given ErrorDetail `format` template. | ||||||
| /// \param compiler is an optional handler for caller-specific template %code sequences | ||||||
| /// \sa compile() | ||||||
| SBuf compileDetail(const char *format, const ErrorPage::PercentCodeCompiler *compiler) const; | ||||||
|
|
||||||
| /// the source of the error template (for reporting purposes) | ||||||
| SBuf inputLocation; | ||||||
|
|
||||||
| private: | ||||||
| typedef ErrorPage::Build Build; | ||||||
|
|
||||||
| /// initializations shared by public constructors | ||||||
| ErrorState(err_type, const AccessLogEntryPointer &); | ||||||
|
|
||||||
|
|
@@ -141,8 +141,11 @@ class ErrorState | |||||
| /// \param building_deny_info_url whether input is a deny_info URL parameter | ||||||
| /// \param allowRecursion whether to compile %codes which produce %codes | ||||||
| /// \returns the given input with all %codes substituted | ||||||
| /// \sa compileDetail() | ||||||
| SBuf compile(const char *input, bool building_deny_info_url, bool allowRecursion); | ||||||
|
|
||||||
| void compile(Build &build) const; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant parameter and missing documentation on new method.
Suggested change
|
||||||
|
|
||||||
| /// React to a compile() error, throwing if buildContext allows. | ||||||
| /// \param msg description of what went wrong | ||||||
| /// \param errorLocation approximate start of the problematic input | ||||||
|
|
@@ -336,6 +339,41 @@ class TemplateFile | |||||
| err_type templateCode; ///< The internal code for this template. | ||||||
| }; | ||||||
|
|
||||||
| namespace ErrorPage { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This move to Yes the badly named |
||||||
|
|
||||||
| /// An API for recognizing and replacing a single %code sequence. | ||||||
| class PercentCodeCompiler: public Interface { | ||||||
| public: | ||||||
| /// Either recognizes a single %code sequence at the beginning of | ||||||
| /// `build.input` and appends its replacement to `build.output` OR does not | ||||||
| /// modify `build`. | ||||||
| /// \returns true when the leading %code was recognized | ||||||
| /// \prec `build.input` starts with a `%` character. | ||||||
| virtual bool compilePercentCode(Build &) const = 0; | ||||||
| }; | ||||||
|
|
||||||
| /// State and parameters shared by several | ||||||
| /// PercentCodeCompiler::compilePercentCode() and ErrorState::compile*() methods | ||||||
| /// that convert an errorpage template fragment (or equivalent) into an error | ||||||
| /// response body fragment. This conversion replaces legacy errorpage %code | ||||||
| /// sequences, logformat %code sequences, and, in some cases, | ||||||
| /// ErrorDetail-dependent %code sequences. | ||||||
| class Build | ||||||
| { | ||||||
| public: | ||||||
| SBuf output; ///< compilation result | ||||||
| const char *input; ///< template bytes that need to be compiled; never nil | ||||||
|
|
||||||
| /// Handles context-dependent %code sequences unsupported by ErrorState. | ||||||
| /// Compiler object lifetime must exceed this Build object lifetime. | ||||||
| const PercentCodeCompiler *secondaryCompiler = nullptr; | ||||||
|
|
||||||
| bool building_deny_info_url = false; ///< whether we compile deny_info URI | ||||||
| bool allowRecursion = false; ///< whether top-level compile() calls are OK | ||||||
| }; | ||||||
|
|
||||||
| } // namespace ErrorPage | ||||||
|
|
||||||
| /** | ||||||
| * Parses the Accept-Language header value and return one language item on | ||||||
| * each call. | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,8 +25,11 @@ BEGIN { | |
| nspath = "" | ||
| } | ||
|
|
||
| # when namespace is encountered store it | ||
| # Remember the name of the last namespace encountered before the enum. | ||
| # XXX: We should remember the name(s) of the namespace(s) surrounding the enum | ||
| # instead. TODO: Replace this C++ parsing hack with a command-line parameter. | ||
| /^namespace *[a-zA-Z]+/ { | ||
| if (type) next | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is out of scope and seems to be adding support for invalid C++ syntax: Please remove, or if necessary please discuss the error being produced that requires a change. |
||
| nspath = tolower($2) "/" # nested folder | ||
| namespace = $2 # code namespace reconstruct | ||
| next | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to avoid noisy changes like this one in this PR by adding a temporary API shim. I have not done that because these changes do not impact v7 backporting in my quick-and-dirty tests (cherry-picking fails because v7 lacks some
src/security/ErrorDetail.ccchanges in master/v8), and because we would have to post another official PR to remove that shim, of course.