• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 1530135362

06 Nov 2024 04:26PM UTC coverage: 76.409% (+0.08%) from 76.331%
1530135362

push

gitlab-ci

lluiscampos
fix: Limit file name length for the Artifact manifest

Limit it to 100 characters. The number is arbitrary but long enough for
the known contents of the manifest.

A manually crafted Artifact could have very long filenames and we want
to prevent the regex to run then. The `mender-artifact` tool does not
create such long filenames.

Changelog: Title

Ticket: MEN-7722

Signed-off-by: Lluis Campos <lluis.campos@northern.tech>

4 of 4 new or added lines in 1 file covered. (100.0%)

22 existing lines in 3 files now uncovered.

7333 of 9597 relevant lines covered (76.41%)

11274.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.19
/src/artifact/parser.cpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#include <artifact/parser.hpp>
16

17
#include <cstdint>
18
#include <memory>
19
#include <system_error>
20
#include <unordered_map>
21

22
#include <common/json.hpp>
23
#include <common/log.hpp>
24
#include <artifact/tar/tar.hpp>
25
#include <common/common.hpp>
26

27
#include <artifact/lexer.hpp>
28
#include <artifact/tar/tar.hpp>
29
#include <artifact/sha/sha.hpp>
30

31
namespace mender {
32
namespace artifact {
33
namespace parser {
34

35
using namespace std;
36

37
namespace lexer = artifact::lexer;
38
namespace log = mender::common::log;
39
namespace io = mender::common::io;
40
namespace tar = mender::tar;
41
namespace expected = mender::common::expected;
42
namespace error = mender::common::error;
43

44
namespace version = mender::artifact::v3::version;
45
namespace manifest = mender::artifact::v3::manifest;
46
namespace manifest_sig = mender::artifact::v3::manifest_sig;
47
namespace payload = mender::artifact::v3::payload;
48

49
ExpectedArtifact VerifyEmptyPayloadArtifact(
6✔
50
        Artifact &artifact, lexer::Lexer<token::Token, token::Type> &lexer) {
51
        // No meta-data allowed
52
        if (artifact.header.subHeaders.at(0).metadata) {
6✔
53
                return expected::unexpected(parser_error::MakeError(
×
54
                        parser_error::Code::ParseError,
55
                        "Empty payload Artifacts cannot contain a meta-data section"));
×
56
        }
57
        // TODO - When augmented sections are added - check for these also
58
        log::Trace("Empty payload Artifact: Verifying empty payload");
12✔
59
        auto expected_payload = artifact.Next();
6✔
60
        if (expected_payload) {
6✔
61
                // If a payload is present, verify that it is empty
62
                auto payload = expected_payload.value();
12✔
63
                auto expected_payload_file = payload.Next();
6✔
64
                if (expected_payload_file) {
6✔
65
                        return expected::unexpected(parser_error::MakeError(
×
66
                                parser_error::Code::ParseError, "Empty Payload Artifacts cannot have a payload"));
×
67
                } else if (
6✔
68
                        expected_payload_file.error().code
69
                        != parser_error::MakeError(parser_error::Code::NoMorePayloadFilesError, "").code) {
6✔
70
                        return expected::unexpected(
×
71
                                expected_payload.error().WithContext("While verifying empty payload"));
×
72
                } // else fall through
73
        } else if (
×
74
                expected_payload.error().code != parser_error::MakeError(parser_error::EOFError, "").code) {
×
75
                return expected::unexpected(
×
76
                        expected_payload.error().WithContext("While verifying empty payload"));
×
77
        } // else fall through
78
        return artifact;
6✔
79
}
80

81
ExpectedArtifact Parse(io::Reader &reader, config::ParserConfig config) {
157✔
82
        std::shared_ptr<tar::Reader> tar_reader {make_shared<tar::Reader>(reader)};
157✔
83

84
        auto lexer = lexer::Lexer<token::Token, token::Type> {tar_reader};
314✔
85

86
        token::Token tok = lexer.Next();
157✔
87

88
        log::Trace("Parsing Version");
314✔
89
        if (tok.type != token::Type::Version) {
157✔
90
                return expected::unexpected(parser_error::MakeError(
1✔
91
                        parser_error::Code::ParseError,
92
                        "Got unexpected token : '" + tok.TypeToString() + "' expected 'version'"));
3✔
93
        }
94

95
        auto expected_version = version::Parse(*tok.value);
156✔
96

97
        if (!expected_version) {
156✔
98
                return expected::unexpected(parser_error::MakeError(
×
99
                        parser_error::Code::ParseError,
100
                        "Failed to parse the version: " + expected_version.error().message));
×
101
        }
102

103
        auto version = expected_version.value();
312✔
104

105
        log::Trace("Parsing the Manifest");
312✔
106
        tok = lexer.Next();
156✔
107
        if (tok.type != token::Type::Manifest) {
156✔
108
                return expected::unexpected(parser_error::MakeError(
×
109
                        parser_error::Code::ParseError,
110
                        "Got unexpected token " + tok.TypeToString() + " expected 'manifest'"));
×
111
        }
112
        auto expected_manifest = manifest::Parse(*tok.value);
156✔
113
        if (!expected_manifest) {
156✔
114
                return expected::unexpected(parser_error::MakeError(
×
115
                        parser_error::Code::ParseError,
116
                        "Failed to parse the manifest: " + expected_manifest.error().String()));
×
117
        }
118
        auto manifest = expected_manifest.value();
312✔
119

120
        tok = lexer.Next();
156✔
121
        optional<ManifestSignature> signature;
156✔
122

123
        // When configured for signed artifacts, refuse installing non signed ones
124
        if (config.verify_signature != config::Signature::Skip
156✔
125
                and config.artifact_verify_keys.size() > 0 and tok.type != token::Type::ManifestSignature) {
156✔
126
                return expected::unexpected(parser_error::MakeError(
×
127
                        parser_error::Code::SignatureVerificationError,
128
                        "expecting signed artifact, but no signature file found"));
×
129
        }
130

131
        if (tok.type == token::Type::ManifestSignature) {
156✔
132
                auto expected_signature = manifest_sig::Parse(*tok.value);
6✔
133
                if (!expected_signature) {
6✔
134
                        return expected::unexpected(parser_error::MakeError(
×
135
                                parser_error::Code::ParseError,
136
                                "Failed to parse the manifest signature: " + expected_signature.error().message));
×
137
                }
138
                signature = expected_signature.value();
6✔
139
                tok = lexer.Next();
6✔
140

141
                // Verify the signature
142
                if (config.verify_signature != config::Signature::Skip
6✔
143
                        and config.artifact_verify_keys.size() > 0) {
6✔
144
                        auto expected_verified = manifest_sig::VerifySignature(
145
                                *signature, manifest.shasum, config.artifact_verify_keys);
4✔
146
                        if (!expected_verified) {
4✔
147
                                return expected::unexpected(parser_error::MakeError(
1✔
148
                                        parser_error::Code::SignatureVerificationError,
149
                                        "Failed to verify the manifest signature: "
150
                                                + expected_verified.error().message));
3✔
151
                        }
152
                        if (!expected_verified.value()) {
3✔
153
                                return expected::unexpected(parser_error::MakeError(
×
154
                                        parser_error::Code::SignatureVerificationError,
155
                                        "Wrong manifest signature or wrong key"));
×
156
                        }
157
                }
158
        }
159

160
        log::Trace("Check version integrity");
310✔
161
        if (manifest.Get("version") != version.shasum.String()) {
155✔
162
                return expected::unexpected(sha::MakeError(
1✔
163
                        sha::ShasumMismatchError,
164
                        "The checksum of version file does not match the expected checksum, (expected): "
165
                                + manifest.Get("version") + " (calculated): " + version.shasum.String()));
3✔
166
        }
167

168
        log::Trace("Parsing the Header");
308✔
169
        if (tok.type != token::Type::Header) {
154✔
UNCOV
170
                return expected::unexpected(parser_error::MakeError(
×
171
                        parser_error::Code::ParseError,
UNCOV
172
                        "Got unexpected token " + tok.TypeToString() + " expected 'Header'"));
×
173
        }
174
        sha::Reader shasum_reader {*tok.value, manifest.Get("header.tar")};
462✔
175
        auto expected_header = v3::header::Parse(shasum_reader, config);
308✔
176
        if (!expected_header) {
154✔
177
                return expected::unexpected(parser_error::MakeError(
1✔
178
                        parser_error::Code::ParseError,
179
                        "Failed to parse the header: " + expected_header.error().message));
3✔
180
        }
181
        auto header = expected_header.value();
306✔
182

183
        // Create the object
184
        auto artifact = Artifact {version, manifest, header, lexer};
459✔
185
        if (signature) {
153✔
186
                artifact.manifest_signature = signature;
187
        }
188

189
        // Check the empty payload structure
190
        if (header.info.payloads.at(0).type == v3::header::Payload::EmptyPayload) {
153✔
191
                auto expected_empty_payload_artifact = VerifyEmptyPayloadArtifact(artifact, lexer);
6✔
192
                if (!expected_empty_payload_artifact) {
6✔
193
                        return expected_empty_payload_artifact;
194
                }
195
                return artifact;
6✔
196
        }
197

198
        return artifact;
147✔
199
};
200

201

202
ExpectedPayload Artifact::Next() {
238✔
203
        token::Token tok = lexer_.Next();
238✔
204
        if (payload_index_ != 0) {
238✔
205
                // Currently only one payload supported
206
                switch (tok.type) {
100✔
207
                case token::Type::EOFToken:
208
                        return expected::unexpected(parser_error::MakeError(
100✔
209
                                parser_error::Code::EOFError, "Reached the end of the Artifact"));
300✔
210
                case token::Type::Payload:
UNCOV
211
                        return expected::unexpected(error::Error(
×
212
                                make_error_condition(errc::not_supported), "Only one artifact payload supported"));
×
UNCOV
213
                default:
×
214
                        return expected::unexpected(parser_error::MakeError(
×
UNCOV
215
                                parser_error::Code::ParseError, "Unexpected token: " + tok.TypeToString()));
×
216
                }
217
        }
218

219
        if (tok.type != token::Type::Payload) {
138✔
UNCOV
220
                return expected::unexpected(parser_error::MakeError(
×
221
                        parser_error::Code::ParseError,
UNCOV
222
                        "Got unexpected token " + tok.TypeToString() + " expected 'data/0000.tar"));
×
223
        }
224

225
        log::Trace("Parsing the payload");
276✔
226
        payload_index_++;
138✔
227
        return payload::Payload(*(this->lexer_.current.value), manifest);
138✔
228
}
229

230
} // namespace parser
231
} // namespace artifact
232
} // namespace mender
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc