1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2016 Couchbase, Inc.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #include "config.h"
18 
19 #include <gtest/gtest.h>
20 #include <xattr/utils.h>
21 #include <gsl/gsl>
22 
23 class XattrValidatorTest : public ::testing::Test {
24 public:
XattrValidatorTest()25     XattrValidatorTest() : blob(4) {
26     }
27 
28 protected:
addKvPair(const std::string& key, const std::string& value)29     void addKvPair(const std::string& key, const std::string& value) {
30         auto offset = blob.size();
31         // set aside room for the length
32         blob.resize(offset + 4);
33 
34         std::copy(key.begin(), key.end(), std::back_inserter(blob));
35         blob.push_back(0x00);
36         std::copy(value.begin(), value.end(), std::back_inserter(blob));
37         blob.push_back(0x00);
38 
39         uint32_t len = htonl(gsl::narrow<uint32_t>(blob.size() - (offset + 4)));
40         memcpy(blob.data() + offset, &len, 4);
41 
42         // Update the root block
43         len = htonl(gsl::narrow<uint32_t>(blob.size() - 4));
44         memcpy(blob.data(), &len, 4);
45     }
46 
getBuffer()47     cb::const_char_buffer getBuffer() {
48         return {blob.data(), blob.size()};
49     }
50 
51     std::vector<char> blob;
52 };
53 
TEST_F(XattrValidatorTest, TestEmptyXAttrBlob)54 TEST_F(XattrValidatorTest, TestEmptyXAttrBlob) {
55     EXPECT_TRUE(cb::xattr::validate(getBuffer()));
56 
57     // We may also have data after the xattr blob
58     blob.resize(100);
59     EXPECT_TRUE(cb::xattr::validate(getBuffer()));
60 }
61 
TEST_F(XattrValidatorTest, TestXattrSingleKV)62 TEST_F(XattrValidatorTest, TestXattrSingleKV) {
63     addKvPair("_sync", "{ \"foo\" : \"bar\" }");
64     EXPECT_TRUE(cb::xattr::validate(getBuffer()));
65 }
66 
TEST_F(XattrValidatorTest, TestXattrMultipleKV)67 TEST_F(XattrValidatorTest, TestXattrMultipleKV) {
68     for (int ii = 0; ii < 100; ++ii) {
69         addKvPair("_sync" + std::to_string(ii), "{ \"foo\" : \"bar\" }");
70     }
71     EXPECT_TRUE(cb::xattr::validate(getBuffer()));
72 }
73 
TEST_F(XattrValidatorTest, TestXattrInvalidRootLength)74 TEST_F(XattrValidatorTest, TestXattrInvalidRootLength) {
75     addKvPair("_sync", "{ \"foo\" : \"bar\" }");
76     uint32_t len;
77 
78     // One byte too long
79     memcpy(&len, blob.data(), sizeof(len));
80     len = htonl(ntohl(len) + 1);
81     memcpy(blob.data(), &len, sizeof(len));
82     EXPECT_FALSE(cb::xattr::validate(getBuffer()));
83 
84     // A byte too short
85     len = htonl(ntohl(len) - 2);
86     memcpy(blob.data(), &len, sizeof(len));
87     EXPECT_FALSE(cb::xattr::validate(getBuffer()));
88 }
89 
TEST_F(XattrValidatorTest, TestXattrInvalidKeyLength)90 TEST_F(XattrValidatorTest, TestXattrInvalidKeyLength) {
91     addKvPair("_sync", "{ \"foo\" : \"bar\" }");
92     uint32_t len;
93 
94     // One byte too long
95     memcpy(&len, blob.data() + 4, sizeof(len));
96     len = htonl(ntohl(len) + 1);
97     memcpy(blob.data() + 4, &len, sizeof(len));
98     EXPECT_FALSE(cb::xattr::validate(getBuffer()));
99 
100     // A byte too short
101     len = htonl(ntohl(len) - 2);
102     memcpy(blob.data() + 4, &len, sizeof(len));
103     EXPECT_FALSE(cb::xattr::validate(getBuffer()));
104 }
105 
TEST_F(XattrValidatorTest, TestXattrKeyNotTerminated)106 TEST_F(XattrValidatorTest, TestXattrKeyNotTerminated) {
107     addKvPair("_sync", "{ \"foo\" : \"bar\" }");
108 
109     // 4 byte header, 4 byte kv header, 5 characters keyname
110     EXPECT_EQ(0, blob[13]);
111     blob[13] = 'a';
112     EXPECT_FALSE(cb::xattr::validate(getBuffer()));
113 }
114 
TEST_F(XattrValidatorTest, TestXattrValueNotTerminated)115 TEST_F(XattrValidatorTest, TestXattrValueNotTerminated) {
116     addKvPair("_sync", "{ \"foo\" : \"bar\" }");
117 
118     EXPECT_EQ(0, blob.back());
119     blob.back() = 'a';
120     EXPECT_FALSE(cb::xattr::validate(getBuffer()));
121 }
122 
TEST_F(XattrValidatorTest, TestXattrDuplicateKeysNotAllowed)123 TEST_F(XattrValidatorTest, TestXattrDuplicateKeysNotAllowed) {
124     addKvPair("_sync", "{ \"foo\" : \"bar\" }");
125     addKvPair("_sync", "{ \"foo\" : \"bar\" }");
126 
127     EXPECT_FALSE(cb::xattr::validate(getBuffer()));
128 }
129