| 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 | |