1 /*
2  * Copyright 2004-2021 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #if (defined(_WIN64) || defined(_WIN32_WCE)) && !defined(UNICODE)
11 # define UNICODE
12 #endif
13 #if defined(UNICODE) && !defined(_UNICODE)
14 # define _UNICODE
15 #endif
16 #if defined(_UNICODE) && !defined(UNICODE)
17 # define UNICODE
18 #endif
19 
20 #include <windows.h>
21 #include <tchar.h>
22 #include <stdio.h>
23 #include <stddef.h>
24 #include "uplink.h"
25 void OPENSSL_showfatal(const char *, ...);
26 
27 static TCHAR msg[128];
28 
unimplemented(void)29 static void unimplemented(void)
30 {
31     OPENSSL_showfatal(sizeof(TCHAR) == sizeof(char) ? "%s\n" : "%S\n", msg);
32     TerminateProcess(GetCurrentProcess(), 1);
33 }
34 
OPENSSL_Uplink(volatile void ** table,int index)35 void OPENSSL_Uplink(volatile void **table, int index)
36 {
37     static HMODULE volatile apphandle = NULL;
38     static void **volatile applinktable = NULL;
39     int len;
40     void (*func) (void) = unimplemented;
41     HANDLE h;
42     void **p;
43 
44     /*
45      * Note that the below code is not MT-safe in respect to msg buffer, but
46      * what's the worst thing that can happen? Error message might be
47      * misleading or corrupted. As error condition is fatal and should never
48      * be risen, I accept the risk...
49      */
50     /*
51      * One can argue that I should have used InterlockedExchangePointer or
52      * something to update static variables and table[]. Well, store
53      * instructions are as atomic as they can get and assigned values are
54      * effectively constant... So that volatile qualifier should be
55      * sufficient [it prohibits compiler to reorder memory access
56      * instructions].
57      */
58     do {
59         len = _sntprintf(msg, sizeof(msg) / sizeof(TCHAR),
60                          _T("OPENSSL_Uplink(%p,%02X): "), table, index);
61         _tcscpy(msg + len, _T("unimplemented function"));
62 
63         if ((h = apphandle) == NULL) {
64             if ((h = GetModuleHandle(NULL)) == NULL) {
65                 apphandle = (HMODULE) - 1;
66                 _tcscpy(msg + len, _T("no host application"));
67                 break;
68             }
69             apphandle = h;
70         }
71         if ((h = apphandle) == (HMODULE) - 1) /* revalidate */
72             break;
73 
74         if (applinktable == NULL) {
75             void **(*applink) ();
76 
77             applink = (void **(*)())GetProcAddress(h, "OPENSSL_Applink");
78             if (applink == NULL) {
79                 apphandle = (HMODULE) - 1;
80                 _tcscpy(msg + len, _T("no OPENSSL_Applink"));
81                 break;
82             }
83             p = (*applink) ();
84             if (p == NULL) {
85                 apphandle = (HMODULE) - 1;
86                 _tcscpy(msg + len, _T("no ApplinkTable"));
87                 break;
88             }
89             applinktable = p;
90         } else
91             p = applinktable;
92 
93         if (index > (intptr_t)p[0])
94             break;
95 
96         if (p[index])
97             func = p[index];
98     } while (0);
99 
100     table[index] = func;
101 }
102 
103 #if (defined(_MSC_VER) || defined(__BORLANDC__)) && defined(_M_IX86)
104 # if defined(_MSC_VER)
105 #  define LAZY(i)         \
106 __declspec(naked) static void lazy##i (void) {  \
107         _asm    push i                          \
108         _asm    push OFFSET OPENSSL_UplinkTable \
109         _asm    call OPENSSL_Uplink             \
110         _asm    add  esp,8                      \
111         _asm    jmp  OPENSSL_UplinkTable+4*i    }
112 # elif defined(__BORLANDC__) && defined(__clang__)
113 void *OPENSSL_UplinkTable[26]; /* C++Builder requires declaration before use */
114 #  define LAZY(i)         \
115 __declspec(naked) static void lazy##i (void) { \
116     __asm__("pushl $" #i "; "                  \
117             "pushl %0; "                       \
118             "call  %P1; "                      \
119             "addl  $8, %%esp; "                \
120             "jmp   *%2 "                       \
121             : /* no outputs */                 \
122             : "i" (OPENSSL_UplinkTable),       \
123               "i" (OPENSSL_Uplink),            \
124               "m" (OPENSSL_UplinkTable[i]));   }
125 # endif
126 
127 # if APPLINK_MAX>25
128 #  error "Add more stubs..."
129 # endif
130 /* make some in advance... */
131 LAZY(1) LAZY(2) LAZY(3) LAZY(4) LAZY(5)
132     LAZY(6) LAZY(7) LAZY(8) LAZY(9) LAZY(10)
133     LAZY(11) LAZY(12) LAZY(13) LAZY(14) LAZY(15)
134     LAZY(16) LAZY(17) LAZY(18) LAZY(19) LAZY(20)
135     LAZY(21) LAZY(22) LAZY(23) LAZY(24) LAZY(25)
136 void *OPENSSL_UplinkTable[] = {
137     (void *)APPLINK_MAX,
138     lazy1, lazy2, lazy3, lazy4, lazy5,
139     lazy6, lazy7, lazy8, lazy9, lazy10,
140     lazy11, lazy12, lazy13, lazy14, lazy15,
141     lazy16, lazy17, lazy18, lazy19, lazy20,
142     lazy21, lazy22, lazy23, lazy24, lazy25,
143 };
144 #endif
145 
146 #ifdef SELFTEST
main()147 main()
148 {
149     UP_fprintf(UP_stdout, "hello, world!\n");
150 }
151 #endif
152