| 1 | // Licensed to the .NET Foundation under one or more agreements. | 
|---|
| 2 | // The .NET Foundation licenses this file to you under the MIT license. | 
|---|
| 3 | // See the LICENSE file in the project root for more information. | 
|---|
| 4 |  | 
|---|
| 5 | /*++ | 
|---|
| 6 |  | 
|---|
| 7 |  | 
|---|
| 8 |  | 
|---|
| 9 | Module Name: | 
|---|
| 10 |  | 
|---|
| 11 | miscpalapi.c | 
|---|
| 12 |  | 
|---|
| 13 | Abstract: | 
|---|
| 14 |  | 
|---|
| 15 | Implementation misc PAL APIs | 
|---|
| 16 |  | 
|---|
| 17 | Revision History: | 
|---|
| 18 |  | 
|---|
| 19 |  | 
|---|
| 20 |  | 
|---|
| 21 | --*/ | 
|---|
| 22 |  | 
|---|
| 23 | #include "pal/palinternal.h" | 
|---|
| 24 | #include "pal/dbgmsg.h" | 
|---|
| 25 | #include "pal/file.h" | 
|---|
| 26 | #include "pal/process.h" | 
|---|
| 27 | #include "pal/module.h" | 
|---|
| 28 | #include "pal/malloc.hpp" | 
|---|
| 29 | #include "pal/stackstring.hpp" | 
|---|
| 30 |  | 
|---|
| 31 | #include <errno.h> | 
|---|
| 32 | #include <unistd.h> | 
|---|
| 33 | #include <time.h> | 
|---|
| 34 | #include <pthread.h> | 
|---|
| 35 | #include <dlfcn.h> | 
|---|
| 36 |  | 
|---|
| 37 | #include <pal_endian.h> | 
|---|
| 38 |  | 
|---|
| 39 | #ifdef __APPLE__ | 
|---|
| 40 | #include <mach-o/dyld.h> | 
|---|
| 41 | #endif // __APPLE__ | 
|---|
| 42 |  | 
|---|
| 43 | SET_DEFAULT_DEBUG_CHANNEL(MISC); | 
|---|
| 44 |  | 
|---|
| 45 | static const char URANDOM_DEVICE_NAME[]= "/dev/urandom"; | 
|---|
| 46 |  | 
|---|
| 47 | /*++ | 
|---|
| 48 |  | 
|---|
| 49 | Function : | 
|---|
| 50 |  | 
|---|
| 51 | PAL_GetPALDirectoryW | 
|---|
| 52 |  | 
|---|
| 53 | Returns the fully qualified path name | 
|---|
| 54 | where the PALL DLL was loaded from. | 
|---|
| 55 |  | 
|---|
| 56 | On failure it returns FALSE and sets the | 
|---|
| 57 | proper LastError code. | 
|---|
| 58 |  | 
|---|
| 59 | --*/ | 
|---|
| 60 | BOOL | 
|---|
| 61 | PAL_GetPALDirectoryW(PathWCharString& lpDirectoryName) | 
|---|
| 62 | { | 
|---|
| 63 | LPCWSTR lpFullPathAndName = NULL; | 
|---|
| 64 | LPCWSTR lpEndPoint = NULL; | 
|---|
| 65 | BOOL bRet = FALSE; | 
|---|
| 66 |  | 
|---|
| 67 | PERF_ENTRY(PAL_GetPALDirectoryW); | 
|---|
| 68 |  | 
|---|
| 69 | MODSTRUCT *module = LOADGetPalLibrary(); | 
|---|
| 70 | if (!module) | 
|---|
| 71 | { | 
|---|
| 72 | SetLastError(ERROR_INTERNAL_ERROR); | 
|---|
| 73 | goto EXIT; | 
|---|
| 74 | } | 
|---|
| 75 | lpFullPathAndName = module->lib_name; | 
|---|
| 76 | if (lpFullPathAndName == NULL) | 
|---|
| 77 | { | 
|---|
| 78 | SetLastError(ERROR_INTERNAL_ERROR); | 
|---|
| 79 | goto EXIT; | 
|---|
| 80 | } | 
|---|
| 81 | lpEndPoint = PAL_wcsrchr( lpFullPathAndName, '/' ); | 
|---|
| 82 | if ( lpEndPoint ) | 
|---|
| 83 | { | 
|---|
| 84 | /* The path that we return is required to have | 
|---|
| 85 | the trailing slash on the end.*/ | 
|---|
| 86 | lpEndPoint++; | 
|---|
| 87 |  | 
|---|
| 88 |  | 
|---|
| 89 | if(!lpDirectoryName.Set(lpFullPathAndName,lpEndPoint - lpFullPathAndName)) | 
|---|
| 90 | { | 
|---|
| 91 | ASSERT( "The buffer was not large enough.\n"); | 
|---|
| 92 | SetLastError( ERROR_INSUFFICIENT_BUFFER ); | 
|---|
| 93 | goto EXIT; | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | bRet = TRUE; | 
|---|
| 97 | } | 
|---|
| 98 | else | 
|---|
| 99 | { | 
|---|
| 100 | ASSERT( "Unable to determine the path.\n"); | 
|---|
| 101 | /* Error path, should not be executed. */ | 
|---|
| 102 | SetLastError( ERROR_INTERNAL_ERROR ); | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 | EXIT: | 
|---|
| 106 | PERF_EXIT(PAL_GetPALDirectoryW); | 
|---|
| 107 | return bRet; | 
|---|
| 108 | } | 
|---|
| 109 |  | 
|---|
| 110 | BOOL | 
|---|
| 111 | PAL_GetPALDirectoryA(PathCharString& lpDirectoryName) | 
|---|
| 112 | { | 
|---|
| 113 | BOOL bRet; | 
|---|
| 114 | PathWCharString directory; | 
|---|
| 115 |  | 
|---|
| 116 | PERF_ENTRY(PAL_GetPALDirectoryA); | 
|---|
| 117 |  | 
|---|
| 118 | bRet = PAL_GetPALDirectoryW(directory); | 
|---|
| 119 |  | 
|---|
| 120 | if (bRet) | 
|---|
| 121 | { | 
|---|
| 122 |  | 
|---|
| 123 | int length = WideCharToMultiByte(CP_ACP, 0, directory.GetString(), -1, NULL, 0, NULL, 0); | 
|---|
| 124 | LPSTR DirectoryName = lpDirectoryName.OpenStringBuffer(length); | 
|---|
| 125 | if (NULL == DirectoryName) | 
|---|
| 126 | { | 
|---|
| 127 | SetLastError( ERROR_INSUFFICIENT_BUFFER ); | 
|---|
| 128 | bRet = FALSE; | 
|---|
| 129 | } | 
|---|
| 130 |  | 
|---|
| 131 | length = WideCharToMultiByte(CP_ACP, 0, directory.GetString(), -1, DirectoryName, length, NULL, 0); | 
|---|
| 132 |  | 
|---|
| 133 | if (0 == length) | 
|---|
| 134 | { | 
|---|
| 135 | bRet = FALSE; | 
|---|
| 136 | length++; | 
|---|
| 137 | } | 
|---|
| 138 |  | 
|---|
| 139 | lpDirectoryName.CloseBuffer(length - 1); | 
|---|
| 140 | } | 
|---|
| 141 |  | 
|---|
| 142 | PERF_EXIT(PAL_GetPALDirectoryA); | 
|---|
| 143 | return bRet; | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | /*++ | 
|---|
| 147 |  | 
|---|
| 148 | Function : | 
|---|
| 149 |  | 
|---|
| 150 | PAL_GetPALDirectoryW | 
|---|
| 151 |  | 
|---|
| 152 | Returns the fully qualified path name | 
|---|
| 153 | where the PALL DLL was loaded from. | 
|---|
| 154 |  | 
|---|
| 155 | On failure it returns FALSE and sets the | 
|---|
| 156 | proper LastError code. | 
|---|
| 157 |  | 
|---|
| 158 | --*/ | 
|---|
| 159 | PALIMPORT | 
|---|
| 160 | BOOL | 
|---|
| 161 | PALAPI | 
|---|
| 162 | PAL_GetPALDirectoryW( OUT LPWSTR lpDirectoryName, IN OUT UINT* cchDirectoryName ) | 
|---|
| 163 | { | 
|---|
| 164 | PathWCharString directory; | 
|---|
| 165 | BOOL bRet; | 
|---|
| 166 | PERF_ENTRY(PAL_GetPALDirectoryW); | 
|---|
| 167 | ENTRY( "PAL_GetPALDirectoryW( %p, %d )\n", lpDirectoryName, *cchDirectoryName ); | 
|---|
| 168 |  | 
|---|
| 169 | bRet = PAL_GetPALDirectoryW(directory); | 
|---|
| 170 |  | 
|---|
| 171 | if (bRet) { | 
|---|
| 172 |  | 
|---|
| 173 | if (directory.GetCount() > *cchDirectoryName) | 
|---|
| 174 | { | 
|---|
| 175 | SetLastError( ERROR_INSUFFICIENT_BUFFER ); | 
|---|
| 176 | bRet = FALSE; | 
|---|
| 177 | } | 
|---|
| 178 | else | 
|---|
| 179 | { | 
|---|
| 180 | PAL_wcscpy(lpDirectoryName, directory.GetString()); | 
|---|
| 181 | } | 
|---|
| 182 |  | 
|---|
| 183 | *cchDirectoryName = directory.GetCount(); | 
|---|
| 184 | } | 
|---|
| 185 |  | 
|---|
| 186 | LOGEXIT( "PAL_GetPALDirectoryW returns BOOL %d.\n", bRet); | 
|---|
| 187 | PERF_EXIT(PAL_GetPALDirectoryW); | 
|---|
| 188 | return bRet; | 
|---|
| 189 |  | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 | PALIMPORT | 
|---|
| 193 | BOOL | 
|---|
| 194 | PALAPI | 
|---|
| 195 | PAL_GetPALDirectoryA( | 
|---|
| 196 | OUT LPSTR lpDirectoryName, | 
|---|
| 197 | IN UINT*  cchDirectoryName) | 
|---|
| 198 | { | 
|---|
| 199 | BOOL bRet; | 
|---|
| 200 | PathCharString directory; | 
|---|
| 201 |  | 
|---|
| 202 | PERF_ENTRY(PAL_GetPALDirectoryA); | 
|---|
| 203 | ENTRY( "PAL_GetPALDirectoryA( %p, %d )\n", lpDirectoryName, *cchDirectoryName ); | 
|---|
| 204 |  | 
|---|
| 205 | bRet = PAL_GetPALDirectoryA(directory); | 
|---|
| 206 |  | 
|---|
| 207 | if (bRet) | 
|---|
| 208 | { | 
|---|
| 209 | if (directory.GetCount() > *cchDirectoryName) | 
|---|
| 210 | { | 
|---|
| 211 | SetLastError( ERROR_INSUFFICIENT_BUFFER ); | 
|---|
| 212 | bRet = FALSE; | 
|---|
| 213 | *cchDirectoryName = directory.GetCount(); | 
|---|
| 214 | } | 
|---|
| 215 | else if (strcpy_s(lpDirectoryName, directory.GetCount(), directory.GetString()) == SAFECRT_SUCCESS) | 
|---|
| 216 | { | 
|---|
| 217 | } | 
|---|
| 218 | else | 
|---|
| 219 | { | 
|---|
| 220 | bRet = FALSE; | 
|---|
| 221 | } | 
|---|
| 222 | } | 
|---|
| 223 |  | 
|---|
| 224 | LOGEXIT( "PAL_GetPALDirectoryA returns BOOL %d.\n", bRet); | 
|---|
| 225 | PERF_EXIT(PAL_GetPALDirectoryA); | 
|---|
| 226 | return bRet; | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | VOID | 
|---|
| 230 | PALAPI | 
|---|
| 231 | PAL_Random( | 
|---|
| 232 | IN OUT LPVOID lpBuffer, | 
|---|
| 233 | IN DWORD dwLength) | 
|---|
| 234 | { | 
|---|
| 235 | int rand_des = -1; | 
|---|
| 236 | DWORD i; | 
|---|
| 237 | long num = 0; | 
|---|
| 238 | static BOOL sMissingDevURandom; | 
|---|
| 239 | static BOOL sInitializedMRand; | 
|---|
| 240 |  | 
|---|
| 241 | PERF_ENTRY(PAL_Random); | 
|---|
| 242 | ENTRY( "PAL_Random(lpBuffer=%p, dwLength=%d)\n", lpBuffer, dwLength); | 
|---|
| 243 |  | 
|---|
| 244 | if (!sMissingDevURandom) | 
|---|
| 245 | { | 
|---|
| 246 | do | 
|---|
| 247 | { | 
|---|
| 248 | rand_des = open( "/dev/urandom", O_RDONLY, O_CLOEXEC); | 
|---|
| 249 | } | 
|---|
| 250 | while ((rand_des == -1) && (errno == EINTR)); | 
|---|
| 251 |  | 
|---|
| 252 | if (rand_des == -1) | 
|---|
| 253 | { | 
|---|
| 254 | if (errno == ENOENT) | 
|---|
| 255 | { | 
|---|
| 256 | sMissingDevURandom = TRUE; | 
|---|
| 257 | } | 
|---|
| 258 | else | 
|---|
| 259 | { | 
|---|
| 260 | ASSERT( "PAL__open() failed, errno:%d (%s)\n", errno, strerror(errno)); | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | // Back off and try mrand48. | 
|---|
| 264 | } | 
|---|
| 265 | else | 
|---|
| 266 | { | 
|---|
| 267 | DWORD offset = 0; | 
|---|
| 268 | do | 
|---|
| 269 | { | 
|---|
| 270 | DWORD n = read(rand_des, (BYTE*)lpBuffer + offset , dwLength - offset); | 
|---|
| 271 | if (n == -1) | 
|---|
| 272 | { | 
|---|
| 273 | if (errno == EINTR) | 
|---|
| 274 | { | 
|---|
| 275 | continue; | 
|---|
| 276 | } | 
|---|
| 277 | ASSERT( "read() failed, errno:%d (%s)\n", errno, strerror(errno)); | 
|---|
| 278 |  | 
|---|
| 279 | break; | 
|---|
| 280 | } | 
|---|
| 281 |  | 
|---|
| 282 | offset += n; | 
|---|
| 283 | } | 
|---|
| 284 | while (offset != dwLength); | 
|---|
| 285 |  | 
|---|
| 286 | _ASSERTE(offset == dwLength); | 
|---|
| 287 |  | 
|---|
| 288 | close(rand_des); | 
|---|
| 289 | } | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | if (!sInitializedMRand) | 
|---|
| 293 | { | 
|---|
| 294 | srand48(time(NULL)); | 
|---|
| 295 | sInitializedMRand = TRUE; | 
|---|
| 296 | } | 
|---|
| 297 |  | 
|---|
| 298 | // always xor srand48 over the whole buffer to get some randomness | 
|---|
| 299 | // in case /dev/urandom is not really random | 
|---|
| 300 |  | 
|---|
| 301 | for (i = 0; i < dwLength; i++) | 
|---|
| 302 | { | 
|---|
| 303 | if (i % sizeof(long) == 0) { | 
|---|
| 304 | num = mrand48(); | 
|---|
| 305 | } | 
|---|
| 306 |  | 
|---|
| 307 | *(((BYTE*)lpBuffer) + i) ^= num; | 
|---|
| 308 | num >>= 8; | 
|---|
| 309 | } | 
|---|
| 310 |  | 
|---|
| 311 | LOGEXIT( "PAL_Random\n"); | 
|---|
| 312 | PERF_EXIT(PAL_Random); | 
|---|
| 313 | } | 
|---|
| 314 |  | 
|---|