diff options
| author | Paul Eggert | 2011-08-28 16:52:34 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-08-28 16:52:34 -0700 |
| commit | 17107bb698f82bb5b9c8a732cd6b3faaad4d7af6 (patch) | |
| tree | 5a0e1fb90617fbe9eb24ae763caed03c45daf948 | |
| parent | 5fc295a42feaef453b57010b826e589b9b9cb7dd (diff) | |
| download | emacs-17107bb698f82bb5b9c8a732cd6b3faaad4d7af6.tar.gz emacs-17107bb698f82bb5b9c8a732cd6b3faaad4d7af6.zip | |
Integer and memory overflow issues.
* emacsclient.c (xmalloc): Accept size_t, not unsigned int, to
avoid potential buffer overflow issues on typical 64-bit hosts.
Return void *, not long *.
(get_current_dir_name): Report a failure, instead of looping
forever, if buffer size calculation overflows. Treat malloc
failures like realloc failures, as that has better behavior and is
more consistent. Do not check whether xmalloc returns NULL, as
that's not possible.
(message): Do not arbitrarily truncate message to 2048 bytes when
sending it to stderr; use vfprintf instead.
(get_server_config, set_local_socket)
(start_daemon_and_retry_set_socket): Do not alloca
arbitrarily-large buffers; that's not safe.
(get_server_config, set_local_socket): Do not use sprintf when its
result might not fit in 'int'.
(set_local_socket): Do not assume uid fits in 'int'.
| -rw-r--r-- | lib-src/ChangeLog | 21 | ||||
| -rw-r--r-- | lib-src/emacsclient.c | 95 |
2 files changed, 79 insertions, 37 deletions
diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog index c878d313b70..d056b1a4b81 100644 --- a/lib-src/ChangeLog +++ b/lib-src/ChangeLog | |||
| @@ -1,3 +1,24 @@ | |||
| 1 | 2011-08-28 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Integer and memory overflow issues. | ||
| 4 | |||
| 5 | * emacsclient.c (xmalloc): Accept size_t, not unsigned int, to | ||
| 6 | avoid potential buffer overflow issues on typical 64-bit hosts. | ||
| 7 | Return void *, not long *. | ||
| 8 | (get_current_dir_name): Report a failure, instead of looping | ||
| 9 | forever, if buffer size calculation overflows. Treat malloc | ||
| 10 | failures like realloc failures, as that has better behavior and is | ||
| 11 | more consistent. Do not check whether xmalloc returns NULL, as | ||
| 12 | that's not possible. | ||
| 13 | (message): Do not arbitrarily truncate message to 2048 bytes when | ||
| 14 | sending it to stderr; use vfprintf instead. | ||
| 15 | (get_server_config, set_local_socket) | ||
| 16 | (start_daemon_and_retry_set_socket): Do not alloca | ||
| 17 | arbitrarily-large buffers; that's not safe. | ||
| 18 | (get_server_config, set_local_socket): Do not use sprintf when its | ||
| 19 | result might not fit in 'int'. | ||
| 20 | (set_local_socket): Do not assume uid fits in 'int'. | ||
| 21 | |||
| 1 | 2011-07-28 Paul Eggert <eggert@cs.ucla.edu> | 22 | 2011-07-28 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 23 | ||
| 3 | Assume freestanding C89 headers, string.h, stdlib.h. | 24 | Assume freestanding C89 headers, string.h, stdlib.h. |
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index 2af139aee6d..ece9dc65c49 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c | |||
| @@ -194,10 +194,10 @@ struct option longopts[] = | |||
| 194 | 194 | ||
| 195 | /* Like malloc but get fatal error if memory is exhausted. */ | 195 | /* Like malloc but get fatal error if memory is exhausted. */ |
| 196 | 196 | ||
| 197 | static long * | 197 | static void * |
| 198 | xmalloc (unsigned int size) | 198 | xmalloc (size_t size) |
| 199 | { | 199 | { |
| 200 | long *result = (long *) malloc (size); | 200 | void *result = malloc (size); |
| 201 | if (result == NULL) | 201 | if (result == NULL) |
| 202 | { | 202 | { |
| 203 | perror ("malloc"); | 203 | perror ("malloc"); |
| @@ -250,32 +250,33 @@ get_current_dir_name (void) | |||
| 250 | ) | 250 | ) |
| 251 | { | 251 | { |
| 252 | buf = (char *) xmalloc (strlen (pwd) + 1); | 252 | buf = (char *) xmalloc (strlen (pwd) + 1); |
| 253 | if (!buf) | ||
| 254 | return NULL; | ||
| 255 | strcpy (buf, pwd); | 253 | strcpy (buf, pwd); |
| 256 | } | 254 | } |
| 257 | #ifdef HAVE_GETCWD | 255 | #ifdef HAVE_GETCWD |
| 258 | else | 256 | else |
| 259 | { | 257 | { |
| 260 | size_t buf_size = 1024; | 258 | size_t buf_size = 1024; |
| 261 | buf = (char *) xmalloc (buf_size); | ||
| 262 | if (!buf) | ||
| 263 | return NULL; | ||
| 264 | for (;;) | 259 | for (;;) |
| 265 | { | 260 | { |
| 261 | int tmp_errno; | ||
| 262 | buf = malloc (buf_size); | ||
| 263 | if (! buf) | ||
| 264 | break; | ||
| 266 | if (getcwd (buf, buf_size) == buf) | 265 | if (getcwd (buf, buf_size) == buf) |
| 267 | break; | 266 | break; |
| 268 | if (errno != ERANGE) | 267 | tmp_errno = errno; |
| 268 | free (buf); | ||
| 269 | if (tmp_errno != ERANGE) | ||
| 269 | { | 270 | { |
| 270 | int tmp_errno = errno; | ||
| 271 | free (buf); | ||
| 272 | errno = tmp_errno; | 271 | errno = tmp_errno; |
| 273 | return NULL; | 272 | return NULL; |
| 274 | } | 273 | } |
| 275 | buf_size *= 2; | 274 | buf_size *= 2; |
| 276 | buf = (char *) realloc (buf, buf_size); | 275 | if (! buf_size) |
| 277 | if (!buf) | 276 | { |
| 278 | return NULL; | 277 | errno = ENOMEM; |
| 278 | return NULL; | ||
| 279 | } | ||
| 279 | } | 280 | } |
| 280 | } | 281 | } |
| 281 | #else | 282 | #else |
| @@ -283,8 +284,6 @@ get_current_dir_name (void) | |||
| 283 | { | 284 | { |
| 284 | /* We need MAXPATHLEN here. */ | 285 | /* We need MAXPATHLEN here. */ |
| 285 | buf = (char *) xmalloc (MAXPATHLEN + 1); | 286 | buf = (char *) xmalloc (MAXPATHLEN + 1); |
| 286 | if (!buf) | ||
| 287 | return NULL; | ||
| 288 | if (getwd (buf) == NULL) | 287 | if (getwd (buf) == NULL) |
| 289 | { | 288 | { |
| 290 | int tmp_errno = errno; | 289 | int tmp_errno = errno; |
| @@ -494,16 +493,17 @@ static void message (int, const char *, ...) ATTRIBUTE_FORMAT_PRINTF (2, 3); | |||
| 494 | static void | 493 | static void |
| 495 | message (int is_error, const char *format, ...) | 494 | message (int is_error, const char *format, ...) |
| 496 | { | 495 | { |
| 497 | char msg[2048]; | ||
| 498 | va_list args; | 496 | va_list args; |
| 499 | 497 | ||
| 500 | va_start (args, format); | 498 | va_start (args, format); |
| 501 | vsprintf (msg, format, args); | ||
| 502 | va_end (args); | ||
| 503 | 499 | ||
| 504 | #ifdef WINDOWSNT | 500 | #ifdef WINDOWSNT |
| 505 | if (w32_window_app ()) | 501 | if (w32_window_app ()) |
| 506 | { | 502 | { |
| 503 | char msg[2048]; | ||
| 504 | vsnprintf (msg, sizeof msg, format, args); | ||
| 505 | msg[sizeof msg - 1] = '\0'; | ||
| 506 | |||
| 507 | if (is_error) | 507 | if (is_error) |
| 508 | MessageBox (NULL, msg, "Emacsclient ERROR", MB_ICONERROR); | 508 | MessageBox (NULL, msg, "Emacsclient ERROR", MB_ICONERROR); |
| 509 | else | 509 | else |
| @@ -514,9 +514,11 @@ message (int is_error, const char *format, ...) | |||
| 514 | { | 514 | { |
| 515 | FILE *f = is_error ? stderr : stdout; | 515 | FILE *f = is_error ? stderr : stdout; |
| 516 | 516 | ||
| 517 | fputs (msg, f); | 517 | vfprintf (f, format, args); |
| 518 | fflush (f); | 518 | fflush (f); |
| 519 | } | 519 | } |
| 520 | |||
| 521 | va_end (args); | ||
| 520 | } | 522 | } |
| 521 | 523 | ||
| 522 | /* Decode the options from argv and argc. | 524 | /* Decode the options from argv and argc. |
| @@ -959,18 +961,24 @@ get_server_config (struct sockaddr_in *server, char *authentication) | |||
| 959 | 961 | ||
| 960 | if (home) | 962 | if (home) |
| 961 | { | 963 | { |
| 962 | char *path = alloca (strlen (home) + strlen (server_file) | 964 | char *path = xmalloc (strlen (home) + strlen (server_file) |
| 963 | + EXTRA_SPACE); | 965 | + EXTRA_SPACE); |
| 964 | sprintf (path, "%s/.emacs.d/server/%s", home, server_file); | 966 | strcpy (path, home); |
| 967 | strcat (path, "/.emacs.d/server/"); | ||
| 968 | strcat (path, server_file); | ||
| 965 | config = fopen (path, "rb"); | 969 | config = fopen (path, "rb"); |
| 970 | free (path); | ||
| 966 | } | 971 | } |
| 967 | #ifdef WINDOWSNT | 972 | #ifdef WINDOWSNT |
| 968 | if (!config && (home = egetenv ("APPDATA"))) | 973 | if (!config && (home = egetenv ("APPDATA"))) |
| 969 | { | 974 | { |
| 970 | char *path = alloca (strlen (home) + strlen (server_file) | 975 | char *path = xmalloc (strlen (home) + strlen (server_file) |
| 971 | + EXTRA_SPACE); | 976 | + EXTRA_SPACE); |
| 972 | sprintf (path, "%s/.emacs.d/server/%s", home, server_file); | 977 | strcpy (path, home); |
| 978 | strcat (path, "/.emacs.d/server/"); | ||
| 979 | strcat (path, server_file); | ||
| 973 | config = fopen (path, "rb"); | 980 | config = fopen (path, "rb"); |
| 981 | free (path); | ||
| 974 | } | 982 | } |
| 975 | #endif | 983 | #endif |
| 976 | } | 984 | } |
| @@ -1243,6 +1251,8 @@ set_local_socket (void) | |||
| 1243 | int saved_errno = 0; | 1251 | int saved_errno = 0; |
| 1244 | const char *server_name = "server"; | 1252 | const char *server_name = "server"; |
| 1245 | const char *tmpdir IF_LINT ( = NULL); | 1253 | const char *tmpdir IF_LINT ( = NULL); |
| 1254 | char *tmpdir_storage = NULL; | ||
| 1255 | char *socket_name_storage = NULL; | ||
| 1246 | 1256 | ||
| 1247 | if (socket_name && !strchr (socket_name, '/') | 1257 | if (socket_name && !strchr (socket_name, '/') |
| 1248 | && !strchr (socket_name, '\\')) | 1258 | && !strchr (socket_name, '\\')) |
| @@ -1255,6 +1265,8 @@ set_local_socket (void) | |||
| 1255 | 1265 | ||
| 1256 | if (default_sock) | 1266 | if (default_sock) |
| 1257 | { | 1267 | { |
| 1268 | long uid = geteuid (); | ||
| 1269 | ptrdiff_t tmpdirlen; | ||
| 1258 | tmpdir = egetenv ("TMPDIR"); | 1270 | tmpdir = egetenv ("TMPDIR"); |
| 1259 | if (!tmpdir) | 1271 | if (!tmpdir) |
| 1260 | { | 1272 | { |
| @@ -1265,17 +1277,19 @@ set_local_socket (void) | |||
| 1265 | size_t n = confstr (_CS_DARWIN_USER_TEMP_DIR, NULL, (size_t) 0); | 1277 | size_t n = confstr (_CS_DARWIN_USER_TEMP_DIR, NULL, (size_t) 0); |
| 1266 | if (n > 0) | 1278 | if (n > 0) |
| 1267 | { | 1279 | { |
| 1268 | tmpdir = alloca (n); | 1280 | tmpdir = tmpdir_storage = xmalloc (n); |
| 1269 | confstr (_CS_DARWIN_USER_TEMP_DIR, tmpdir, n); | 1281 | confstr (_CS_DARWIN_USER_TEMP_DIR, tmpdir, n); |
| 1270 | } | 1282 | } |
| 1271 | else | 1283 | else |
| 1272 | #endif | 1284 | #endif |
| 1273 | tmpdir = "/tmp"; | 1285 | tmpdir = "/tmp"; |
| 1274 | } | 1286 | } |
| 1275 | socket_name = alloca (strlen (tmpdir) + strlen (server_name) | 1287 | tmpdirlen = strlen (tmpdir); |
| 1276 | + EXTRA_SPACE); | 1288 | socket_name = socket_name_storage = |
| 1277 | sprintf (socket_name, "%s/emacs%d/%s", | 1289 | xmalloc (tmpdirlen + strlen (server_name) + EXTRA_SPACE); |
| 1278 | tmpdir, (int) geteuid (), server_name); | 1290 | strcpy (socket_name, tmpdir); |
| 1291 | sprintf (socket_name + tmpdirlen, "/emacs%ld/", uid); | ||
| 1292 | strcat (socket_name + tmpdirlen, server_name); | ||
| 1279 | } | 1293 | } |
| 1280 | 1294 | ||
| 1281 | if (strlen (socket_name) < sizeof (server.sun_path)) | 1295 | if (strlen (socket_name) < sizeof (server.sun_path)) |
| @@ -1309,10 +1323,13 @@ set_local_socket (void) | |||
| 1309 | if (pw && (pw->pw_uid != geteuid ())) | 1323 | if (pw && (pw->pw_uid != geteuid ())) |
| 1310 | { | 1324 | { |
| 1311 | /* We're running under su, apparently. */ | 1325 | /* We're running under su, apparently. */ |
| 1312 | socket_name = alloca (strlen (tmpdir) + strlen (server_name) | 1326 | long uid = pw->pw_uid; |
| 1313 | + EXTRA_SPACE); | 1327 | ptrdiff_t tmpdirlen = strlen (tmpdir); |
| 1314 | sprintf (socket_name, "%s/emacs%d/%s", | 1328 | socket_name = xmalloc (tmpdirlen + strlen (server_name) |
| 1315 | tmpdir, (int) pw->pw_uid, server_name); | 1329 | + EXTRA_SPACE); |
| 1330 | strcpy (socket_name, tmpdir); | ||
| 1331 | sprintf (socket_name + tmpdirlen, "/emacs%ld/", uid); | ||
| 1332 | strcat (socket_name + tmpdirlen, server_name); | ||
| 1316 | 1333 | ||
| 1317 | if (strlen (socket_name) < sizeof (server.sun_path)) | 1334 | if (strlen (socket_name) < sizeof (server.sun_path)) |
| 1318 | strcpy (server.sun_path, socket_name); | 1335 | strcpy (server.sun_path, socket_name); |
| @@ -1322,6 +1339,7 @@ set_local_socket (void) | |||
| 1322 | progname, socket_name); | 1339 | progname, socket_name); |
| 1323 | exit (EXIT_FAILURE); | 1340 | exit (EXIT_FAILURE); |
| 1324 | } | 1341 | } |
| 1342 | free (socket_name); | ||
| 1325 | 1343 | ||
| 1326 | sock_status = socket_status (server.sun_path); | 1344 | sock_status = socket_status (server.sun_path); |
| 1327 | saved_errno = errno; | 1345 | saved_errno = errno; |
| @@ -1331,6 +1349,9 @@ set_local_socket (void) | |||
| 1331 | } | 1349 | } |
| 1332 | } | 1350 | } |
| 1333 | 1351 | ||
| 1352 | free (socket_name_storage); | ||
| 1353 | free (tmpdir_storage); | ||
| 1354 | |||
| 1334 | switch (sock_status) | 1355 | switch (sock_status) |
| 1335 | { | 1356 | { |
| 1336 | case 1: | 1357 | case 1: |
| @@ -1526,8 +1547,8 @@ start_daemon_and_retry_set_socket (void) | |||
| 1526 | { | 1547 | { |
| 1527 | /* Pass --daemon=socket_name as argument. */ | 1548 | /* Pass --daemon=socket_name as argument. */ |
| 1528 | const char *deq = "--daemon="; | 1549 | const char *deq = "--daemon="; |
| 1529 | char *daemon_arg = alloca (strlen (deq) | 1550 | char *daemon_arg = xmalloc (strlen (deq) |
| 1530 | + strlen (socket_name) + 1); | 1551 | + strlen (socket_name) + 1); |
| 1531 | strcpy (daemon_arg, deq); | 1552 | strcpy (daemon_arg, deq); |
| 1532 | strcat (daemon_arg, socket_name); | 1553 | strcat (daemon_arg, socket_name); |
| 1533 | d_argv[1] = daemon_arg; | 1554 | d_argv[1] = daemon_arg; |