xref: /aosp_15_r20/external/sandboxed-api/contrib/libidn2/libidn2_sapi.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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