mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Copybara import of the project:
--55de8f7fd7
by Demi Marie Obenour <demi@invisiblethingslab.com>: Simple libidn2 wrapper This adds a simple libidn2 wrapper, including unit tests via GTest. COPYBARA_INTEGRATE_REVIEW=https://github.com/google/sandboxed-api/pull/96 from DemiMarie:libidn255de8f7fd7
PiperOrigin-RevId: 426121420 Change-Id: I79b23560ba23c0c2f1da063bfaa85eac13b2f517
This commit is contained in:
parent
b6d65ef244
commit
24ad0cc108
61
contrib/libidn2/CMakeLists.txt
Normal file
61
contrib/libidn2/CMakeLists.txt
Normal file
|
@ -0,0 +1,61 @@
|
|||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.13..3.22)
|
||||
project(libidn2-sapi CXX C)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
if(NOT TARGET sapi::sapi)
|
||||
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
|
||||
add_subdirectory("${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
# Omit this to have the full Sandboxed API in IDE
|
||||
EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBIDN2 REQUIRED IMPORTED_TARGET libidn2)
|
||||
|
||||
add_sapi_library(libidn2_sapi
|
||||
FUNCTIONS idn2_lookup_u8 idn2_register_u8
|
||||
idn2_strerror idn2_strerror_name
|
||||
idn2_free idn2_to_ascii_8z
|
||||
idn2_to_unicode_8z8z
|
||||
INPUTS "${LIBIDN2_INCLUDEDIR}/idn2.h"
|
||||
LIBRARY idn2
|
||||
LIBRARY_NAME IDN2
|
||||
NAMESPACE ""
|
||||
)
|
||||
target_include_directories(libidn2_sapi INTERFACE
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
"${SAPI_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
add_library(libidn2_sapi_wrapper
|
||||
libidn2_sapi.cc
|
||||
libidn2_sapi.h
|
||||
)
|
||||
add_library(sapi_contrib::libidn2 ALIAS libidn2_sapi_wrapper)
|
||||
target_link_libraries(libidn2_sapi_wrapper
|
||||
# PUBLIC so that the include directories are included in the interface
|
||||
PUBLIC libidn2_sapi
|
||||
sapi::base
|
||||
PRIVATE idn2
|
||||
)
|
||||
|
||||
if(SAPI_ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
90
contrib/libidn2/libidn2_sapi.cc
Normal file
90
contrib/libidn2/libidn2_sapi.cc
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "libidn2_sapi.h" // NOLINT(build/include)
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "sandboxed_api/util/fileops.h"
|
||||
|
||||
static constexpr std::size_t kMaxDomainNameLength = 256;
|
||||
static constexpr int kMinPossibleKnownError = -10000;
|
||||
|
||||
absl::StatusOr<std::string> IDN2Lib::ProcessErrors(
|
||||
const absl::StatusOr<int>& untrusted_res, sapi::v::GenericPtr& ptr) {
|
||||
SAPI_RETURN_IF_ERROR(untrusted_res.status());
|
||||
int res = untrusted_res.value();
|
||||
if (res < 0) {
|
||||
if (res == IDN2_MALLOC) {
|
||||
return absl::ResourceExhaustedError("malloc() failed in libidn2");
|
||||
}
|
||||
if (res > kMinPossibleKnownError) {
|
||||
return absl::InvalidArgumentError(idn2_strerror(res));
|
||||
}
|
||||
return absl::InvalidArgumentError("Unexpected error");
|
||||
}
|
||||
::sapi::v::RemotePtr p(reinterpret_cast<void*>(ptr.GetValue()));
|
||||
auto maybe_untrusted_name = sandbox_->GetCString(p, kMaxDomainNameLength);
|
||||
SAPI_RETURN_IF_ERROR(sandbox_->Free(&p));
|
||||
if (!maybe_untrusted_name.ok()) {
|
||||
return maybe_untrusted_name.status();
|
||||
}
|
||||
// FIXME: sanitize the result by checking that the return value is
|
||||
// valid ASCII (for a-labels) or UTF-8 (for u-labels) and doesn't
|
||||
// contain potentially malicious characters.
|
||||
return *maybe_untrusted_name;
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> IDN2Lib::idn2_register_u8(const char* ulabel,
|
||||
const char* alabel) {
|
||||
::std::optional<::sapi::v::ConstCStr> alabel_ptr, ulabel_ptr;
|
||||
if (ulabel) ulabel_ptr.emplace(ulabel);
|
||||
if (alabel) alabel_ptr.emplace(alabel);
|
||||
::sapi::v::GenericPtr ptr;
|
||||
::sapi::v::NullPtr null_ptr;
|
||||
const auto untrusted_res = api_.idn2_register_u8(
|
||||
ulabel ? ulabel_ptr->PtrBefore() : &null_ptr,
|
||||
alabel ? alabel_ptr->PtrBefore() : &null_ptr, ptr.PtrAfter(),
|
||||
IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
|
||||
return this->ProcessErrors(untrusted_res, ptr);
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> IDN2Lib::SapiGeneric(
|
||||
const char* data,
|
||||
absl::StatusOr<int> (IDN2Api::*cb)(sapi::v::Ptr* input,
|
||||
sapi::v::Ptr* output, int flags)) {
|
||||
::sapi::v::ConstCStr src(data);
|
||||
::sapi::v::GenericPtr ptr;
|
||||
|
||||
absl::StatusOr<int> untrusted_res = ((api_).*(cb))(
|
||||
src.PtrBefore(), ptr.PtrAfter(), IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
|
||||
return this->ProcessErrors(untrusted_res, ptr);
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> IDN2Lib::idn2_to_unicode_8z8z(const char* data) {
|
||||
return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_to_unicode_8z8z);
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> IDN2Lib::idn2_to_ascii_8z(const char* data) {
|
||||
return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_to_ascii_8z);
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> IDN2Lib::idn2_lookup_u8(const char* data) {
|
||||
return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_lookup_u8);
|
||||
}
|
65
contrib/libidn2/libidn2_sapi.h
Normal file
65
contrib/libidn2/libidn2_sapi.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CONTRIB_LIBIDN2_LIBIDN2_SAPI_H_
|
||||
#define CONTRIB_LIBIDN2_LIBIDN2_SAPI_H_
|
||||
|
||||
#include <idn2.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "libidn2_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/fileops.h"
|
||||
class Idn2SapiSandbox : public IDN2Sandbox {
|
||||
public:
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowSystemMalloc()
|
||||
.AllowRead()
|
||||
.AllowStat()
|
||||
.AllowWrite()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_close,
|
||||
__NR_lseek,
|
||||
__NR_getpid,
|
||||
})
|
||||
.BuildOrDie();
|
||||
}
|
||||
};
|
||||
|
||||
class IDN2Lib {
|
||||
public:
|
||||
explicit IDN2Lib(Idn2SapiSandbox* sandbox)
|
||||
: sandbox_(CHECK_NOTNULL(sandbox)), api_(sandbox_) {}
|
||||
absl::StatusOr<std::string> idn2_register_u8(const char* ulabel,
|
||||
const char* alabel);
|
||||
absl::StatusOr<std::string> idn2_lookup_u8(const char* data);
|
||||
absl::StatusOr<std::string> idn2_to_ascii_8z(const char* ulabel);
|
||||
absl::StatusOr<std::string> idn2_to_unicode_8z8z(const char* ulabel);
|
||||
|
||||
private:
|
||||
absl::StatusOr<std::string> SapiGeneric(
|
||||
const char* data,
|
||||
absl::StatusOr<int> (IDN2Api::*cb)(sapi::v::Ptr* input,
|
||||
sapi::v::Ptr* output, int flags));
|
||||
absl::StatusOr<std::string> ProcessErrors(const absl::StatusOr<int>& status,
|
||||
sapi::v::GenericPtr& ptr);
|
||||
Idn2SapiSandbox* sandbox_;
|
||||
IDN2Api api_;
|
||||
};
|
||||
#endif // CONTRIB_LIBIDN2_LIBIDN2_SAPI_H_
|
22
contrib/libidn2/tests/CMakeLists.txt
Normal file
22
contrib/libidn2/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_executable(libidn2_sapi_test
|
||||
libidn2_sapi_test.cc
|
||||
)
|
||||
target_link_libraries(libidn2_sapi_test PRIVATE
|
||||
sapi_contrib::libidn2
|
||||
sapi::test_main
|
||||
)
|
||||
gtest_discover_tests(libidn2_sapi_test)
|
64
contrib/libidn2/tests/libidn2_sapi_test.cc
Normal file
64
contrib/libidn2/tests/libidn2_sapi_test.cc
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "contrib/libidn2/libidn2_sapi.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/testing.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
using ::sapi::IsOk;
|
||||
using ::testing::Not;
|
||||
using ::testing::StrEq;
|
||||
|
||||
class Idn2SapiSandboxTest : public testing::Test {
|
||||
protected:
|
||||
static void SetUpTestSuite() {
|
||||
sandbox_ = new Idn2SapiSandbox();
|
||||
ASSERT_THAT(sandbox_->Init(), IsOk());
|
||||
lib_ = new IDN2Lib(sandbox_);
|
||||
}
|
||||
static void TearDownTestSuite() {
|
||||
delete lib_;
|
||||
delete sandbox_;
|
||||
}
|
||||
static IDN2Lib* lib_;
|
||||
|
||||
private:
|
||||
static Idn2SapiSandbox* sandbox_;
|
||||
};
|
||||
|
||||
IDN2Lib* Idn2SapiSandboxTest::lib_;
|
||||
Idn2SapiSandbox* Idn2SapiSandboxTest::sandbox_;
|
||||
|
||||
TEST_F(Idn2SapiSandboxTest, WorksOkay) {
|
||||
EXPECT_THAT(lib_->idn2_lookup_u8("β").value(), StrEq("xn--nxa"));
|
||||
EXPECT_THAT(lib_->idn2_lookup_u8("ß").value(), StrEq("xn--zca"));
|
||||
EXPECT_THAT(lib_->idn2_lookup_u8("straße.de").value(),
|
||||
StrEq("xn--strae-oqa.de"));
|
||||
EXPECT_THAT(lib_->idn2_to_unicode_8z8z("xn--strae-oqa.de").value(),
|
||||
StrEq("straße.de"));
|
||||
EXPECT_THAT(lib_->idn2_lookup_u8("--- "), Not(IsOk()));
|
||||
}
|
||||
|
||||
TEST_F(Idn2SapiSandboxTest, RegisterConversion) {
|
||||
// I could not get this to succeed except on ASCII-only strings
|
||||
EXPECT_THAT(lib_->idn2_register_u8("βgr", "xn--gr-e9b").value(),
|
||||
StrEq("xn--gr-e9b"));
|
||||
EXPECT_THAT(lib_->idn2_register_u8("βgr", "xn--gr-e9"), Not(IsOk()));
|
||||
EXPECT_THAT(lib_->idn2_register_u8("β.gr", nullptr), Not(IsOk()));
|
||||
}
|
Loading…
Reference in New Issue
Block a user