1 // Copyright 2022 Google LLC
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 // https://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 "libidn2_sapi.h" // NOLINT(build/include)
16
17 #include <cstdlib>
18 #include <fstream>
19 #include <iostream>
20
21 #include "absl/log/log.h"
22 #include "sandboxed_api/util/fileops.h"
23
24 static constexpr std::size_t kMaxDomainNameLength = 256;
25 static constexpr int kMinPossibleKnownError = -10000;
26
ProcessErrors(const absl::StatusOr<int> & untrusted_res,sapi::v::GenericPtr & ptr)27 absl::StatusOr<std::string> IDN2Lib::ProcessErrors(
28 const absl::StatusOr<int>& untrusted_res, sapi::v::GenericPtr& ptr) {
29 SAPI_RETURN_IF_ERROR(untrusted_res.status());
30 int res = untrusted_res.value();
31 if (res < 0) {
32 if (res == IDN2_MALLOC) {
33 return absl::ResourceExhaustedError("malloc() failed in libidn2");
34 }
35 if (res > kMinPossibleKnownError) {
36 return absl::InvalidArgumentError(idn2_strerror(res));
37 }
38 return absl::InvalidArgumentError("Unexpected error");
39 }
40 sapi::v::RemotePtr p(reinterpret_cast<void*>(ptr.GetValue()));
41 auto maybe_untrusted_name = sandbox_->GetCString(p, kMaxDomainNameLength);
42 SAPI_RETURN_IF_ERROR(sandbox_->Free(&p));
43 if (!maybe_untrusted_name.ok()) {
44 return maybe_untrusted_name.status();
45 }
46 // FIXME: sanitize the result by checking that the return value is
47 // valid ASCII (for a-labels) or UTF-8 (for u-labels) and doesn't
48 // contain potentially malicious characters.
49 return *maybe_untrusted_name;
50 }
51
idn2_register_u8(const char * ulabel,const char * alabel)52 absl::StatusOr<std::string> IDN2Lib::idn2_register_u8(const char* ulabel,
53 const char* alabel) {
54 std::optional<sapi::v::ConstCStr> alabel_ptr;
55 std::optional<sapi::v::ConstCStr> ulabel_ptr;
56 if (ulabel) {
57 ulabel_ptr.emplace(ulabel);
58 }
59 if (alabel) {
60 alabel_ptr.emplace(alabel);
61 }
62 sapi::v::GenericPtr ptr;
63 sapi::v::NullPtr null_ptr;
64 const auto untrusted_res = api_.idn2_register_u8(
65 ulabel ? ulabel_ptr->PtrBefore() : &null_ptr,
66 alabel ? alabel_ptr->PtrBefore() : &null_ptr, ptr.PtrAfter(),
67 IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
68 return this->ProcessErrors(untrusted_res, ptr);
69 }
70
SapiGeneric(const char * data,absl::StatusOr<int> (IDN2Api::* cb)(sapi::v::Ptr * input,sapi::v::Ptr * output,int flags))71 absl::StatusOr<std::string> IDN2Lib::SapiGeneric(
72 const char* data,
73 absl::StatusOr<int> (IDN2Api::*cb)(sapi::v::Ptr* input,
74 sapi::v::Ptr* output, int flags)) {
75 sapi::v::ConstCStr src(data);
76 sapi::v::GenericPtr ptr;
77
78 absl::StatusOr<int> untrusted_res = ((api_).*(cb))(
79 src.PtrBefore(), ptr.PtrAfter(), IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
80 return this->ProcessErrors(untrusted_res, ptr);
81 }
82
idn2_to_unicode_8z8z(const char * data)83 absl::StatusOr<std::string> IDN2Lib::idn2_to_unicode_8z8z(const char* data) {
84 return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_to_unicode_8z8z);
85 }
86
idn2_to_ascii_8z(const char * data)87 absl::StatusOr<std::string> IDN2Lib::idn2_to_ascii_8z(const char* data) {
88 return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_to_ascii_8z);
89 }
90
idn2_lookup_u8(const char * data)91 absl::StatusOr<std::string> IDN2Lib::idn2_lookup_u8(const char* data) {
92 return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_lookup_u8);
93 }
94