// 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 #include #include #include "absl/log/log.h" #include "sandboxed_api/util/fileops.h" static constexpr std::size_t kMaxDomainNameLength = 256; static constexpr int kMinPossibleKnownError = -10000; absl::StatusOr IDN2Lib::ProcessErrors( const absl::StatusOr& 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(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 IDN2Lib::idn2_register_u8(const char* ulabel, const char* alabel) { std::optional alabel_ptr; std::optional ulabel_ptr; if (ulabel) { ulabel_ptr.emplace(ulabel); } if (alabel) { alabel_ptr.emplace(alabel); } sapi::v::GenericPtr ptr; const auto untrusted_res = api_.idn2_register_u8( ulabel ? ulabel_ptr->PtrBefore() : nullptr, alabel ? alabel_ptr->PtrBefore() : nullptr, ptr.PtrAfter(), IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL); return this->ProcessErrors(untrusted_res, ptr); } absl::StatusOr IDN2Lib::SapiGeneric( const char* data, absl::StatusOr (IDN2Api::*cb)(sapi::v::Ptr* input, sapi::v::Ptr* output, int flags)) { sapi::v::ConstCStr src(data); sapi::v::GenericPtr ptr; absl::StatusOr untrusted_res = ((api_).*(cb))( src.PtrBefore(), ptr.PtrAfter(), IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL); return this->ProcessErrors(untrusted_res, ptr); } absl::StatusOr IDN2Lib::idn2_to_unicode_8z8z(const char* data) { return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_to_unicode_8z8z); } absl::StatusOr IDN2Lib::idn2_to_ascii_8z(const char* data) { return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_to_ascii_8z); } absl::StatusOr IDN2Lib::idn2_lookup_u8(const char* data) { return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_lookup_u8); }