1 /*
2 * Copyright (C) 2025 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // Defining protected as public to create object of SkEmbossMaskFilter
18 #define protected public
19
20 #include <sys/mman.h>
21 #include <unistd.h>
22
23 #include "binary_loader.h"
24 #include "common.h"
25 #include "include/core/SkMatrix.h"
26 #include "memutils.h"
27 #include "src/effects/SkEmbossMaskFilter.h"
28
29 typedef bool (*filterMask_func)(SkEmbossMaskFilter*, SkMaskBuilder*, const SkMaskBuilder&,
30 const SkMatrix&, SkIPoint*);
31 char* startPtr = nullptr;
32 struct sigaction new_action, old_action;
33 static void* (*real_malloc_func)(size_t) = nullptr;
34
35 // Set width and height such that '3 * width * height' exceeds INT_MAX (32-bit)
36 int kWidth = 1000;
37 int kHeight = 1000000;
38
sig_handler(int signum,siginfo_t * info,void * context)39 void sig_handler(int signum, siginfo_t* info, void* context) {
40 // Free the allocated buffer.
41 if (startPtr) {
42 ENABLE_MEM_ACCESS(startPtr, getpagesize());
43 free(startPtr);
44 }
45
46 // Check if signal is coming from expected address.
47 if ((((uintptr_t)info->si_addr ^ (uintptr_t)startPtr) & (uintptr_t)info->si_addr) == 0) {
48 (*old_action.sa_sigaction)(signum, info, context);
49 startPtr = nullptr;
50 exit(EXIT_VULNERABLE);
51 }
52 startPtr = nullptr;
53
54 // Assumption failure for unexpected signals.
55 exit(EXIT_FAILURE);
56 }
57
malloc(size_t size)58 void* malloc(size_t size) {
59 real_malloc_func = (void* (*)(size_t))dlsym(RTLD_NEXT, "malloc");
60 FAIL_CHECK(real_malloc_func);
61
62 // Return a guarded buffer
63 if (size == 3 * kWidth * kHeight) {
64 size_t page_size = getpagesize();
65 startPtr = (char*)memalign(page_size, page_size);
66 memset(startPtr, 0, page_size);
67 DISABLE_MEM_ACCESS(startPtr, page_size);
68 return startPtr;
69 }
70
71 // Call actual malloc().
72 return real_malloc_func(size);
73 }
74
main(int,char * argv[])75 int main(int /* argc */, char* argv[]) {
76 // Setup signal handler.
77 sigemptyset(&new_action.sa_mask);
78 sigaddset(&new_action.sa_mask, SIGSEGV); // Add SIGSEGV to the signal mask
79 sigaddset(&new_action.sa_mask, SIGBUS); // Add SIGBUS to the signal mask
80 new_action.sa_flags = SA_SIGINFO;
81 new_action.sa_sigaction = sig_handler;
82 sigaction(SIGSEGV, &new_action, &old_action);
83 sigaction(SIGBUS, &new_action, &old_action);
84
85 // Get the path to the shared library and offset from command-line arguments
86 const char* libPath = argv[1];
87 const uintptr_t functionOffset = strtoul(argv[2], nullptr, 0);
88
89 // Get function address of 'filterMask()' from loaded library
90 BinaryLoader binaryLoader(libPath);
91 const uintptr_t functionAddress = binaryLoader.getFunctionAddress(functionOffset);
92 FAIL_CHECK(functionAddress);
93
94 // Create function pointer to 'filterMask()'
95 filterMask_func filterMask_ptr = (filterMask_func)functionAddress;
96
97 // Create object of SkEmbossMaskFilter.
98 SkEmbossMaskFilter::Light light;
99 SkEmbossMaskFilter s(1.0f, light);
100
101 // Configure params with values such that '3 * width * height' exceed INT_MAX32 to cause
102 // integer overflow.
103 uint8_t* img = SkMaskBuilder::AllocImage(6 /* arbitrary value */);
104 const SkIRect& bounds = SkIRect::MakeWH(kWidth, kHeight);
105 uint32_t rowBytes = 0;
106 SkMask::Format format = SkMask::kA8_Format;
107 SkMaskBuilder dst(img, bounds, rowBytes, format), src(img, bounds, rowBytes, format);
108 SkMatrix matrix;
109 SkIPoint margin;
110
111 // Call the vulnerable function. Without fix, OOB read occurs. With fix, the function
112 // returns false due to the check and no buffer is allocated.
113 filterMask_ptr(&s, &dst, src, matrix, &margin);
114
115 return EXIT_SUCCESS;
116 }
117