diff options
Diffstat (limited to 'lib-src')
| -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; |